@@ -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,11 @@ 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
+ override fun validatePrepared (node : ReceiveOrClosed <E >): Any? {
356
+ val token = node.tryResumeReceive(element, idempotent = this ) ? : return REMOVE_PREPARED
357
+ if (token == = RETRY_ATOMIC ) return RETRY_ATOMIC
357
358
resumeToken = token
358
- return true
359
+ return null
359
360
}
360
361
}
361
362
@@ -388,6 +389,7 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
388
389
when {
389
390
offerResult == = ALREADY_SELECTED -> return
390
391
offerResult == = OFFER_FAILED -> {} // retry
392
+ offerResult == = RETRY_ATOMIC -> {} // retry
391
393
offerResult == = OFFER_SUCCESS -> {
392
394
block.startCoroutineUnintercepted(receiver = this , completion = select.completion)
393
395
return
@@ -438,7 +440,7 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
438
440
@JvmField val block : suspend (SendChannel <E >) -> R
439
441
) : Send(), DisposableHandle {
440
442
override fun tryResumeSend (idempotent : Any? ): Any? =
441
- if ( select.trySelect (idempotent)) SELECT_STARTED else null
443
+ select.trySelectIdempotent (idempotent)
442
444
443
445
override fun completeResumeSend (token : Any ) {
444
446
assert { token == = SELECT_STARTED }
@@ -450,7 +452,7 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
450
452
}
451
453
452
454
override fun resumeSendClosed (closed : Closed <* >) {
453
- if (select.trySelect(null ))
455
+ if (select.trySelect())
454
456
select.resumeSelectCancellableWithException(closed.sendException)
455
457
}
456
458
@@ -505,7 +507,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
505
507
506
508
/* *
507
509
* 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`
510
+ * Return type is `ALREADY_SELECTED | E | POLL_FAILED | RETRY_ATOMIC | Closed`
509
511
* @suppress **This is unstable API and it is subject to change.**
510
512
*/
511
513
protected open fun pollSelectInternal (select : SelectInstance <* >): Any? {
@@ -655,11 +657,12 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
655
657
}
656
658
657
659
@Suppress(" UNCHECKED_CAST" )
658
- override fun validatePrepared (node : Send ): Boolean {
659
- val token = node.tryResumeSend(idempotent = this ) ? : return false
660
+ override fun validatePrepared (node : Send ): Any? {
661
+ val token = node.tryResumeSend(idempotent = this ) ? : return REMOVE_PREPARED
662
+ if (token == = RETRY_ATOMIC ) return RETRY_ATOMIC
660
663
resumeToken = token
661
664
pollResult = node.pollResult as E
662
- return true
665
+ return null
663
666
}
664
667
}
665
668
@@ -681,6 +684,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
681
684
when {
682
685
pollResult == = ALREADY_SELECTED -> return
683
686
pollResult == = POLL_FAILED -> {} // retry
687
+ pollResult == = RETRY_ATOMIC -> {}
684
688
pollResult is Closed <* > -> throw recoverStackTrace(pollResult.receiveException)
685
689
else -> {
686
690
block.startCoroutineUnintercepted(pollResult as E , select.completion)
@@ -709,9 +713,10 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
709
713
when {
710
714
pollResult == = ALREADY_SELECTED -> return
711
715
pollResult == = POLL_FAILED -> {} // retry
716
+ pollResult == = RETRY_ATOMIC -> {} // retry
712
717
pollResult is Closed <* > -> {
713
718
if (pollResult.closeCause == null ) {
714
- if (select.trySelect(null ))
719
+ if (select.trySelect())
715
720
block.startCoroutineUnintercepted(null , select.completion)
716
721
return
717
722
} else {
@@ -746,6 +751,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
746
751
when {
747
752
pollResult == = ALREADY_SELECTED -> return
748
753
pollResult == = POLL_FAILED -> {} // retry
754
+ pollResult == = RETRY_ATOMIC -> {} // retry
749
755
pollResult is Closed <* > -> {
750
756
block.startCoroutineUnintercepted(ValueOrClosed .closed(pollResult.closeCause), select.completion)
751
757
}
@@ -928,8 +934,10 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
928
934
@JvmField val block : suspend (Any? ) -> R ,
929
935
@JvmField val receiveMode : Int
930
936
) : Receive<E>(), DisposableHandle {
931
- override fun tryResumeReceive (value : E , idempotent : Any? ): Any? =
932
- if (select.trySelect(idempotent)) (value ? : NULL_VALUE ) else null
937
+ override fun tryResumeReceive (value : E , idempotent : Any? ): Any? {
938
+ val result = select.trySelectIdempotent(idempotent)
939
+ return if (result == = SELECT_STARTED ) value ? : NULL_VALUE else result
940
+ }
933
941
934
942
@Suppress(" UNCHECKED_CAST" )
935
943
override fun completeResumeReceive (token : Any ) {
@@ -938,7 +946,7 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
938
946
}
939
947
940
948
override fun resumeReceiveClosed (closed : Closed <* >) {
941
- if (! select.trySelect(null )) return
949
+ if (! select.trySelect()) return
942
950
when (receiveMode) {
943
951
RECEIVE_THROWS_ON_CLOSE -> select.resumeSelectCancellableWithException(closed.receiveException)
944
952
RECEIVE_RESULT -> block.startCoroutine(ValueOrClosed .closed<R >(closed.closeCause), select.completion)
@@ -985,10 +993,6 @@ internal val POLL_FAILED: Any = Symbol("POLL_FAILED")
985
993
@SharedImmutable
986
994
internal val ENQUEUE_FAILED : Any = Symbol (" ENQUEUE_FAILED" )
987
995
988
- @JvmField
989
- @SharedImmutable
990
- internal val SELECT_STARTED : Any = Symbol (" SELECT_STARTED" )
991
-
992
996
@JvmField
993
997
@SharedImmutable
994
998
internal val NULL_VALUE : Symbol = Symbol (" NULL_VALUE" )
@@ -1012,6 +1016,7 @@ internal typealias Handler = (Throwable?) -> Unit
1012
1016
*/
1013
1017
internal abstract class Send : LockFreeLinkedListNode () {
1014
1018
abstract val pollResult: Any? // E | Closed
1019
+ // Returns: null - failure, RETRY_ATOMIC for retry (only when idempotent != null), otherwise token for completeResumeSend
1015
1020
abstract fun tryResumeSend (idempotent : Any? ): Any?
1016
1021
abstract fun completeResumeSend (token : Any )
1017
1022
abstract fun resumeSendClosed (closed : Closed <* >)
@@ -1022,6 +1027,7 @@ internal abstract class Send : LockFreeLinkedListNode() {
1022
1027
*/
1023
1028
internal interface ReceiveOrClosed <in E > {
1024
1029
val offerResult: Any // OFFER_SUCCESS | Closed
1030
+ // Returns: null - failure, RETRY_ATOMIC for retry (only when idempotent != null), otherwise token for completeResumeReceive
1025
1031
fun tryResumeReceive (value : E , idempotent : Any? ): Any?
1026
1032
fun completeResumeReceive (token : Any )
1027
1033
}
0 commit comments