github.com/hsfzxjy/dgo/go@v0.2.0/pin/pchan/manager.go (about) 1 package pchan 2 3 import ( 4 "math/bits" 5 6 dgo "github.com/hsfzxjy/dgo/go" 7 "github.com/hsfzxjy/dgo/go/pin/bitset" 8 "github.com/hsfzxjy/dgo/go/pin/pcop" 9 ) 10 11 type Manager struct { 12 backing imanager 13 finished bitset.Bitset64 14 heads []*listener 15 lidsets []bitset.Bitset64 16 } 17 18 func NewManager(n uint8) Manager { 19 if n > 64 { 20 panic("expect n <= 64") 21 } 22 i := 8 - bits.LeadingZeros8(n-1) 23 return managerPools[i].Get().(imanager).as_chanman(n) 24 } 25 26 func (m *Manager) Recycle() { 27 m.backing.recycle() 28 m.backing = nil 29 } 30 31 func (m *Manager) do_chan_listen(op pcop.Op) bool { 32 Chid := op.Chid 33 if m.finished.Test(op.Chid) { 34 return false 35 } 36 m.lidsets[Chid].Set(op.Lid) 37 head := &m.heads[Chid] 38 listener := listenerNew() 39 listener.chid = op.Chid 40 listener.lid = op.Lid 41 listener.dcb = op.Dcb 42 listener.port = (*dgo.Port)(op.Port) 43 listener.next = *head 44 *head = listener 45 return true 46 } 47 48 func (m *Manager) do_chan_cancel_listen(op pcop.Op) { 49 m.lidsets[op.Chid].Clear(op.Lid) 50 } 51 52 func (m *Manager) do_token_dispose(op pcop.Op) { 53 Lid := op.Lid 54 //todo: vectorize 55 for i := range m.lidsets { 56 m.lidsets[i].Clear(Lid) 57 } 58 } 59 60 // For op == CHAN_LISTEN, result == true if the listener was successfully registered; 61 // for op == META_DETACHED, result is always true; 62 // for other values of op, result is meaningless. 63 func (m *Manager) Handle(op pcop.Op) (result bool) { 64 switch op.Kind { 65 case pcop.CHAN_LISTEN: 66 return m.do_chan_listen(op) 67 case pcop.CHAN_CANCEL_LISTEN: 68 m.do_chan_cancel_listen(op) 69 case pcop.TOKEN_DISPOSE: 70 m.do_token_dispose(op) 71 case pcop.META_DETACHED: 72 return true 73 } 74 return false 75 } 76 77 func (m *Manager) GetLids(finished bool, chid uint8, result *[]dgo.CallableDartCallback) (samePort bool) { 78 var visited bitset.Bitset64 79 head := m.heads[chid] 80 var q *listener 81 p := head 82 lids := &m.lidsets[chid] 83 84 var port *dgo.Port 85 if p != nil { 86 port = p.port 87 } 88 89 var flag = dgo.CF.Fallible().PackArray().WithContext() 90 if finished { 91 flag = flag.Pop() 92 } 93 94 samePort = true 95 for p != nil { 96 lid := p.lid 97 if visited.Test(lid) { 98 goto REMOVE 99 } 100 visited.Set(lid) 101 if !lids.Test(lid) { 102 goto REMOVE 103 } 104 *result = append(*result, dgo.WrapDartCallback(p.dcb, p.port).Flag(flag)) 105 if p.port != port { 106 samePort = false 107 } 108 q = p 109 p = p.next 110 continue 111 REMOVE: 112 switch { 113 case q == nil: 114 // p is head 115 head = p.next 116 p.recycle() 117 p = head 118 default: 119 // p is not head 120 q.next = p.next 121 p.recycle() 122 p = q.next 123 } 124 } 125 126 if finished { 127 head.free() 128 m.heads[chid] = nil 129 m.finished.Set(chid) 130 } else { 131 m.heads[chid] = head 132 } 133 134 return 135 }