@@ -382,7 +382,10 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
382
382
select.disposeOnSelect(node)
383
383
return
384
384
}
385
- enqueueResult is Closed <* > -> throw recoverStackTrace(helpCloseAndGetSendException(enqueueResult))
385
+ enqueueResult is Closed <* > -> {
386
+ node.dispose()
387
+ throw recoverStackTrace(helpCloseAndGetSendException(enqueueResult))
388
+ }
386
389
enqueueResult == = ENQUEUE_FAILED -> {} // try to offer
387
390
enqueueResult is Receive <* > -> {} // try to offer
388
391
else -> error(" enqueueSend returned $enqueueResult " )
@@ -448,16 +451,19 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
448
451
override val pollResult : Any? ,
449
452
@JvmField val channel : AbstractSendChannel <E >,
450
453
@JvmField val select : SelectInstance <R >,
451
- @JvmField val block : suspend (SendChannel <E >) -> R
454
+ block : suspend (SendChannel <E >) -> R
452
455
) : Send(), DisposableHandle {
456
+ @JvmField val block: suspend (SendChannel <E >) -> R = block.asShareable()
457
+
453
458
override fun tryResumeSend (otherOp : PrepareOp ? ): Symbol ? =
454
- select.trySelectOther(otherOp) as Symbol ? // must return symbol
459
+ select.trySelectOther(otherOp, onSelect = block::shareableWillBeUsed ) as Symbol ?
455
460
456
461
override fun completeResumeSend () {
457
- block. startCoroutine(receiver = channel, completion = select.completion)
462
+ startCoroutine(CoroutineStart . ATOMIC , channel, select.completion, block )
458
463
}
459
464
460
465
override fun dispose () { // invoked on select completion
466
+ block.shareableDispose(useIt = false )
461
467
remove()
462
468
}
463
469
@@ -773,7 +779,11 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
773
779
): Boolean {
774
780
val node = ReceiveSelect (this , select, block, receiveMode)
775
781
val result = enqueueReceive(node)
776
- if (result) select.disposeOnSelect(node)
782
+ if (result) {
783
+ select.disposeOnSelect(node)
784
+ } else {
785
+ node.dispose()
786
+ }
777
787
return result
778
788
}
779
789
@@ -871,26 +881,31 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
871
881
}
872
882
873
883
private class ReceiveElement <in E >(
874
- @JvmField val cont : CancellableContinuation <Any ?>,
884
+ cont : CancellableContinuation <Any ?>,
875
885
@JvmField val receiveMode : Int
876
886
) : Receive<E>() {
887
+ private val _cont = atomic<CancellableContinuation <Any ?>? > (cont)
888
+
877
889
fun resumeValue (value : E ): Any? = when (receiveMode) {
878
890
RECEIVE_RESULT -> ValueOrClosed .value(value)
879
891
else -> value
880
892
}
881
893
882
894
@Suppress(" IMPLICIT_CAST_TO_ANY" )
883
895
override fun tryResumeReceive (value : E , otherOp : PrepareOp ? ): Symbol ? {
884
- val token = cont .tryResume(resumeValue(value), otherOp?.desc) ? : return null
896
+ val token = _cont .value? .tryResume(resumeValue(value), otherOp?.desc) ? : return null
885
897
assert { token == = RESUME_TOKEN } // the only other possible result
886
898
// We can call finishPrepare only after successful tryResume, so that only good affected node is saved
887
899
otherOp?.finishPrepare()
888
900
return RESUME_TOKEN
889
901
}
890
902
891
- override fun completeResumeReceive (value : E ) = cont.completeResume(RESUME_TOKEN )
903
+ override fun completeResumeReceive (value : E ) {
904
+ _cont .getAndSet(null )!! .completeResume(RESUME_TOKEN )
905
+ }
892
906
893
907
override fun resumeReceiveClosed (closed : Closed <* >) {
908
+ val cont = _cont .getAndSet(null )!!
894
909
when {
895
910
receiveMode == RECEIVE_NULL_ON_CLOSE && closed.closeCause == null -> cont.resume(null )
896
911
receiveMode == RECEIVE_RESULT -> cont.resume(closed.toResult<Any >())
@@ -902,10 +917,12 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
902
917
903
918
private class ReceiveHasNext <E >(
904
919
@JvmField val iterator : Itr <E >,
905
- @JvmField val cont : CancellableContinuation <Boolean >
920
+ cont : CancellableContinuation <Boolean >
906
921
) : Receive<E>() {
922
+ private val _cont = atomic<CancellableContinuation <Boolean >? > (cont)
923
+
907
924
override fun tryResumeReceive (value : E , otherOp : PrepareOp ? ): Symbol ? {
908
- val token = cont .tryResume(true , otherOp?.desc) ? : return null
925
+ val token = _cont .value? .tryResume(true , otherOp?.desc) ? : return null
909
926
assert { token == = RESUME_TOKEN } // the only other possible result
910
927
// We can call finishPrepare only after successful tryResume, so that only good affected node is saved
911
928
otherOp?.finishPrepare()
@@ -918,10 +935,11 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
918
935
but completeResumeReceive is called once so we set iterator result here.
919
936
*/
920
937
iterator.result = value
921
- cont .completeResume(RESUME_TOKEN )
938
+ _cont .getAndSet( null ) !! .completeResume(RESUME_TOKEN )
922
939
}
923
940
924
941
override fun resumeReceiveClosed (closed : Closed <* >) {
942
+ val cont = _cont .getAndSet(null )!!
925
943
val token = if (closed.closeCause == null ) {
926
944
cont.tryResume(false )
927
945
} else {
@@ -938,31 +956,38 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
938
956
private class ReceiveSelect <R , E >(
939
957
@JvmField val channel : AbstractChannel <E >,
940
958
@JvmField val select : SelectInstance <R >,
941
- @JvmField val block : suspend (Any? ) -> R ,
959
+ block : suspend (Any? ) -> R ,
942
960
@JvmField val receiveMode : Int
943
961
) : Receive<E>(), DisposableHandle {
962
+ @JvmField val block: suspend (Any? ) -> R = block.asShareable() // captured variables in this block need screening
963
+
944
964
override fun tryResumeReceive (value : E , otherOp : PrepareOp ? ): Symbol ? =
945
- select.trySelectOther(otherOp) as Symbol ?
965
+ select.trySelectOther(otherOp, onSelect = block::shareableWillBeUsed ) as Symbol ?
946
966
947
967
@Suppress(" UNCHECKED_CAST" )
948
968
override fun completeResumeReceive (value : E ) {
949
- block. startCoroutine(if (receiveMode == RECEIVE_RESULT ) ValueOrClosed .value(value) else value, select.completion)
969
+ startCoroutine(CoroutineStart . ATOMIC , if (receiveMode == RECEIVE_RESULT ) ValueOrClosed .value(value) else value, select.completion, block )
950
970
}
951
971
952
972
override fun resumeReceiveClosed (closed : Closed <* >) {
953
- if (! select.trySelect()) return
973
+ if (! select.trySelect(onSelect = block::shareableWillBeUsed )) return
954
974
when (receiveMode) {
955
- RECEIVE_THROWS_ON_CLOSE -> select.resumeSelectWithException(closed.receiveException)
956
- RECEIVE_RESULT -> block.startCoroutine(ValueOrClosed .closed<R >(closed.closeCause), select.completion)
975
+ RECEIVE_THROWS_ON_CLOSE -> {
976
+ block.shareableDispose(useIt = true )
977
+ select.resumeSelectWithException(closed.receiveException)
978
+ }
979
+ RECEIVE_RESULT -> startCoroutine(CoroutineStart .ATOMIC , ValueOrClosed .closed<R >(closed.closeCause), select.completion, block)
957
980
RECEIVE_NULL_ON_CLOSE -> if (closed.closeCause == null ) {
958
- block. startCoroutine(null , select.completion)
981
+ startCoroutine(CoroutineStart . ATOMIC , null , select.completion, block )
959
982
} else {
983
+ block.shareableDispose(useIt = true )
960
984
select.resumeSelectWithException(closed.receiveException)
961
985
}
962
986
}
963
987
}
964
988
965
989
override fun dispose () { // invoked on select completion
990
+ block.shareableDispose(useIt = false )
966
991
if (remove())
967
992
channel.onReceiveDequeued() // notify cancellation of receive
968
993
}
@@ -1031,17 +1056,26 @@ internal interface ReceiveOrClosed<in E> {
1031
1056
@Suppress(" UNCHECKED_CAST" )
1032
1057
internal class SendElement (
1033
1058
override val pollResult : Any? ,
1034
- @JvmField val cont : CancellableContinuation <Unit >
1059
+ cont : CancellableContinuation <Unit >
1035
1060
) : Send() {
1061
+ private val _cont = atomic<CancellableContinuation <Unit >? > (cont)
1062
+
1036
1063
override fun tryResumeSend (otherOp : PrepareOp ? ): Symbol ? {
1037
- val token = cont .tryResume(Unit , otherOp?.desc) ? : return null
1064
+ val token = _cont .value? .tryResume(Unit , otherOp?.desc) ? : return null
1038
1065
assert { token == = RESUME_TOKEN } // the only other possible result
1039
1066
// We can call finishPrepare only after successful tryResume, so that only good affected node is saved
1040
1067
otherOp?.finishPrepare() // finish preparations
1041
1068
return RESUME_TOKEN
1042
1069
}
1043
- override fun completeResumeSend () = cont.completeResume(RESUME_TOKEN )
1044
- override fun resumeSendClosed (closed : Closed <* >) = cont.resumeWithException(closed.sendException)
1070
+
1071
+ override fun completeResumeSend () {
1072
+ _cont .getAndSet(null )!! .completeResume(RESUME_TOKEN )
1073
+ }
1074
+
1075
+ override fun resumeSendClosed (closed : Closed <* >) {
1076
+ _cont .getAndSet(null )!! .resumeWithException(closed.sendException)
1077
+ }
1078
+
1045
1079
override fun toString (): String = " SendElement@$hexAddress ($pollResult )"
1046
1080
}
1047
1081
0 commit comments