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  }