gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/ipc/cgo/sem/queue/queue32.go (about)

     1  package queue
     2  
     3  import (
     4  	semPkg "gitee.com/sy_183/go-common/ipc/cgo/sem"
     5  	"sync/atomic"
     6  )
     7  
     8  type Queue32 struct {
     9  	cap  uint32
    10  	head uint32
    11  	tail uint32
    12  }
    13  
    14  func (q *Queue32) Init(cap uint32) {
    15  	if (cap & (cap - 1)) != 0 {
    16  		panic(ErrInvalidCap)
    17  	}
    18  	q.cap = cap
    19  	q.head = 0
    20  	q.tail = 0
    21  }
    22  
    23  func (q *Queue32) Len() uint32 {
    24  	return atomic.LoadUint32(&q.tail) - atomic.LoadUint32(&q.head)
    25  }
    26  
    27  func (q *Queue32) Cap() uint32 {
    28  	return q.cap
    29  }
    30  
    31  func wait(sem *semPkg.Sem) error {
    32  	if sem != nil {
    33  		return sem.Wait()
    34  	}
    35  	return nil
    36  }
    37  
    38  func post(sem *semPkg.Sem) error {
    39  	if sem != nil {
    40  		v, err := sem.GetValue()
    41  		if err != nil {
    42  			return err
    43  		}
    44  		if v == 0 {
    45  			return sem.Post()
    46  		}
    47  	}
    48  	return nil
    49  }
    50  
    51  type Queue32View struct {
    52  	queue *Queue32
    53  	start uint32
    54  	end   uint32
    55  }
    56  
    57  func (v Queue32View) Len() uint32 {
    58  	return v.end - v.start
    59  }
    60  
    61  func (v Queue32View) Slice(raw []byte) (prefix []byte, suffix []byte) {
    62  	if len(raw) != int(v.queue.cap) {
    63  		return nil, nil
    64  	}
    65  	mask := v.queue.cap - 1
    66  	start, end := v.start&mask, v.end&mask
    67  	if end >= start {
    68  		return raw[start:end], nil
    69  	} else {
    70  		return raw[end:], raw[:start]
    71  	}
    72  }
    73  
    74  const (
    75  	PostModeCanAlloc = iota
    76  	PostModeCanUse   = iota
    77  )
    78  
    79  func (v *Queue32View) Post(mode int, sem *semPkg.Sem) error {
    80  	switch mode {
    81  	case PostModeCanAlloc:
    82  		atomic.StoreUint32(&v.queue.head, v.end)
    83  		//if !atomic.CompareAndSwapUint32(&v.queue.head, v.start, v.end) {
    84  		//	panic(ErrConcurrentUse)
    85  		//}
    86  		return post(sem)
    87  	case PostModeCanUse:
    88  		atomic.StoreUint32(&v.queue.tail, v.end)
    89  		//if !atomic.CompareAndSwapUint32(&v.queue.tail, v.start, v.end) {
    90  		//	panic(ErrConcurrentAlloc)
    91  		//}
    92  		return post(sem)
    93  	}
    94  	return nil
    95  }
    96  
    97  func (q *Queue32) view(start, end uint32) Queue32View {
    98  	return Queue32View{
    99  		queue: q,
   100  		start: start,
   101  		end:   end,
   102  	}
   103  }
   104  
   105  func (q *Queue32) can(start, end, p uint32) bool {
   106  	if end >= start {
   107  		// |✕✕✕✕✕✕✕✕|✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓|✕✕✕✕✕✕✕✕✕✕✕|
   108  		//          ↑                ↑
   109  		// 0      start             end         2^32
   110  		return p > start && p <= end
   111  	} else {
   112  		//
   113  		// |✓✓✓✓✓✓✓✓|✕✕✕✕✕✕✕✕✕✕✕✕✕✕✕✕|✓✓✓✓✓✓✓✓✓✓✓|
   114  		//          ↑                ↑
   115  		// 0       end             start        2^32
   116  		return p > start || p <= end
   117  	}
   118  }
   119  
   120  func (q *Queue32) want(start, end, p uint32) Queue32View {
   121  	if end >= start {
   122  		// |✕✕✕✕✕✕✕✕|✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓✓|✕✕✕✕✕✕✕✕✕✕✕|
   123  		//          ↑                ↑
   124  		// 0      start             end         2^32
   125  		if p < start || p > end {
   126  			return q.view(start, end)
   127  		}
   128  	} else {
   129  		//
   130  		// |✓✓✓✓✓✓✓✓|✕✕✕✕✕✕✕✕✕✕✕✕✕✕✕✕|✓✓✓✓✓✓✓✓✓✓✓|
   131  		//          ↑                ↑
   132  		// 0       end             start        2^32
   133  		if p < start && p > end {
   134  			return q.view(start, end)
   135  		}
   136  	}
   137  	return q.view(start, p)
   138  }
   139  
   140  func (q *Queue32) TryAlloc(size uint32) (view Queue32View, ok bool) {
   141  	if size == 0 || size > q.cap {
   142  		return
   143  	}
   144  	tail := atomic.LoadUint32(&q.tail)
   145  	if p := tail + size; q.can(tail, atomic.LoadUint32(&q.head)+q.cap, p) {
   146  		return q.view(tail, p), true
   147  	} else {
   148  		return
   149  	}
   150  }
   151  
   152  func (q *Queue32) WantTryAlloc(size uint32) (view Queue32View, ok bool) {
   153  	if size == 0 {
   154  		return
   155  	}
   156  	if size > q.cap {
   157  		size = q.cap
   158  	}
   159  	tail, max := atomic.LoadUint32(&q.tail), atomic.LoadUint32(&q.head)+q.cap
   160  	if tail == max {
   161  		return
   162  	}
   163  	return q.want(tail, max, tail+size), true
   164  }
   165  
   166  func (q *Queue32) Alloc(size uint32, sem *semPkg.Sem) (view Queue32View, err error) {
   167  	if size == 0 || size > q.cap {
   168  		return
   169  	}
   170  	tail := atomic.LoadUint32(&q.tail)
   171  	p := tail + size
   172  	for !q.can(tail, atomic.LoadUint32(&q.head)+q.cap, p) {
   173  		if err = wait(sem); err != nil {
   174  			return
   175  		}
   176  	}
   177  	return q.view(tail, p), nil
   178  }
   179  
   180  func (q *Queue32) WantAlloc(size uint32, sem *semPkg.Sem) (view Queue32View, err error) {
   181  	if size == 0 {
   182  		return
   183  	}
   184  	if size > q.cap {
   185  		size = q.cap
   186  	}
   187  	tail, max := atomic.LoadUint32(&q.tail), atomic.LoadUint32(&q.head)+q.cap
   188  	for tail == max {
   189  		if err = wait(sem); err != nil {
   190  			return
   191  		}
   192  		max = atomic.LoadUint32(&q.head) + q.cap
   193  	}
   194  	return q.want(tail, max, tail+size), nil
   195  }
   196  
   197  func (q *Queue32) TryUse(size uint32) (view Queue32View, ok bool) {
   198  	if size == 0 || size > q.cap {
   199  		return
   200  	}
   201  	head := atomic.LoadUint32(&q.head)
   202  	if p := head + size; q.can(head, atomic.LoadUint32(&q.tail), p) {
   203  		return q.view(head, p), true
   204  	} else {
   205  		return
   206  	}
   207  }
   208  
   209  func (q *Queue32) WantTryUse(size uint32) (view Queue32View, ok bool) {
   210  	if size == 0 {
   211  		return
   212  	}
   213  	if size > q.cap {
   214  		size = q.cap
   215  	}
   216  	head, tail := atomic.LoadUint32(&q.head), atomic.LoadUint32(&q.tail)
   217  	if head == tail {
   218  		return
   219  	}
   220  	return q.want(head, tail, head+size), true
   221  }
   222  
   223  func (q *Queue32) Use(size uint32, sem *semPkg.Sem) (view Queue32View, err error) {
   224  	if size == 0 || size > q.cap {
   225  		return
   226  	}
   227  	head := atomic.LoadUint32(&q.head)
   228  	p := head + size
   229  	for !q.can(head, atomic.LoadUint32(&q.tail), p) {
   230  		if err = wait(sem); err != nil {
   231  			return
   232  		}
   233  	}
   234  	return q.view(head, p), nil
   235  }
   236  
   237  func (q *Queue32) WantUse(size uint32, sem *semPkg.Sem) (view Queue32View, err error) {
   238  	if size == 0 {
   239  		return
   240  	}
   241  	if size > q.cap {
   242  		size = q.cap
   243  	}
   244  	head, tail := atomic.LoadUint32(&q.head), atomic.LoadUint32(&q.tail)
   245  	for head == tail {
   246  		if err = wait(sem); err != nil {
   247  			return
   248  		}
   249  		tail = atomic.LoadUint32(&q.tail)
   250  	}
   251  	return q.want(head, tail, head+size), nil
   252  }