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