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 }