@@ -46,7 +46,7 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
46
46
protected open fun offerInternal (element : E ): Any {
47
47
while (true ) {
48
48
val receive = takeFirstReceiveOrPeekClosed() ? : return OFFER_FAILED
49
- val token = receive.tryResumeReceive(element, idempotent = null )
49
+ val token = receive.tryResumeReceive(element, null , null )
50
50
if (token != null ) {
51
51
receive.completeResumeReceive(token)
52
52
return receive.offerResult
@@ -56,7 +56,7 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
56
56
57
57
/* *
58
58
* Tries to add element to buffer or to queued receiver if select statement clause was not selected yet.
59
- * Return type is `ALREADY_SELECTED | OFFER_SUCCESS | OFFER_FAILED | Closed`.
59
+ * Return type is `ALREADY_SELECTED | OFFER_SUCCESS | OFFER_FAILED | RETRY_ATOMIC | Closed`.
60
60
* @suppress **This is unstable API and it is subject to change.**
61
61
*/
62
62
protected open fun offerSelectInternal (element : E , select : SelectInstance <* >): Any {
@@ -352,10 +352,14 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
352
352
else -> null
353
353
}
354
354
355
- override fun validatePrepared (node : ReceiveOrClosed <E >): Boolean {
356
- val token = node.tryResumeReceive(element, idempotent = this ) ? : return false
355
+ @Suppress(" UNCHECKED_CAST" )
356
+ override fun onPrepare (affected : LockFreeLinkedListNode , next : LockFreeLinkedListNode ): Any? {
357
+ affected as ReceiveOrClosed <E > // type assertion, see "failure" impl
358
+ val beforeStart = { finishPrepare(affected, next) }
359
+ val token = affected.tryResumeReceive(element, this , beforeStart) ? : return REMOVE_PREPARED
360
+ if (token == = RETRY_ATOMIC ) return RETRY_ATOMIC
357
361
resumeToken = token
358
- return true
362
+ return null
359
363
}
360
364
}
361
365
@@ -388,6 +392,7 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
388
392
when {
389
393
offerResult == = ALREADY_SELECTED -> return
390
394
offerResult == = OFFER_FAILED -> {} // retry
395
+ offerResult == = RETRY_ATOMIC -> {} // retry
391
396
offerResult == = OFFER_SUCCESS -> {
392
397
block.startCoroutineUnintercepted(receiver = this , completion = select.completion)
393
398
return
@@ -437,8 +442,8 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
437
442
@JvmField val select : SelectInstance <R >,
438
443
@JvmField val block : suspend (SendChannel <E >) -> R
439
444
) : Send(), DisposableHandle {
440
- override fun tryResumeSend (idempotent : Any ? ): Any? =
441
- if ( select.trySelect (idempotent)) SELECT_STARTED else null
445
+ override fun tryResumeSend (idempotent : AtomicDesc ? , beforeStart : (() -> Unit ) ? ): Any? =
446
+ select.trySelectIdempotent (idempotent, beforeStart)
442
447
443
448
override fun completeResumeSend (token : Any ) {
444
449
assert { token == = SELECT_STARTED }
@@ -450,7 +455,7 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
450
455
}
451
456
452
457
override fun resumeSendClosed (closed : Closed <* >) {
453
- if (select.trySelect(null ))
458
+ if (select.trySelect())
454
459
select.resumeSelectCancellableWithException(closed.sendException)
455
460
}
456
461
@@ -461,7 +466,10 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
461
466
@JvmField val element : E
462
467
) : Send() {
463
468
override val pollResult: Any? get() = element
464
- override fun tryResumeSend (idempotent : Any? ): Any? = SEND_RESUMED
469
+ override fun tryResumeSend (idempotent : AtomicDesc ? , beforeStart : (() -> Unit )? ): Any? {
470
+ beforeStart?.invoke()
471
+ return SEND_RESUMED
472
+ }
465
473
override fun completeResumeSend (token : Any ) { assert { token == = SEND_RESUMED } }
466
474
override fun resumeSendClosed (closed : Closed <* >) {}
467
475
}
@@ -495,7 +503,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
495
503
protected open fun pollInternal (): Any? {
496
504
while (true ) {
497
505
val send = takeFirstSendOrPeekClosed() ? : return POLL_FAILED
498
- val token = send.tryResumeSend(idempotent = null )
506
+ val token = send.tryResumeSend(null , null )
499
507
if (token != null ) {
500
508
send.completeResumeSend(token)
501
509
return send.pollResult
@@ -505,7 +513,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
505
513
506
514
/* *
507
515
* Tries to remove element from buffer or from queued sender if select statement clause was not selected yet.
508
- * Return type is `ALREADY_SELECTED | E | POLL_FAILED | Closed`
516
+ * Return type is `ALREADY_SELECTED | E | POLL_FAILED | RETRY_ATOMIC | Closed`
509
517
* @suppress **This is unstable API and it is subject to change.**
510
518
*/
511
519
protected open fun pollSelectInternal (select : SelectInstance <* >): Any? {
@@ -655,11 +663,14 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
655
663
}
656
664
657
665
@Suppress(" UNCHECKED_CAST" )
658
- override fun validatePrepared (node : Send ): Boolean {
659
- val token = node.tryResumeSend(idempotent = this ) ? : return false
666
+ override fun onPrepare (affected : LockFreeLinkedListNode , next : LockFreeLinkedListNode ): Any? {
667
+ affected as Send // type assertion, see "failure" impl
668
+ val beforeStart = { finishPrepare(affected, next) }
669
+ val token = affected.tryResumeSend(this , beforeStart) ? : return REMOVE_PREPARED
670
+ if (token == = RETRY_ATOMIC ) return RETRY_ATOMIC
660
671
resumeToken = token
661
- pollResult = node .pollResult as E
662
- return true
672
+ pollResult = affected .pollResult as E
673
+ return null
663
674
}
664
675
}
665
676
@@ -681,6 +692,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
681
692
when {
682
693
pollResult == = ALREADY_SELECTED -> return
683
694
pollResult == = POLL_FAILED -> {} // retry
695
+ pollResult == = RETRY_ATOMIC -> {} // retry
684
696
pollResult is Closed <* > -> throw recoverStackTrace(pollResult.receiveException)
685
697
else -> {
686
698
block.startCoroutineUnintercepted(pollResult as E , select.completion)
@@ -709,9 +721,10 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
709
721
when {
710
722
pollResult == = ALREADY_SELECTED -> return
711
723
pollResult == = POLL_FAILED -> {} // retry
724
+ pollResult == = RETRY_ATOMIC -> {} // retry
712
725
pollResult is Closed <* > -> {
713
726
if (pollResult.closeCause == null ) {
714
- if (select.trySelect(null ))
727
+ if (select.trySelect())
715
728
block.startCoroutineUnintercepted(null , select.completion)
716
729
return
717
730
} else {
@@ -746,6 +759,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
746
759
when {
747
760
pollResult == = ALREADY_SELECTED -> return
748
761
pollResult == = POLL_FAILED -> {} // retry
762
+ pollResult == = RETRY_ATOMIC -> {} // retry
749
763
pollResult is Closed <* > -> {
750
764
block.startCoroutineUnintercepted(ValueOrClosed .closed(pollResult.closeCause), select.completion)
751
765
}
@@ -870,7 +884,11 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
870
884
}
871
885
872
886
@Suppress(" IMPLICIT_CAST_TO_ANY" )
873
- override fun tryResumeReceive (value : E , idempotent : Any? ): Any? = cont.tryResume(resumeValue(value), idempotent)
887
+ override fun tryResumeReceive (value : E , idempotent : AtomicDesc ? , beforeStart : (() -> Unit )? ): Any? {
888
+ beforeStart?.invoke()
889
+ return cont.tryResume(resumeValue(value), idempotent)
890
+ }
891
+
874
892
override fun completeResumeReceive (token : Any ) = cont.completeResume(token)
875
893
override fun resumeReceiveClosed (closed : Closed <* >) {
876
894
when {
@@ -886,7 +904,8 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
886
904
@JvmField val iterator : Itr <E >,
887
905
@JvmField val cont : CancellableContinuation <Boolean >
888
906
) : Receive<E>() {
889
- override fun tryResumeReceive (value : E , idempotent : Any? ): Any? {
907
+ override fun tryResumeReceive (value : E , idempotent : AtomicDesc ? , beforeStart : (() -> Unit )? ): Any? {
908
+ beforeStart?.invoke()
890
909
val token = cont.tryResume(true , idempotent)
891
910
if (token != null ) {
892
911
/*
@@ -928,8 +947,10 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
928
947
@JvmField val block : suspend (Any? ) -> R ,
929
948
@JvmField val receiveMode : Int
930
949
) : Receive<E>(), DisposableHandle {
931
- override fun tryResumeReceive (value : E , idempotent : Any? ): Any? =
932
- if (select.trySelect(idempotent)) (value ? : NULL_VALUE ) else null
950
+ override fun tryResumeReceive (value : E , idempotent : AtomicDesc ? , beforeStart : (() -> Unit )? ): Any? {
951
+ val result = select.trySelectIdempotent(idempotent, beforeStart)
952
+ return if (result == = SELECT_STARTED ) value ? : NULL_VALUE else result
953
+ }
933
954
934
955
@Suppress(" UNCHECKED_CAST" )
935
956
override fun completeResumeReceive (token : Any ) {
@@ -938,7 +959,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
938
959
}
939
960
940
961
override fun resumeReceiveClosed (closed : Closed <* >) {
941
- if (! select.trySelect(null )) return
962
+ if (! select.trySelect()) return
942
963
when (receiveMode) {
943
964
RECEIVE_THROWS_ON_CLOSE -> select.resumeSelectCancellableWithException(closed.receiveException)
944
965
RECEIVE_RESULT -> block.startCoroutine(ValueOrClosed .closed<R >(closed.closeCause), select.completion)
@@ -985,10 +1006,6 @@ internal val POLL_FAILED: Any = Symbol("POLL_FAILED")
985
1006
@SharedImmutable
986
1007
internal val ENQUEUE_FAILED : Any = Symbol (" ENQUEUE_FAILED" )
987
1008
988
- @JvmField
989
- @SharedImmutable
990
- internal val SELECT_STARTED : Any = Symbol (" SELECT_STARTED" )
991
-
992
1009
@JvmField
993
1010
@SharedImmutable
994
1011
internal val NULL_VALUE : Symbol = Symbol (" NULL_VALUE" )
@@ -1012,7 +1029,8 @@ internal typealias Handler = (Throwable?) -> Unit
1012
1029
*/
1013
1030
internal abstract class Send : LockFreeLinkedListNode () {
1014
1031
abstract val pollResult: Any? // E | Closed
1015
- abstract fun tryResumeSend (idempotent : Any? ): Any?
1032
+ // Returns: null - failure, RETRY_ATOMIC for retry (only when idempotent != null), otherwise token for completeResumeSend
1033
+ abstract fun tryResumeSend (idempotent : AtomicDesc ? , beforeStart : (() -> Unit )? ): Any?
1016
1034
abstract fun completeResumeSend (token : Any )
1017
1035
abstract fun resumeSendClosed (closed : Closed <* >)
1018
1036
}
@@ -1022,7 +1040,8 @@ internal abstract class Send : LockFreeLinkedListNode() {
1022
1040
*/
1023
1041
internal interface ReceiveOrClosed <in E > {
1024
1042
val offerResult: Any // OFFER_SUCCESS | Closed
1025
- fun tryResumeReceive (value : E , idempotent : Any? ): Any?
1043
+ // Returns: null - failure, RETRY_ATOMIC for retry (only when idempotent != null), otherwise token for completeResumeReceive
1044
+ fun tryResumeReceive (value : E , idempotent : AtomicDesc ? , beforeStart : (() -> Unit )? ): Any?
1026
1045
fun completeResumeReceive (token : Any )
1027
1046
}
1028
1047
@@ -1034,7 +1053,10 @@ internal class SendElement(
1034
1053
override val pollResult : Any? ,
1035
1054
@JvmField val cont : CancellableContinuation <Unit >
1036
1055
) : Send() {
1037
- override fun tryResumeSend (idempotent : Any? ): Any? = cont.tryResume(Unit , idempotent)
1056
+ override fun tryResumeSend (idempotent : AtomicDesc ? , beforeStart : (() -> Unit )? ): Any? {
1057
+ beforeStart?.invoke()
1058
+ return cont.tryResume(Unit , idempotent)
1059
+ }
1038
1060
override fun completeResumeSend (token : Any ) = cont.completeResume(token)
1039
1061
override fun resumeSendClosed (closed : Closed <* >) = cont.resumeWithException(closed.sendException)
1040
1062
override fun toString (): String = " SendElement($pollResult )"
@@ -1051,9 +1073,15 @@ internal class Closed<in E>(
1051
1073
1052
1074
override val offerResult get() = this
1053
1075
override val pollResult get() = this
1054
- override fun tryResumeSend (idempotent : Any? ): Any? = CLOSE_RESUMED
1076
+ override fun tryResumeSend (idempotent : AtomicDesc ? , beforeStart : (() -> Unit )? ): Any? {
1077
+ beforeStart?.invoke()
1078
+ return CLOSE_RESUMED
1079
+ }
1055
1080
override fun completeResumeSend (token : Any ) { assert { token == = CLOSE_RESUMED } }
1056
- override fun tryResumeReceive (value : E , idempotent : Any? ): Any? = CLOSE_RESUMED
1081
+ override fun tryResumeReceive (value : E , idempotent : AtomicDesc ? , beforeStart : (() -> Unit )? ): Any? {
1082
+ beforeStart?.invoke()
1083
+ return CLOSE_RESUMED
1084
+ }
1057
1085
override fun completeResumeReceive (token : Any ) { assert { token == = CLOSE_RESUMED } }
1058
1086
override fun resumeSendClosed (closed : Closed <* >) = assert { false } // "Should be never invoked"
1059
1087
override fun toString (): String = " Closed[$closeCause ]"
0 commit comments