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

     1  package pin
     2  
     3  import (
     4  	"sync"
     5  	"unsafe"
     6  
     7  	"github.com/hsfzxjy/dgo/go/pin/pcop"
     8  )
     9  
    10  type rawToken struct {
    11  	version uint16
    12  	lid     uint8
    13  	_pad    [1]byte
    14  	meta    *Meta
    15  }
    16  
    17  type Token[T any] struct {
    18  	*rawToken
    19  	//lint:ingore U1000 unexportable marker
    20  	_ struct{}
    21  }
    22  
    23  var rawTokenPool = sync.Pool{
    24  	New: func() any { return new(rawToken) },
    25  }
    26  
    27  func newToken(meta *Meta, version uint16, lid uint8) untypedToken {
    28  	rt := rawTokenPool.Get().(*rawToken)
    29  	rt.version = version
    30  	rt.meta = meta
    31  	rt.lid = lid
    32  	return Token[struct{}]{rawToken: rt}
    33  }
    34  
    35  // t should be dropped after Dispose() invoked
    36  func (t *Token[T]) Dispose() (success bool) {
    37  	if t.IsEmpty() {
    38  		return false
    39  	}
    40  	t.meta.decref(t.version, t.lid)
    41  	untypedTokenLeak(untypedToken(*t))
    42  	return true
    43  }
    44  
    45  func (t Token[T]) Data() *T {
    46  	if t.IsEmpty() {
    47  		panic("dgo:go: Data() called on an empty Token")
    48  	}
    49  	return (*T)(unsafe.Pointer(t.meta))
    50  }
    51  
    52  func (t *Token[T]) IsEmpty() bool { return t.rawToken == nil || t.rawToken.meta == nil }
    53  
    54  type untypedToken = Token[struct{}]
    55  
    56  //lint:ignore U1000 go:linkname
    57  func untypedTokenFromRaw(version uint16, lid uint8, data uintptr) (ret untypedToken) {
    58  	meta, ok := pinTable.m.Load(data)
    59  	if !ok {
    60  		return
    61  	}
    62  
    63  LOAD_FLAG:
    64  	flag := meta.flag.Load()
    65  	switch flag {
    66  	case accessing:
    67  		goto LOAD_FLAG
    68  	case attached_not_intable, attached_intable:
    69  		runtime_procPin()
    70  		if !meta.flag.CompareAndSwap(flag, accessing) {
    71  			runtime_procUnpin()
    72  			goto LOAD_FLAG
    73  		}
    74  		if meta.version == version &&
    75  			meta.lids.Test(lid) {
    76  			ret = newToken(meta, version, lid)
    77  		}
    78  		// else: the version is mismatched or lid is invalid, we return an empty token
    79  		meta.flag.Store(flag)
    80  		runtime_procUnpin()
    81  		return
    82  	case detached:
    83  		return
    84  	}
    85  
    86  	return
    87  }
    88  
    89  //lint:ignore U1000 go:linkname
    90  func untypedTokenLeak(token untypedToken) {
    91  	token.version = 0
    92  	token.lid = 0
    93  	token.meta = nil
    94  	rawTokenPool.Put(token.rawToken)
    95  }
    96  
    97  //lint:ignore U1000 go:linkname
    98  func untypedTokenExtract(token untypedToken) (version uint16, lid uint8, data uintptr) {
    99  	version = token.version
   100  	lid = token.lid
   101  	data = uintptr(unsafe.Pointer(token.meta))
   102  	return version, lid, data
   103  }
   104  
   105  //go:linkname pin_TokenDispose github.com/hsfzxjy/dgo/go.pin_TokenDispose
   106  func pin_TokenDispose(version uint16, lid uint8, data uintptr) {
   107  	token := untypedTokenFromRaw(uint16(version), uint8(lid), uintptr(data))
   108  	token.Dispose()
   109  }
   110  
   111  //go:linkname pin_ChanListen github.com/hsfzxjy/dgo/go.pin_ChanListen
   112  func pin_ChanListen(version uint16, lid uint8, data uintptr, chid uint8, dcb uint32, port unsafe.Pointer) {
   113  	token := untypedTokenFromRaw(uint16(version), uint8(lid), uintptr(data))
   114  	if token.IsEmpty() {
   115  		return
   116  	}
   117  	token.meta.ops <- pcop.Op{Kind: pcop.CHAN_LISTEN, Lid: lid, Chid: chid, Dcb: dcb, Port: port}
   118  }
   119  
   120  //go:linkname pin_ChanCancelListen github.com/hsfzxjy/dgo/go.pin_ChanCancelListen
   121  func pin_ChanCancelListen(version uint16, lid uint8, data uintptr, chid uint8) {
   122  	token := untypedTokenFromRaw(uint16(version), uint8(lid), uintptr(data))
   123  	if token.IsEmpty() {
   124  		return
   125  	}
   126  	token.meta.ops <- pcop.Op{Kind: pcop.CHAN_CANCEL_LISTEN, Lid: lid, Chid: chid}
   127  }
   128  
   129  var _ = pin_ChanCancelListen