@@ -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 )
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 {
@@ -362,10 +362,13 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
362
362
else -> null
363
363
}
364
364
365
- override fun validatePrepared (node : ReceiveOrClosed <E >): Boolean {
366
- val token = node.tryResumeReceive(element, idempotent = this ) ? : return false
365
+ @Suppress(" UNCHECKED_CAST" )
366
+ override fun onPrepare (prepareOp : PrepareOp ): Any? {
367
+ val affected = prepareOp.affected as ReceiveOrClosed <E > // see "failure" impl
368
+ val token = affected.tryResumeReceive(element, prepareOp) ? : return REMOVE_PREPARED
369
+ if (token == = RETRY_ATOMIC ) return RETRY_ATOMIC
367
370
resumeToken = token
368
- return true
371
+ return null
369
372
}
370
373
}
371
374
@@ -398,6 +401,7 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
398
401
when {
399
402
offerResult == = ALREADY_SELECTED -> return
400
403
offerResult == = OFFER_FAILED -> {} // retry
404
+ offerResult == = RETRY_ATOMIC -> {} // retry
401
405
offerResult == = OFFER_SUCCESS -> {
402
406
block.startCoroutineUnintercepted(receiver = this , completion = select.completion)
403
407
return
@@ -447,8 +451,8 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
447
451
@JvmField val select : SelectInstance <R >,
448
452
@JvmField val block : suspend (SendChannel <E >) -> R
449
453
) : Send(), DisposableHandle {
450
- override fun tryResumeSend (idempotent : Any ? ): Any? =
451
- if ( select.trySelect(idempotent)) SELECT_STARTED else null
454
+ override fun tryResumeSend (otherOp : PrepareOp ? ): Any? =
455
+ select.trySelectOther(otherOp)
452
456
453
457
override fun completeResumeSend (token : Any ) {
454
458
assert { token == = SELECT_STARTED }
@@ -460,7 +464,7 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
460
464
}
461
465
462
466
override fun resumeSendClosed (closed : Closed <* >) {
463
- if (select.trySelect(null ))
467
+ if (select.trySelect())
464
468
select.resumeSelectCancellableWithException(closed.sendException)
465
469
}
466
470
@@ -471,7 +475,7 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
471
475
@JvmField val element : E
472
476
) : Send() {
473
477
override val pollResult: Any? get() = element
474
- override fun tryResumeSend (idempotent : Any ? ): Any? = SEND_RESUMED
478
+ override fun tryResumeSend (otherOp : PrepareOp ? ): Any? = SEND_RESUMED . also { otherOp?.finishPrepare() }
475
479
override fun completeResumeSend (token : Any ) { assert { token == = SEND_RESUMED } }
476
480
override fun resumeSendClosed (closed : Closed <* >) {}
477
481
}
@@ -505,7 +509,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
505
509
protected open fun pollInternal (): Any? {
506
510
while (true ) {
507
511
val send = takeFirstSendOrPeekClosed() ? : return POLL_FAILED
508
- val token = send.tryResumeSend(idempotent = null )
512
+ val token = send.tryResumeSend(null )
509
513
if (token != null ) {
510
514
send.completeResumeSend(token)
511
515
return send.pollResult
@@ -515,7 +519,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
515
519
516
520
/* *
517
521
* Tries to remove element from buffer or from queued sender if select statement clause was not selected yet.
518
- * Return type is `ALREADY_SELECTED | E | POLL_FAILED | Closed`
522
+ * Return type is `ALREADY_SELECTED | E | POLL_FAILED | RETRY_ATOMIC | Closed`
519
523
* @suppress **This is unstable API and it is subject to change.**
520
524
*/
521
525
protected open fun pollSelectInternal (select : SelectInstance <* >): Any? {
@@ -679,11 +683,13 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
679
683
}
680
684
681
685
@Suppress(" UNCHECKED_CAST" )
682
- override fun validatePrepared (node : Send ): Boolean {
683
- val token = node.tryResumeSend(idempotent = this ) ? : return false
686
+ override fun onPrepare (prepareOp : PrepareOp ): Any? {
687
+ val affected = prepareOp.affected as Send // see "failure" impl
688
+ val token = affected.tryResumeSend(prepareOp) ? : return REMOVE_PREPARED
689
+ if (token == = RETRY_ATOMIC ) return RETRY_ATOMIC
684
690
resumeToken = token
685
- pollResult = node .pollResult as E
686
- return true
691
+ pollResult = affected .pollResult as E
692
+ return null
687
693
}
688
694
}
689
695
@@ -705,6 +711,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
705
711
when {
706
712
pollResult == = ALREADY_SELECTED -> return
707
713
pollResult == = POLL_FAILED -> {} // retry
714
+ pollResult == = RETRY_ATOMIC -> {} // retry
708
715
pollResult is Closed <* > -> throw recoverStackTrace(pollResult.receiveException)
709
716
else -> {
710
717
block.startCoroutineUnintercepted(pollResult as E , select.completion)
@@ -733,9 +740,10 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
733
740
when {
734
741
pollResult == = ALREADY_SELECTED -> return
735
742
pollResult == = POLL_FAILED -> {} // retry
743
+ pollResult == = RETRY_ATOMIC -> {} // retry
736
744
pollResult is Closed <* > -> {
737
745
if (pollResult.closeCause == null ) {
738
- if (select.trySelect(null ))
746
+ if (select.trySelect())
739
747
block.startCoroutineUnintercepted(null , select.completion)
740
748
return
741
749
} else {
@@ -770,6 +778,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
770
778
when {
771
779
pollResult == = ALREADY_SELECTED -> return
772
780
pollResult == = POLL_FAILED -> {} // retry
781
+ pollResult == = RETRY_ATOMIC -> {} // retry
773
782
pollResult is Closed <* > -> {
774
783
block.startCoroutineUnintercepted(ValueOrClosed .closed(pollResult.closeCause), select.completion)
775
784
}
@@ -894,7 +903,11 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
894
903
}
895
904
896
905
@Suppress(" IMPLICIT_CAST_TO_ANY" )
897
- override fun tryResumeReceive (value : E , idempotent : Any? ): Any? = cont.tryResume(resumeValue(value), idempotent)
906
+ override fun tryResumeReceive (value : E , otherOp : PrepareOp ? ): Any? {
907
+ otherOp?.finishPrepare()
908
+ return cont.tryResume(resumeValue(value), otherOp?.desc)
909
+ }
910
+
898
911
override fun completeResumeReceive (token : Any ) = cont.completeResume(token)
899
912
override fun resumeReceiveClosed (closed : Closed <* >) {
900
913
when {
@@ -910,15 +923,16 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
910
923
@JvmField val iterator : Itr <E >,
911
924
@JvmField val cont : CancellableContinuation <Boolean >
912
925
) : Receive<E>() {
913
- override fun tryResumeReceive (value : E , idempotent : Any? ): Any? {
914
- val token = cont.tryResume(true , idempotent)
926
+ override fun tryResumeReceive (value : E , otherOp : PrepareOp ? ): Any? {
927
+ otherOp?.finishPrepare()
928
+ val token = cont.tryResume(true , otherOp?.desc)
915
929
if (token != null ) {
916
930
/*
917
- When idempotent != null this invocation can be stale and we cannot directly update iterator.result
931
+ When otherOp != null this invocation can be stale and we cannot directly update iterator.result
918
932
Instead, we save both token & result into a temporary IdempotentTokenValue object and
919
933
set iterator result only in completeResumeReceive that is going to be invoked just once
920
934
*/
921
- if (idempotent != null ) return IdempotentTokenValue (token, value)
935
+ if (otherOp != null ) return IdempotentTokenValue (token, value)
922
936
iterator.result = value
923
937
}
924
938
return token
@@ -952,8 +966,10 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
952
966
@JvmField val block : suspend (Any? ) -> R ,
953
967
@JvmField val receiveMode : Int
954
968
) : Receive<E>(), DisposableHandle {
955
- override fun tryResumeReceive (value : E , idempotent : Any? ): Any? =
956
- if (select.trySelect(idempotent)) (value ? : NULL_VALUE ) else null
969
+ override fun tryResumeReceive (value : E , otherOp : PrepareOp ? ): Any? {
970
+ val result = select.trySelectOther(otherOp)
971
+ return if (result == = SELECT_STARTED ) value ? : NULL_VALUE else result
972
+ }
957
973
958
974
@Suppress(" UNCHECKED_CAST" )
959
975
override fun completeResumeReceive (token : Any ) {
@@ -962,7 +978,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
962
978
}
963
979
964
980
override fun resumeReceiveClosed (closed : Closed <* >) {
965
- if (! select.trySelect(null )) return
981
+ if (! select.trySelect()) return
966
982
when (receiveMode) {
967
983
RECEIVE_THROWS_ON_CLOSE -> select.resumeSelectCancellableWithException(closed.receiveException)
968
984
RECEIVE_RESULT -> block.startCoroutine(ValueOrClosed .closed<R >(closed.closeCause), select.completion)
@@ -1009,10 +1025,6 @@ internal val POLL_FAILED: Any = Symbol("POLL_FAILED")
1009
1025
@SharedImmutable
1010
1026
internal val ENQUEUE_FAILED : Any = Symbol (" ENQUEUE_FAILED" )
1011
1027
1012
- @JvmField
1013
- @SharedImmutable
1014
- internal val SELECT_STARTED : Any = Symbol (" SELECT_STARTED" )
1015
-
1016
1028
@JvmField
1017
1029
@SharedImmutable
1018
1030
internal val NULL_VALUE : Symbol = Symbol (" NULL_VALUE" )
@@ -1036,7 +1048,11 @@ internal typealias Handler = (Throwable?) -> Unit
1036
1048
*/
1037
1049
internal abstract class Send : LockFreeLinkedListNode () {
1038
1050
abstract val pollResult: Any? // E | Closed
1039
- abstract fun tryResumeSend (idempotent : Any? ): Any?
1051
+ // Returns: null - failure,
1052
+ // RETRY_ATOMIC for retry (only when otherOp != null),
1053
+ // otherwise token for completeResumeSend
1054
+ // Must call otherOp?.finishPrepare() before deciding on result other than RETRY_ATOMIC
1055
+ abstract fun tryResumeSend (otherOp : PrepareOp ? ): Any?
1040
1056
abstract fun completeResumeSend (token : Any )
1041
1057
abstract fun resumeSendClosed (closed : Closed <* >)
1042
1058
}
@@ -1046,7 +1062,11 @@ internal abstract class Send : LockFreeLinkedListNode() {
1046
1062
*/
1047
1063
internal interface ReceiveOrClosed <in E > {
1048
1064
val offerResult: Any // OFFER_SUCCESS | Closed
1049
- fun tryResumeReceive (value : E , idempotent : Any? ): Any?
1065
+ // Returns: null - failure,
1066
+ // RETRY_ATOMIC for retry (only when otherOp != null),
1067
+ // otherwise token for completeResumeReceive
1068
+ // Must call otherOp?.finishPrepare() before deciding on result other than RETRY_ATOMIC
1069
+ fun tryResumeReceive (value : E , otherOp : PrepareOp ? ): Any?
1050
1070
fun completeResumeReceive (token : Any )
1051
1071
}
1052
1072
@@ -1058,7 +1078,10 @@ internal class SendElement(
1058
1078
override val pollResult : Any? ,
1059
1079
@JvmField val cont : CancellableContinuation <Unit >
1060
1080
) : Send() {
1061
- override fun tryResumeSend (idempotent : Any? ): Any? = cont.tryResume(Unit , idempotent)
1081
+ override fun tryResumeSend (otherOp : PrepareOp ? ): Any? {
1082
+ otherOp?.finishPrepare()
1083
+ return cont.tryResume(Unit , otherOp?.desc)
1084
+ }
1062
1085
override fun completeResumeSend (token : Any ) = cont.completeResume(token)
1063
1086
override fun resumeSendClosed (closed : Closed <* >) = cont.resumeWithException(closed.sendException)
1064
1087
override fun toString (): String = " SendElement($pollResult )"
@@ -1075,9 +1098,9 @@ internal class Closed<in E>(
1075
1098
1076
1099
override val offerResult get() = this
1077
1100
override val pollResult get() = this
1078
- override fun tryResumeSend (idempotent : Any ? ): Any? = CLOSE_RESUMED
1101
+ override fun tryResumeSend (otherOp : PrepareOp ? ): Any? = CLOSE_RESUMED . also { otherOp?.finishPrepare() }
1079
1102
override fun completeResumeSend (token : Any ) { assert { token == = CLOSE_RESUMED } }
1080
- override fun tryResumeReceive (value : E , idempotent : Any ? ): Any? = CLOSE_RESUMED
1103
+ override fun tryResumeReceive (value : E , otherOp : PrepareOp ? ): Any? = CLOSE_RESUMED . also { otherOp?.finishPrepare() }
1081
1104
override fun completeResumeReceive (token : Any ) { assert { token == = CLOSE_RESUMED } }
1082
1105
override fun resumeSendClosed (closed : Closed <* >) = assert { false } // "Should be never invoked"
1083
1106
override fun toString (): String = " Closed[$closeCause ]"
0 commit comments