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 }