github.com/hsfzxjy/dgo/go@v0.2.0/pin/meta.go (about)

     1  package pin
     2  
     3  import (
     4  	"sync/atomic"
     5  	"unsafe"
     6  
     7  	"github.com/hsfzxjy/dgo/go/pin/bitset"
     8  	"github.com/hsfzxjy/dgo/go/pin/pcop"
     9  )
    10  
    11  const (
    12  	detached uint32 = iota
    13  	accessing
    14  	attached_not_intable
    15  
    16  	intable uint32 = 0x1000_0000
    17  
    18  	attached_intable = intable | attached_not_intable
    19  )
    20  
    21  type Meta struct {
    22  	_       noCopy
    23  	flag    atomic.Uint32
    24  	version uint16
    25  	nchans  uint8
    26  	_pad    [1]byte
    27  	lids    bitset.Bitset64
    28  	ops     chan pcop.Op
    29  }
    30  
    31  //lint:ignore U1000 go:linkname
    32  func metaPin(m *Meta, nchans uint8, workerfn func(chan pcop.Op)) (success bool) {
    33  LOAD_FLAG:
    34  	flag := m.flag.Load()
    35  	switch flag {
    36  	case accessing:
    37  		goto LOAD_FLAG
    38  	case detached:
    39  		var ops chan pcop.Op
    40  		runtime_procPin()
    41  		if !m.flag.CompareAndSwap(flag, accessing) {
    42  			runtime_procUnpin()
    43  			goto LOAD_FLAG
    44  		}
    45  		m.version = uint16(pinTable.nextVersion.Add(1))
    46  		m.lids = 0
    47  		m.nchans = nchans
    48  		if nchans > 0 {
    49  			ops = pcop.NewOpChan()
    50  			m.ops = ops
    51  		}
    52  		pinTable.m.Store(uintptr(m.key()), m)
    53  		m.flag.Store(attached_intable)
    54  		runtime_procUnpin()
    55  
    56  		if nchans > 0 {
    57  			go workerfn(ops)
    58  		}
    59  
    60  		return true
    61  	case attached_not_intable:
    62  		if !m.flag.CompareAndSwap(flag, attached_intable) {
    63  			goto LOAD_FLAG
    64  		}
    65  	}
    66  	return false
    67  }
    68  
    69  func (m *Meta) Unpin() (success bool) {
    70  	var ops chan pcop.Op
    71  LOAD_FLAG:
    72  	flag := m.flag.Load()
    73  	switch flag {
    74  	case accessing:
    75  		goto LOAD_FLAG
    76  	case detached:
    77  	case attached_not_intable, attached_intable:
    78  		runtime_procPin()
    79  		if !m.flag.CompareAndSwap(flag, accessing) {
    80  			runtime_procUnpin()
    81  			goto LOAD_FLAG
    82  		}
    83  		if m.lids.IsEmpty() {
    84  			m.lids = 0
    85  			pinTable.m.Delete(m.key())
    86  			if m.nchans > 0 {
    87  				ops = m.ops
    88  				m.ops = nil
    89  			}
    90  			m.flag.Store(detached)
    91  		} else {
    92  			m.flag.Store(attached_not_intable)
    93  		}
    94  		runtime_procUnpin()
    95  
    96  		if ops != nil {
    97  			ops <- pcop.Op{Kind: pcop.META_DETACHED}
    98  		}
    99  
   100  		return true
   101  	}
   102  	return false
   103  }
   104  
   105  func (m *Meta) key() uintptr { return uintptr(unsafe.Pointer(m)) }
   106  
   107  func (m *Meta) decref(version uint16, lid uint8) {
   108  	var ops chan pcop.Op
   109  LOAD_FLAG:
   110  	flag := m.flag.Load()
   111  	switch flag {
   112  	case accessing:
   113  		goto LOAD_FLAG
   114  	case detached:
   115  		return
   116  	case attached_not_intable, attached_intable:
   117  		runtime_procPin()
   118  		if !m.flag.CompareAndSwap(flag, accessing) {
   119  			runtime_procUnpin()
   120  			goto LOAD_FLAG
   121  		}
   122  		if m.version != version ||
   123  			!m.lids.Test(lid) {
   124  			m.flag.Store(flag)
   125  			runtime_procUnpin()
   126  			return
   127  		}
   128  		m.lids.Clear(lid)
   129  		if m.lids.IsEmpty() && flag&intable == 0 {
   130  			m.lids = 0
   131  			pinTable.m.Delete(uintptr(m.key()))
   132  			if m.nchans > 0 {
   133  				ops = m.ops
   134  				m.ops = nil
   135  			}
   136  			m.flag.Store(detached)
   137  		} else {
   138  			m.flag.Store(flag)
   139  		}
   140  		runtime_procUnpin()
   141  	}
   142  	if ops != nil {
   143  		ops <- pcop.Op{Kind: pcop.META_DETACHED}
   144  	}
   145  }
   146  
   147  //lint:ignore U1000 go:linkname
   148  func metaNewToken(m *Meta) untypedToken {
   149  	var lid uint8
   150  	var version uint16
   151  LOAD_FLAG:
   152  	flag := m.flag.Load()
   153  	switch flag {
   154  	case accessing:
   155  		goto LOAD_FLAG
   156  	case detached:
   157  		panic("dgo:go: cannot call NewToken() on an unpinned object")
   158  	case attached_intable, attached_not_intable:
   159  		runtime_procPin()
   160  		if !m.flag.CompareAndSwap(flag, accessing) {
   161  			runtime_procUnpin()
   162  			goto LOAD_FLAG
   163  		}
   164  		var ok bool
   165  		lid, ok = m.lids.PickSet()
   166  		if !ok {
   167  			m.flag.Store(flag)
   168  			runtime_procUnpin()
   169  			panic("dgo:go: too many allocated lids")
   170  		}
   171  		version = m.version
   172  		m.flag.Store(flag)
   173  		runtime_procUnpin()
   174  	}
   175  	return newToken(m, version, lid)
   176  }