@@ -102,7 +102,9 @@ proc trySend*[T](chan: var ChannelMpscUnboundedBatch[T], src: sink T): bool {.in
102
102
# # Send an item to the back of the channel
103
103
# # As the channel has unbounded capacity, this should never fail
104
104
105
- discard chan.count.fetchAdd (1 , moRelaxed)
105
+ let oldCount {.used .} = chan.count.fetchAdd (1 , moRelease)
106
+ postCondition: oldCount >= 0
107
+
106
108
src.next.store (nil , moRelease)
107
109
let oldBack = chan.back.exchange (src, moAcquireRelease)
108
110
# Consumer can be blocked here, it doesn't see the (potentially growing) end of the queue
@@ -116,7 +118,9 @@ proc trySendBatch*[T](chan: var ChannelMpscUnboundedBatch[T], first, last: sink
116
118
# # They should be linked together by their next field
117
119
# # As the channel has unbounded capacity this should never fail
118
120
119
- discard chan.count.fetchAdd (int (count), moRelaxed)
121
+ let oldCount {.used .} = chan.count.fetchAdd (1 , moRelease)
122
+ postCondition: oldCount >= 0
123
+
120
124
last.next.store (nil , moRelease)
121
125
let oldBack = chan.back.exchange (last, moAcquireRelease)
122
126
# Consumer can be blocked here, it doesn't see the (potentially growing) end of the queue
@@ -144,10 +148,13 @@ proc tryRecv*[T](chan: var ChannelMpscUnboundedBatch[T], dst: var T): bool =
144
148
if not next.isNil:
145
149
# Not competing with producers
146
150
prefetch (first)
147
- discard chan.count. fetchSub ( 1 , moRelaxed)
151
+
148
152
chan.front.next.store (next, moRelaxed)
149
153
# fence(moAcquire) # Sync "first.next.load(moRelaxed)"
150
154
dst = first
155
+
156
+ let oldCount {.used .} = chan.count.fetchSub (1 , moRelaxed)
157
+ ascertain: oldCount >= 1 # The producers may overestimate the count
151
158
return true
152
159
# End fast-path
153
160
@@ -162,8 +169,10 @@ proc tryRecv*[T](chan: var ChannelMpscUnboundedBatch[T], dst: var T): bool =
162
169
if compareExchange (chan.back, last, chan.front.addr , moAcquireRelease):
163
170
# We won and replaced the last node with the channel front
164
171
prefetch (first)
165
- discard chan.count.fetchSub (1 , moRelaxed)
166
172
dst = first
173
+
174
+ let oldCount {.used .} = chan.count.fetchSub (1 , moRelaxed)
175
+ ascertain: oldCount >= 1 # The producers may overestimate the count
167
176
return true
168
177
169
178
# We lost but now we know that there is an extra node coming very soon
@@ -179,10 +188,12 @@ proc tryRecv*[T](chan: var ChannelMpscUnboundedBatch[T], dst: var T): bool =
179
188
next = first.next.load (moAcquire)
180
189
181
190
prefetch (first)
182
- discard chan.count.fetchSub (1 , moRelaxed)
183
191
chan.front.next.store (next, moRelaxed)
184
192
# fence(moAcquire) # sync first.next.load(moRelaxed)
185
193
dst = first
194
+
195
+ let oldCount {.used .} = chan.count.fetchSub (1 , moRelaxed)
196
+ ascertain: oldCount >= 1 # The producers may overestimate the count
186
197
return true
187
198
188
199
# # Alternative implementation
@@ -235,8 +246,9 @@ proc tryRecvBatch*[T](chan: var ChannelMpscUnboundedBatch[T], bFirst, bLast: var
235
246
if front != last:
236
247
# We lose the competition, bail out
237
248
chan.front.next.store (front, moRelease)
238
- discard chan.count.fetchSub (result , moRelaxed)
239
- postCondition: chan.count.load (moRelaxed) >= 0 # TODO : somehow it can be negative
249
+
250
+ let oldCount {.used .} = chan.count.fetchSub (result , moRelaxed)
251
+ postCondition: oldCount >= result # TODO : somehow it can be negative
240
252
return
241
253
242
254
# front == last
@@ -245,9 +257,10 @@ proc tryRecvBatch*[T](chan: var ChannelMpscUnboundedBatch[T], bFirst, bLast: var
245
257
# We won and replaced the last node with the channel front
246
258
prefetch (front)
247
259
result += 1
248
- discard chan.count.fetchSub (result , moRelaxed)
249
260
bLast = front
250
- postCondition: chan.count.load (moRelaxed) >= 0
261
+
262
+ let oldCount {.used .} = chan.count.fetchSub (result , moRelaxed)
263
+ postCondition: oldCount >= result # TODO : somehow it can be negative
251
264
return
252
265
253
266
# We lost but now we know that there is an extra node
@@ -267,11 +280,12 @@ proc tryRecvBatch*[T](chan: var ChannelMpscUnboundedBatch[T], bFirst, bLast: var
267
280
268
281
prefetch (front)
269
282
result += 1
270
- discard chan.count.fetchSub (result , moRelaxed)
271
283
chan.front.next.store (next, moRelaxed)
272
284
# fence(moAcquire) # sync front.next.load(moRelaxed)
273
285
bLast = front
274
- postCondition: chan.count.load (moRelaxed) >= 0
286
+
287
+ let oldCount {.used .} = chan.count.fetchSub (result , moRelaxed)
288
+ postCondition: oldCount >= result # TODO : somehow it can be negative
275
289
276
290
func peek * (chan: var ChannelMpscUnboundedBatch ): int32 {.inline .} =
277
291
# # Estimates the number of items pending in the channel
0 commit comments