github.com/aaabigfish/gopkg@v1.1.0/internal/benchmark/msq/msq.go (about) 1 // Copyright 2021 ByteDance Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package msq 16 17 import ( 18 "sync" 19 "sync/atomic" 20 "unsafe" 21 ) 22 23 var msqv1pool *sync.Pool = &sync.Pool{New: func() interface{} { return new(msqv1node) }} 24 25 type MSQueue struct { 26 head unsafe.Pointer // *msqv1node 27 tail unsafe.Pointer // *msqv1node 28 } 29 30 type msqv1node struct { 31 value uint64 32 next unsafe.Pointer // *msqv1node 33 } 34 35 func New() *MSQueue { 36 node := unsafe.Pointer(new(msqv1node)) 37 return &MSQueue{head: node, tail: node} 38 } 39 40 func loadMSQPointer(p *unsafe.Pointer) *msqv1node { 41 return (*msqv1node)(atomic.LoadPointer(p)) 42 } 43 44 func (q *MSQueue) Enqueue(value uint64) bool { 45 node := &msqv1node{value: value} 46 for { 47 tail := atomic.LoadPointer(&q.tail) 48 tailstruct := (*msqv1node)(tail) 49 next := atomic.LoadPointer(&tailstruct.next) 50 if tail == atomic.LoadPointer(&q.tail) { 51 if next == nil { 52 // tail.next is empty, inset new node 53 if atomic.CompareAndSwapPointer(&tailstruct.next, next, unsafe.Pointer(node)) { 54 atomic.CompareAndSwapPointer(&q.tail, tail, unsafe.Pointer(node)) 55 break 56 } 57 } else { 58 atomic.CompareAndSwapPointer(&q.tail, tail, next) 59 } 60 } 61 } 62 return true 63 } 64 65 func (q *MSQueue) Dequeue() (value uint64, ok bool) { 66 for { 67 head := atomic.LoadPointer(&q.head) 68 tail := atomic.LoadPointer(&q.tail) 69 headstruct := (*msqv1node)(head) 70 next := atomic.LoadPointer(&headstruct.next) 71 if head == atomic.LoadPointer(&q.head) { 72 if head == tail { 73 if next == nil { 74 return 0, false 75 } 76 atomic.CompareAndSwapPointer(&q.tail, tail, next) 77 } else { 78 value = ((*msqv1node)(next)).value 79 if atomic.CompareAndSwapPointer(&q.head, head, next) { 80 return value, true 81 } 82 } 83 } 84 } 85 }