@@ -105,6 +105,7 @@ class RendezvousChannelKoval<E>(
105
105
// Main function in this chanel, which implements both `#send` and `#receive` operations.
106
106
// Note that `#offer` and `#poll` functions are just simplified versions of this one.
107
107
private suspend fun <T > sendOrReceiveSuspend (element : Any ) = suspendAtomicCancellableCoroutine<T >(holdCancellability = true ) sc@ { curCont ->
108
+ var localCounterUpdate = 0
108
109
try_again@ while (true ) { // CAS loop
109
110
// Read the tail and its enqueue index at first, then the head and its indexes.
110
111
// It is important to read tail and its index at first. If algorithm
@@ -128,14 +129,16 @@ class RendezvousChannelKoval<E>(
128
129
}
129
130
// Queue is empty, try to add a new node with the current continuation.
130
131
if (addNewNode(head, curCont, element)) {
132
+ if (localCounterUpdate > 0 ) { incElimSenderArraySize(1 ); incElimReceiverArraySize(1 ) }
131
133
return @sc
132
- } else { incElimReceiverArraySize( 1 ); incElimSenderArraySize( 1 ) }
134
+ } else { localCounterUpdate ++ }
133
135
} else {
134
136
// The `head` node is not full, therefore the waiting queue
135
137
// is empty. Try to add the current continuation to the queue.
136
138
if (storeContinuation(head, headEnqIdx, curCont, element)) {
139
+ if (localCounterUpdate > 0 ) { incElimSenderArraySize(1 ); incElimReceiverArraySize(1 ) }
137
140
return @sc
138
- } else { incElimReceiverArraySize( 1 ); incElimSenderArraySize( 1 ) }
141
+ } else { localCounterUpdate ++ }
139
142
}
140
143
} else {
141
144
// The waiting queue is not empty and it is guaranteed that `headDeqIdx < headEnqIdx`.
@@ -153,7 +156,7 @@ class RendezvousChannelKoval<E>(
153
156
var firstElement = readElement(head, headDeqIdx)
154
157
if (firstElement == TAKEN_ELEMENT ) {
155
158
// Try to move the deque index in the `head` node
156
- incElimReceiverArraySize( 1 ); incElimSenderArraySize( 1 )
159
+ localCounterUpdate ++
157
160
deqIdxUpdater.compareAndSet(head, headDeqIdx, headDeqIdx + 1 )
158
161
continue @try_again
159
162
}
@@ -176,6 +179,7 @@ class RendezvousChannelKoval<E>(
176
179
// Resume the current continuation
177
180
val result = (if (element == RECEIVER_ELEMENT ) firstElement else Unit ) as T
178
181
curCont.resume(result)
182
+ if (localCounterUpdate > 0 ) { incElimSenderArraySize(1 ); incElimReceiverArraySize(1 ) }
179
183
return @sc
180
184
}
181
185
// Re-read the required pointers
@@ -190,7 +194,7 @@ class RendezvousChannelKoval<E>(
190
194
// Check that `(head.id, headDeqIdx) < (headIdLimit, headDeqIdxLimit)`
191
195
// and re-start the whole operation if needed
192
196
if (head.id > headIdLimit || (head.id == headIdLimit && headDeqIdx >= headDeqIdxLimit)) {
193
- incElimReceiverArraySize( 1 ); incElimSenderArraySize( 1 )
197
+ localCounterUpdate ++
194
198
continue @try_again
195
199
}
196
200
// Re-read the first element
@@ -208,12 +212,12 @@ class RendezvousChannelKoval<E>(
208
212
// if the tail is full, otherwise try to store it at the `tailEnqIdx` index.
209
213
if (tailEnqIdx == segmentSize) {
210
214
if (addNewNode(tail, curCont, element)) {
211
- decOppositeElimArraySize(element, 1 )
215
+ if (localCounterUpdate > 0 ) { incElimSenderArraySize( 1 ); incElimReceiverArraySize( 1 ) }
212
216
return @sc
213
217
}
214
218
} else {
215
219
if (storeContinuation(tail, tailEnqIdx, curCont, element)) {
216
- decOppositeElimArraySize(element, 1 )
220
+ if (localCounterUpdate > 0 ) { incElimSenderArraySize( 1 ); incElimReceiverArraySize( 1 ) }
217
221
return @sc
218
222
}
219
223
}
@@ -224,7 +228,7 @@ class RendezvousChannelKoval<E>(
224
228
head = _head
225
229
headDeqIdx = head._deqIdx
226
230
if (head.id > headIdLimit || (head.id == headIdLimit && headDeqIdx >= headDeqIdxLimit)) {
227
- incElimReceiverArraySize( 1 ); incElimSenderArraySize( 1 )
231
+ localCounterUpdate ++
228
232
continue @try_again
229
233
}
230
234
}
@@ -273,18 +277,19 @@ class RendezvousChannelKoval<E>(
273
277
private fun tryEliminateSender (element : Any ): Unit? {
274
278
val elimReceiverArraySize = _elimReceiverArraySize
275
279
if (elimReceiverArraySize > 0 ) {
276
- // _elimsTotal++
280
+ _elimsTotal ++
277
281
val position = ThreadLocalRandom .current().nextInt(elimReceiverArraySize)
278
282
attempt@ for (i in max(0 , position - 1 ) .. min(position + 1 , elimReceiverArraySize - 1 )) {
279
283
val x = _elimReceiverArray [i]
280
284
when (x) {
281
285
null -> { continue @attempt }
282
286
ELIM_RECEIVER_ELEMENT -> {
283
287
if (_elimReceiverArray .compareAndSet(i, x, Done (element))) {
284
- // _elimsSucc++
288
+ _elimsSucc ++
285
289
return Unit
286
290
} else incElimReceiverArraySize(1 )
287
291
}
292
+ else -> incElimReceiverArraySize(1 )
288
293
}
289
294
}
290
295
// Elimination was unsuccessful :(
@@ -293,7 +298,7 @@ class RendezvousChannelKoval<E>(
293
298
294
299
val elimSenderArraySize = _elimSenderArraySize
295
300
if (elimSenderArraySize > 0 ) {
296
- // _elimsTotal++
301
+ _elimsTotal ++
297
302
val position = ThreadLocalRandom .current().nextInt(elimSenderArraySize)
298
303
attempt@ for (i in max(0 , position - 1 ) .. min(position + 1 , elimSenderArraySize - 1 )) {
299
304
val x = _elimSenderArray [i]
@@ -306,19 +311,20 @@ class RendezvousChannelKoval<E>(
306
311
val probablyDone = _elimSenderArray [i]
307
312
if (probablyDone == ELIM_SENDER_DONE ) {
308
313
_elimSenderArray [i] = null
309
- // _elimsSucc++
314
+ _elimsSucc ++
310
315
return Unit
311
316
}
312
317
}
313
318
if (! _elimSenderArray .compareAndSet(i, box, null )) {
314
319
// _elimSenderArray[i] == ELIM_SENDER_DONE
315
320
incElimSenderArraySize(1 )
316
321
_elimSenderArray [i] = null
317
- // _elimsSucc++
322
+ _elimsSucc ++
318
323
return Unit
319
324
}
320
325
} else incElimSenderArraySize(1 )
321
326
}
327
+ else -> incElimSenderArraySize(1 )
322
328
}
323
329
}
324
330
decElimSenderArraySize(1 )
@@ -330,18 +336,19 @@ class RendezvousChannelKoval<E>(
330
336
private fun tryEliminateReceiver (): Any? {
331
337
val elimSenderArraySize = _elimSenderArraySize
332
338
if (elimSenderArraySize > 0 ) {
333
- // _elimsTotal++
339
+ _elimsTotal ++
334
340
val position = ThreadLocalRandom .current().nextInt(elimSenderArraySize)
335
341
attempt@ for (i in max(0 , position - 1 ) .. min(position + 1 , elimSenderArraySize - 1 )) {
336
342
val x = _elimSenderArray [i]
337
343
when (x) {
338
344
null -> continue @attempt
339
345
is ElementBox -> {
340
346
if (_elimSenderArray .compareAndSet(i, x, ELIM_SENDER_DONE )) {
341
- // _elimsSucc++
347
+ _elimsSucc ++
342
348
return x.value
343
349
} else incElimSenderArraySize(1 )
344
350
}
351
+ else -> incElimSenderArraySize(1 )
345
352
}
346
353
}
347
354
// Elimination was unsuccessful :(
@@ -350,7 +357,7 @@ class RendezvousChannelKoval<E>(
350
357
351
358
val elimReceiverArraySize = _elimReceiverArraySize
352
359
if (elimReceiverArraySize > 0 ) {
353
- // _elimsTotal++
360
+ _elimsTotal ++
354
361
val position = ThreadLocalRandom .current().nextInt(elimReceiverArraySize)
355
362
attempt@ for (i in max(0 , position - 1 ) .. min(position + 1 , elimReceiverArraySize - 1 )) {
356
363
val x = _elimReceiverArray [i]
@@ -362,19 +369,20 @@ class RendezvousChannelKoval<E>(
362
369
if (probablyDone is Done ) {
363
370
val res = probablyDone.value
364
371
_elimReceiverArray [i] = null
365
- // _elimsSucc++
372
+ _elimsSucc ++
366
373
return res
367
374
}
368
375
}
369
376
if (! _elimReceiverArray .compareAndSet(i, ELIM_RECEIVER_ELEMENT , null )) {
370
377
val done = _elimReceiverArray [i] as Done
371
378
_elimReceiverArray [i] = null
372
379
incElimReceiverArraySize(1 )
373
- // _elimsSucc++
380
+ _elimsSucc ++
374
381
return done.value
375
382
}
376
- }
383
+ } else incElimReceiverArraySize( 1 )
377
384
}
385
+ else -> incElimReceiverArraySize(1 )
378
386
}
379
387
}
380
388
// Elimination was unsuccessful :(
@@ -395,6 +403,7 @@ class RendezvousChannelKoval<E>(
395
403
396
404
// This method is based on `#sendOrReceiveSuspend`. Returns `null` if fails.
397
405
private fun <T > sendOrReceiveNonSuspend (element : Any ): T ? {
406
+ var localCounterUpdate = 0
398
407
try_again@ while (true ) { // CAS loop
399
408
// Read the tail and its enqueue index at first, then the head and its indexes.
400
409
val tail = _tail
@@ -411,10 +420,12 @@ class RendezvousChannelKoval<E>(
411
420
if (adjustHead(head)) continue @try_again
412
421
// Queue is empty, try to do elimination
413
422
// and return `null` if it fails.
423
+ if (localCounterUpdate > 0 ) { incElimSenderArraySize(1 ); incElimReceiverArraySize(1 ) }
414
424
return tryEliminate(head, headEnqIdx, element) as T
415
425
} else {
416
426
// Queue is empty, try to do elimination
417
427
// and return `null` if it fails.
428
+ if (localCounterUpdate > 0 ) { incElimSenderArraySize(1 ); incElimReceiverArraySize(1 ) }
418
429
return tryEliminate(head, headEnqIdx, element) as T
419
430
}
420
431
} else {
@@ -425,7 +436,7 @@ class RendezvousChannelKoval<E>(
425
436
if (firstElement == TAKEN_ELEMENT ) {
426
437
// Try to move the deque index in the `head` node
427
438
deqIdxUpdater.compareAndSet(head, headDeqIdx, headDeqIdx + 1 )
428
- incElimReceiverArraySize( 1 ); incElimSenderArraySize( 1 )
439
+ localCounterUpdate ++
429
440
continue @try_again
430
441
}
431
442
val makeRendezvous = if (element == RECEIVER_ELEMENT ) firstElement != RECEIVER_ELEMENT else firstElement == RECEIVER_ELEMENT
@@ -435,6 +446,7 @@ class RendezvousChannelKoval<E>(
435
446
while (true ) {
436
447
if (tryResumeContinuation(head, headDeqIdx, element)) {
437
448
// The rendezvous is happened, congratulations!
449
+ if (localCounterUpdate > 0 ) { incElimSenderArraySize(1 ); incElimReceiverArraySize(1 ) }
438
450
return (if (element == RECEIVER_ELEMENT ) firstElement else Unit ) as T
439
451
}
440
452
// Re-read the required pointers
@@ -443,12 +455,15 @@ class RendezvousChannelKoval<E>(
443
455
head = _head
444
456
headDeqIdx = head._deqIdx
445
457
if (headDeqIdx == segmentSize) {
446
- if (! adjustHead(head)) { incElimReceiverArraySize( 1 ); incElimSenderArraySize( 1 ) ; continue @try_again }
458
+ if (! adjustHead(head)) { localCounterUpdate ++ ; continue @try_again }
447
459
continue @read_state
448
460
}
449
461
// Check that `(head.id, headDeqIdx) < (headIdLimit, headDeqIdxLimit)`
450
462
// and re-start the whole operation if needed
451
- if (head.id > headIdLimit || (head.id == headIdLimit && headDeqIdx >= headDeqIdxLimit)) { incElimReceiverArraySize(1 ); incElimSenderArraySize(1 ); continue @try_again }
463
+ if (head.id > headIdLimit || (head.id == headIdLimit && headDeqIdx >= headDeqIdxLimit)) {
464
+ localCounterUpdate++
465
+ continue @try_again
466
+ }
452
467
// Re-read the first element
453
468
firstElement = readElement(head, headDeqIdx)
454
469
if (firstElement == TAKEN_ELEMENT ) {
@@ -459,6 +474,7 @@ class RendezvousChannelKoval<E>(
459
474
}
460
475
}
461
476
} else {
477
+ if (localCounterUpdate > 0 ) { incElimSenderArraySize(1 ); incElimReceiverArraySize(1 ) }
462
478
return null
463
479
}
464
480
}
0 commit comments