@@ -57,20 +57,13 @@ proc toStrTuple*(tag: TagPtr): string =
57
57
var res = (nptr:tag.nptr, idx:tag.idx)
58
58
return $res
59
59
60
- proc fetchAddSlot(tag: TagPtr; w: uint ): uint =
61
- ## A convenience to fetchAdd the node's slot.
62
- if tag == 0:
63
- raise AssertionDefect.newException "tagptr was empty"
64
- else:
65
- result = fetchAddSlot(tag.node, idx tag, w)
66
-
67
- proc fetchTail(queue: LoonyQueue, moorder: MemoryOrder = moRelaxed): TagPtr =
60
+ proc fetchTail(queue: LoonyQueue): TagPtr =
68
61
## get the TagPtr of the tail (nptr: NodePtr, idx: uint16 )
69
- TagPtr load(queue.tail, order = moorder )
62
+ TagPtr load(queue.tail, order = moRelaxed )
70
63
71
- proc fetchHead(queue: LoonyQueue, moorder: MemoryOrder = moRelaxed ): TagPtr =
64
+ proc fetchHead(queue: LoonyQueue): TagPtr =
72
65
## get the TagPtr of the head (nptr: NodePtr, idx: uint16 )
73
- TagPtr load(queue.head, order = moorder )
66
+ TagPtr load(queue.head, order = moRelaxed )
74
67
75
68
proc fetchCurrTail(queue: LoonyQueue): NodePtr {.used.} =
76
69
# get the NodePtr of the current tail
@@ -80,20 +73,20 @@ proc fetchCurrTail(queue: LoonyQueue): NodePtr {.used.} =
80
73
# imported std/atomics or we export atomics.
81
74
# For the sake of not polluting the users namespace I have changed these into procs.
82
75
# Atomic inc of idx in (nptr: NodePtr, idx: uint16 )
83
- proc fetchIncTail(queue: LoonyQueue, moorder: MemoryOrder = moAcquire ): TagPtr =
84
- cast[TagPtr](queue.tail.fetchAdd(1, order = moorder ))
85
- proc fetchIncHead(queue: LoonyQueue, moorder: MemoryOrder = moAcquire ): TagPtr =
86
- cast[TagPtr](queue.head.fetchAdd(1, order = moorder ))
76
+ proc fetchIncTail(queue: LoonyQueue): TagPtr =
77
+ cast[TagPtr](queue.tail.fetchAdd(1, order = moAcquire ))
78
+ proc fetchIncHead(queue: LoonyQueue): TagPtr =
79
+ cast[TagPtr](queue.head.fetchAdd(1, order = moAcquire ))
87
80
88
- proc compareAndSwapTail(queue: LoonyQueue, expect: var uint , swap: uint | TagPtr): bool =
89
- queue.tail.compareExchange(expect, swap)
81
+ proc compareAndSwapTail(queue: LoonyQueue; expect: var uint ; swap: uint | TagPtr): bool =
82
+ queue.tail.compareExchange(expect, swap, moRelease, moRelaxed )
90
83
91
- proc compareAndSwapHead(queue: LoonyQueue, expect: var uint , swap: uint | TagPtr): bool =
92
- queue.head.compareExchange(expect, swap)
84
+ proc compareAndSwapHead(queue: LoonyQueue; expect: var uint ; swap: uint | TagPtr): bool =
85
+ queue.head.compareExchange(expect, swap, moRelease, moRelaxed )
93
86
94
- proc compareAndSwapCurrTail(queue: LoonyQueue, expect: var uint ,
87
+ proc compareAndSwapCurrTail(queue: LoonyQueue; expect: var uint ;
95
88
swap: uint | TagPtr): bool {.used.} =
96
- queue.currTail.compareExchange(expect, swap)
89
+ queue.currTail.compareExchange(expect, swap, moRelease, moRelaxed )
97
90
98
91
proc `=destroy`*[T](x: var LoonyQueueImpl[T]) =
99
92
## Destroy is completely operated on the basis that no other threads are
@@ -191,7 +184,7 @@ proc advTail[T](queue: LoonyQueue[T]; pel: uint; tag: TagPtr): AdvTail =
191
184
result = AdvOnly
192
185
break done
193
186
# Get current tails next node
194
- var next = origTail. fetchNext()
187
+ var next = fetchNext(origTail, moRelaxed )
195
188
if cast[ptr Node](next).isNil():
196
189
# Prepare the new node with our element in it
197
190
var node = allocNode pel
@@ -242,7 +235,7 @@ proc advHead(queue: LoonyQueue; curr, h, t: var TagPtr): AdvHead =
242
235
incrDeqCount h.node
243
236
QueueEmpty
244
237
else:
245
- var next = fetchNext h.nptr
238
+ var next = fetchNext( h.nptr, moAcquire)
246
239
# Equivalent to (nptr: NodePtr, idx: idx+=1)
247
240
curr += 1
248
241
block done:
@@ -297,12 +290,12 @@ proc pushImpl[T](queue: LoonyQueue[T], el: sink T,
297
290
atomicThreadFence(ATOMIC_RELEASE)
298
291
while true:
299
292
# Enq proc begins with incr the index of node in TagPtr
300
- var tag = fetchIncTail(queue )
293
+ var tag = queue. fetchIncTail()
301
294
if likely(tag.idx < N):
302
295
# FAST PATH OPERATION - 99% of push will enter here; we want the minimal
303
296
# amount of necessary operations in this path.
304
297
# Perform a FAA on our reserved slot which should be 0'd.
305
- let prev = tag.fetchAddSlot pel
298
+ let prev = fetchAddSlot( tag.node, tag.idx, pel, moAcquire)
306
299
case prev
307
300
of 0, RESUME:
308
301
break # the slot was empty; we're good to go
@@ -353,17 +346,17 @@ proc isEmptyImpl(head, tail: TagPtr): bool =
353
346
proc isEmpty*(queue: LoonyQueue): bool =
354
347
## This operation should only be used by internal code. The response for this
355
348
## operation is not precise.
356
- let head = fetchHead queue
357
- let tail = fetchTail queue
349
+ let head = queue.fetchHead()
350
+ let tail = queue.fetchTail()
358
351
isEmptyImpl(head, tail)
359
352
360
353
proc popImpl[T](queue: LoonyQueue[T]; forcedCoherence: static bool = false): T =
361
354
assert not queue.isNil(), "The queue has not been initialised"
362
355
while true:
363
356
# Before incr the deq index, init check performed to determine if queue is empty.
364
357
# Ensure head is loaded last to keep mem hot
365
- var tail = fetchTail queue
366
- var curr = fetchHead queue
358
+ var tail = queue.fetchTail()
359
+ var curr = queue.fetchHead()
367
360
if isEmptyImpl(curr, tail):
368
361
# Queue was empty; nil can be caught in cps w/ "while cont.running"
369
362
when T is ref or T is ptr :
@@ -374,7 +367,7 @@ proc popImpl[T](queue: LoonyQueue[T]; forcedCoherence: static bool = false): T =
374
367
var head = queue.fetchIncHead()
375
368
if likely(head.idx < N):
376
369
# FAST PATH OPS
377
- var prev = head.fetchAddSlot READER
370
+ var prev = fetchAddSlot( head.node, head.idx, READER, moRelease)
378
371
# Last slot in a node - init reclaim proc; if WRITER bit set then upper bits
379
372
# contain a valid pointer to an enqd el that can be returned (see enqueue)
380
373
if not unlikely((prev and SLOTMASK) == 0):
0 commit comments