@@ -448,16 +448,18 @@ internal abstract class AbstractSendChannel<E> : SendChannel<E> {
448
448
override val pollResult : Any? ,
449
449
@JvmField val channel : AbstractSendChannel <E >,
450
450
@JvmField val select : SelectInstance <R >,
451
- @JvmField val block : suspend (SendChannel <E >) -> R
451
+ block : suspend (SendChannel <E >) -> R
452
452
) : Send(), DisposableHandle {
453
+ @JvmField val block: suspend (SendChannel <E >) -> R = block.asShareable()
454
+
453
455
override fun tryResumeSend (otherOp : PrepareOp ? ): Symbol ? =
454
- select.trySelectOther(otherOp) as Symbol ? // must return symbol
456
+ select.trySelectOther(otherOp, onSelect = block::shareableWillBeUsed ) as Symbol ? // must return symbol
455
457
456
- override fun completeResumeSend () {
457
- block.startCoroutine(receiver = channel, completion = select.completion)
458
- }
458
+ override fun completeResumeSend () =
459
+ startCoroutine(CoroutineStart .ATOMIC , channel, select.completion, block)
459
460
460
461
override fun dispose () { // invoked on select completion
462
+ block.shareableDispose(useIt = false )
461
463
remove()
462
464
}
463
465
@@ -871,41 +873,53 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
871
873
}
872
874
873
875
private class ReceiveElement <in E >(
874
- @JvmField val cont : CancellableContinuation <Any ?>,
876
+ cont : CancellableContinuation <Any ?>,
875
877
@JvmField val receiveMode : Int
876
878
) : Receive<E>() {
879
+ private val _cont = atomic<CancellableContinuation <Any ?>? > (cont)
880
+ private fun useCont () = _cont .getAndSet(null )
881
+
877
882
fun resumeValue (value : E ): Any? = when (receiveMode) {
878
883
RECEIVE_RESULT -> ValueOrClosed .value(value)
879
884
else -> value
880
885
}
881
886
882
887
@Suppress(" IMPLICIT_CAST_TO_ANY" )
883
888
override fun tryResumeReceive (value : E , otherOp : PrepareOp ? ): Symbol ? {
884
- val token = cont.tryResume(resumeValue(value), otherOp?.desc) ? : return null
889
+ val token = _cont .value?.tryResume(resumeValue(value), otherOp?.desc) ? : run {
890
+ _cont .value = null
891
+ return null
892
+ }
885
893
assert { token == = RESUME_TOKEN } // the only other possible result
886
894
// We can call finishPrepare only after successful tryResume, so that only good affected node is saved
887
895
otherOp?.finishPrepare()
888
896
return RESUME_TOKEN
889
897
}
890
898
891
- override fun completeResumeReceive (value : E ) = cont .completeResume(RESUME_TOKEN )
899
+ override fun completeResumeReceive (value : E ) { useCont()? .completeResume(RESUME_TOKEN ) }
892
900
893
901
override fun resumeReceiveClosed (closed : Closed <* >) {
894
902
when {
895
- receiveMode == RECEIVE_NULL_ON_CLOSE && closed.closeCause == null -> cont .resume(null )
896
- receiveMode == RECEIVE_RESULT -> cont .resume(closed.toResult<Any >())
897
- else -> cont .resumeWithException(closed.receiveException)
903
+ receiveMode == RECEIVE_NULL_ON_CLOSE && closed.closeCause == null -> useCont()? .resume(null )
904
+ receiveMode == RECEIVE_RESULT -> useCont()? .resume(closed.toResult<Any >())
905
+ else -> useCont()? .resumeWithException(closed.receiveException)
898
906
}
899
907
}
900
908
override fun toString (): String = " ReceiveElement@$hexAddress [receiveMode=$receiveMode ]"
901
909
}
902
910
903
911
private class ReceiveHasNext <E >(
904
912
@JvmField val iterator : Itr <E >,
905
- @JvmField val cont : CancellableContinuation <Boolean >
913
+ cont : CancellableContinuation <Boolean >
906
914
) : Receive<E>() {
915
+ private val _cont = atomic<CancellableContinuation <Boolean >? > (cont)
916
+ private fun useCont () = _cont .getAndSet(null )
917
+
907
918
override fun tryResumeReceive (value : E , otherOp : PrepareOp ? ): Symbol ? {
908
- val token = cont.tryResume(true , otherOp?.desc) ? : return null
919
+ val token = _cont .value?.tryResume(true , otherOp?.desc) ? : run {
920
+ _cont .value = null
921
+ return null
922
+ }
909
923
assert { token == = RESUME_TOKEN } // the only other possible result
910
924
// We can call finishPrepare only after successful tryResume, so that only good affected node is saved
911
925
otherOp?.finishPrepare()
@@ -918,51 +932,61 @@ internal abstract class AbstractChannel<E> : AbstractSendChannel<E>(), Channel<E
918
932
but completeResumeReceive is called once so we set iterator result here.
919
933
*/
920
934
iterator.result = value
921
- cont .completeResume(RESUME_TOKEN )
935
+ useCont()? .completeResume(RESUME_TOKEN )
922
936
}
923
937
924
938
override fun resumeReceiveClosed (closed : Closed <* >) {
925
939
val token = if (closed.closeCause == null ) {
926
- cont .tryResume(false )
940
+ _cont .value? .tryResume(false )
927
941
} else {
928
- cont.tryResumeWithException(recoverStackTrace(closed.receiveException, cont))
942
+ _cont .value?.let { cont ->
943
+ cont.tryResumeWithException(recoverStackTrace(closed.receiveException, cont))
944
+ }
929
945
}
930
946
if (token != null ) {
931
947
iterator.result = closed
932
- cont .completeResume(token)
948
+ _cont .value? .completeResume(token)
933
949
}
950
+ _cont .value = null
934
951
}
935
952
override fun toString (): String = " ReceiveHasNext@$hexAddress "
936
953
}
937
954
938
955
private class ReceiveSelect <R , E >(
939
956
@JvmField val channel : AbstractChannel <E >,
940
957
@JvmField val select : SelectInstance <R >,
941
- @JvmField val block : suspend (Any? ) -> R ,
958
+ block : suspend (Any? ) -> R ,
942
959
@JvmField val receiveMode : Int
943
960
) : Receive<E>(), DisposableHandle {
961
+ @JvmField val block: suspend (Any? ) -> R = block.asShareable() // captured variables in this block need screening
962
+
944
963
override fun tryResumeReceive (value : E , otherOp : PrepareOp ? ): Symbol ? =
945
- select.trySelectOther(otherOp) as Symbol ?
964
+ select.trySelectOther(otherOp, onSelect = block::shareableWillBeUsed ) as Symbol ?
946
965
947
966
@Suppress(" UNCHECKED_CAST" )
948
967
override fun completeResumeReceive (value : E ) {
949
- block. startCoroutine(if (receiveMode == RECEIVE_RESULT ) ValueOrClosed .value(value) else value, select.completion)
968
+ startCoroutine(CoroutineStart . ATOMIC , if (receiveMode == RECEIVE_RESULT ) ValueOrClosed .value(value) else value, select.completion, block )
950
969
}
951
970
952
971
override fun resumeReceiveClosed (closed : Closed <* >) {
953
- if (! select.trySelect()) return
972
+ if (! select.trySelect(onSelect = block::shareableWillBeUsed )) return
954
973
when (receiveMode) {
955
- RECEIVE_THROWS_ON_CLOSE -> select.resumeSelectWithException(closed.receiveException)
956
- RECEIVE_RESULT -> block.startCoroutine(ValueOrClosed .closed<R >(closed.closeCause), select.completion)
974
+ RECEIVE_THROWS_ON_CLOSE -> {
975
+ block.shareableDispose(useIt = true )
976
+ select.resumeSelectWithException(closed.receiveException)
977
+ }
978
+ RECEIVE_RESULT -> startCoroutine(CoroutineStart .ATOMIC , ValueOrClosed .closed<R >(closed.closeCause), select.completion, block)
957
979
RECEIVE_NULL_ON_CLOSE -> if (closed.closeCause == null ) {
958
- block. startCoroutine(null , select.completion)
980
+ startCoroutine(CoroutineStart . ATOMIC , null , select.completion, block )
959
981
} else {
982
+ block.shareableDispose(useIt = true )
960
983
select.resumeSelectWithException(closed.receiveException)
961
984
}
962
985
}
963
986
}
964
987
965
988
override fun dispose () { // invoked on select completion
989
+ block.shareableDispose(useIt = false )
966
990
if (remove())
967
991
channel.onReceiveDequeued() // notify cancellation of receive
968
992
}
@@ -1031,17 +1055,23 @@ internal interface ReceiveOrClosed<in E> {
1031
1055
@Suppress(" UNCHECKED_CAST" )
1032
1056
internal class SendElement (
1033
1057
override val pollResult : Any? ,
1034
- @JvmField val cont : CancellableContinuation <Unit >
1058
+ cont : CancellableContinuation <Unit >
1035
1059
) : Send() {
1060
+ private val _cont = atomic<CancellableContinuation <Unit >? > (cont)
1061
+ private fun useCont () = _cont .getAndSet(null )
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) ? : run {
1065
+ _cont .value = null
1066
+ return null
1067
+ }
1038
1068
assert { token == = RESUME_TOKEN } // the only other possible result
1039
1069
// We can call finishPrepare only after successful tryResume, so that only good affected node is saved
1040
1070
otherOp?.finishPrepare() // finish preparations
1041
1071
return RESUME_TOKEN
1042
1072
}
1043
- override fun completeResumeSend () = cont .completeResume(RESUME_TOKEN )
1044
- override fun resumeSendClosed (closed : Closed <* >) = cont .resumeWithException(closed.sendException)
1073
+ override fun completeResumeSend () { useCont()? .completeResume(RESUME_TOKEN ) }
1074
+ override fun resumeSendClosed (closed : Closed <* >) { useCont()? .resumeWithException(closed.sendException) }
1045
1075
override fun toString (): String = " SendElement@$hexAddress ($pollResult )"
1046
1076
}
1047
1077
0 commit comments