@@ -338,6 +338,7 @@ private inline fun initDispatcher(
338
338
dispatcher eq DISPATCHER_USE_CUSTOM_PROPERTY_VALUE -> loadCustomBlockingDispatcher(
339
339
Thread .currentThread().contextClassLoader
340
340
)
341
+
341
342
else -> null
342
343
}
343
344
@@ -563,12 +564,14 @@ private var runInNoScopeBlockingStrategy: RunInNoScopeBlockingStrategy = Default
563
564
564
565
@OptIn(ExperimentalSimbotAPI ::class )
565
566
private object DefaultRunInNoScopeBlockingStrategy : RunInNoScopeBlockingStrategy {
567
+ @kotlin.jvm.Throws (Exception ::class )
566
568
override fun <T > invoke (context : CoroutineContext , block : suspend () -> T ): T {
567
569
val runner = SuspendRunner <T >(context)
568
570
block.startCoroutine(runner)
569
571
return runner.await(SuspendRunner .isWaitTimeoutEnabled)
570
572
}
571
573
574
+ @kotlin.jvm.Throws (Exception ::class )
572
575
fun <T > invokeWithoutTimeoutLog (context : CoroutineContext , block : suspend () -> T ): T {
573
576
val runner = SuspendRunner <T >(context)
574
577
block.startCoroutine(runner)
@@ -595,31 +598,31 @@ public fun setRunInNoScopeBlockingStrategy(strategy: RunInNoScopeBlockingStrateg
595
598
*
596
599
* 在默认未提供上下文的情况下,[runInBlocking] 所使用的 [context] 为 [DefaultBlockingContext].
597
600
*
598
- * @throws RunInBlockingException [block] 中产生的所有异常(除了 [TimeoutCancellationException])均会被包装在 [RunInBlockingException] 的 `cause` 中被抛出。
601
+ * @throws Exception 原函数可能被抛出的任何异常
602
+ * @throws RunInBlockingException 当出现执行 [block] 过程中由于 future 或线程中断等非 [block] 本身产生的异常时被包装为 [RunInBlockingException]
599
603
*
600
604
* @see DefaultBlockingContext
601
605
* @see runBlocking
602
606
*/
603
607
@OptIn(ExperimentalSimbotAPI ::class , InternalSimbotAPI ::class )
604
- @Throws(RunInBlockingException ::class )
608
+ @Throws(Exception ::class )
605
609
public fun <T > runInBlocking (
606
610
context : CoroutineContext = DefaultBlockingContext ,
607
611
block : suspend CoroutineScope .() -> T ,
608
- ): T = runCatching {
609
- runInBlockingStrategy(context, block)
610
- }.getOrElse { throw `$RunInBlockingException $`(it) }
612
+ ): T = runInBlockingStrategy(context, block)
611
613
612
614
/* *
613
615
* 如果超时,则抛出 [TimeoutCancellationException].
614
616
*
615
617
* @throws TimeoutCancellationException 如果超时
616
- * @throws RunInBlockingException [block] 中产生的所有异常(除了 [TimeoutCancellationException])均会被包装在 [RunInBlockingException] 的 `cause` 中被抛出。
618
+ * @throws Exception 原函数可能被抛出的任何异常
619
+ * @throws RunInBlockingException 当出现执行 [block] 过程中由于 future 或线程中断等非 [block] 本身产生的异常时被包装为 [RunInBlockingException]
617
620
*
618
621
* @see runInBlocking
619
622
* @see withTimeout
620
623
*/
621
624
@OptIn(ExperimentalSimbotAPI ::class , InternalSimbotAPI ::class )
622
- @Throws(RunInBlockingException ::class )
625
+ @Throws(Exception ::class )
623
626
public fun <T > runInTimeoutBlocking (
624
627
timeout : Long ,
625
628
context : CoroutineContext = DefaultBlockingContext ,
@@ -640,46 +643,41 @@ public fun <T> runInTimeoutBlocking(
640
643
*
641
644
* 在默认未提供上下文的情况下,[runInBlocking] 所使用的 [context] 为 [DefaultBlockingContext].
642
645
*
643
- * @throws RunInBlockingException [block] 中产生的所有异常均会被包装在 [RunInBlockingException] 的 `cause` 中被抛出。
644
- *
646
+ * @throws Exception 原函数可能被抛出的任何异常
647
+ * @throws RunInBlockingException 当出现执行 [block] 过程中由于 future 或线程中断等非 [block] 本身产生的异常时被包装为 [RunInBlockingException]
645
648
* @see DefaultBlockingContext
646
649
* @see runBlocking
647
650
*/
648
651
@OptIn(ExperimentalSimbotAPI ::class , InternalSimbotAPI ::class )
649
- @Throws(RunInBlockingException ::class )
652
+ @Throws(Exception ::class )
650
653
public fun <T > runInNoScopeBlocking (
651
654
context : CoroutineContext = DefaultBlockingContext ,
652
655
block : suspend () -> T ,
653
- ): T = runCatching {
654
- runInNoScopeBlockingStrategy(context, block)
655
- }.getOrElse { throw `$RunInBlockingException $`(it) }
656
+ ): T = runInNoScopeBlockingStrategy(context, block)
656
657
657
658
/* *
658
659
* @suppress 内部API
659
660
*
660
- * @throws RunInBlockingException [block] 中产生的所有异常均会被包装在 [RunInBlockingException] 的 `cause` 中被抛出。
661
+ * @throws Exception 原函数可能被抛出的任何异常
662
+ * @throws RunInBlockingException 当出现执行 [block] 过程中由于 future 或线程中断等非 [block] 本身产生的异常时被包装为 [RunInBlockingException]
661
663
*
662
664
* @see runInNoScopeBlocking
663
665
* @see DefaultBlockingContext
664
666
* @see runBlocking
665
667
*/
666
668
@OptIn(ExperimentalSimbotAPI ::class )
667
- @Throws(RunInBlockingException ::class )
669
+ @Throws(Exception ::class )
668
670
@InternalSimbotAPI
669
671
public fun <T > runInNoScopeBlockingWithoutTimeoutDebug (
670
672
context : CoroutineContext = DefaultBlockingContext ,
671
673
block : suspend () -> T ,
672
674
): T {
673
- try {
674
- val strategy = runInNoScopeBlockingStrategy
675
- if (strategy is DefaultRunInNoScopeBlockingStrategy ) {
676
- return DefaultRunInNoScopeBlockingStrategy .invokeWithoutTimeoutLog(context, block)
677
- }
678
-
679
- return strategy(context, block)
680
- } catch (e: Throwable ) {
681
- throw `$RunInBlockingException $`(e)
675
+ val strategy = runInNoScopeBlockingStrategy
676
+ if (strategy is DefaultRunInNoScopeBlockingStrategy ) {
677
+ return DefaultRunInNoScopeBlockingStrategy .invokeWithoutTimeoutLog(context, block)
682
678
}
679
+
680
+ return strategy(context, block)
683
681
}
684
682
685
683
/* *
@@ -746,7 +744,7 @@ public fun <T> `$$asReserve`(scope: CoroutineScope? = null, block: suspend () ->
746
744
747
745
@InternalSimbotAPI
748
746
@Deprecated(" Just used by compiler" , level = DeprecationLevel .HIDDEN )
749
- @Throws(RunInBlockingException ::class )
747
+ @Throws(Exception ::class )
750
748
public fun <T > `$$runInBlocking` (block : suspend () -> T ): T = runInNoScopeBlocking(block = block)
751
749
752
750
@@ -784,38 +782,51 @@ public fun <T> `$$runInAsyncNullable`(block: suspend () -> T, scope: CoroutineSc
784
782
785
783
/* *
786
784
* 使用在 `runBlocking` 或相关函数中,用于将运行其中的函数所抛出的函数捕获并包装。
787
- * 内容函数抛出的真正异常在 [cause] 中。
785
+ *
786
+ * [RunInBlockingException] 只会包装那些由 future 或者线程中断导致的异常,
787
+ * 实际执行的blocking函数所抛出的异常会被原样抛出。
788
+ *
789
+ * 通常来讲,[cause] 可能是:
790
+ * - [CancellationException]
791
+ * - [ExecutionException] (概率很低)
792
+ * - [InterruptedException]
788
793
*/
789
794
public sealed class RunInBlockingException protected constructor(cause : Throwable ) : RuntimeException(cause)
790
795
791
-
792
796
@Suppress(" unused" , " ClassName" )
793
797
private class `$RunInBlockingException $`(cause: Throwable ) : RunInBlockingException (cause)
794
798
799
+ private fun throwRunInBlockingException (cause : Throwable ): Nothing =
800
+ throw `$RunInBlockingException $`(cause)
801
+
795
802
// Yes. I am the BlockingRunner.
796
803
private class SuspendRunner <T >(override val context : CoroutineContext = EmptyCoroutineContext ) : Continuation<T> {
797
804
@Suppress(" unused" )
798
805
@Volatile
799
- var s: Int = 0
806
+ var s: Int = SIGNAL_NONE
800
807
// 1 = resume - success
801
808
// 2 = resume - exception
802
809
// 3 = suspend
803
810
811
+ @Volatile
812
+ var value: Any? = null
804
813
// 1 -> value
805
814
// 2 -> ex
806
815
// 3 -> CompletableFuture<T>
807
- @Volatile
808
- var value: Any? = null
809
816
810
817
private object NULL
811
818
812
819
override fun resumeWith (result : Result <T >) {
820
+ // 先变更信号
813
821
val resumed =
814
822
signalUpdater.compareAndSet(
815
823
this ,
816
824
SIGNAL_NONE ,
817
825
if (result.isSuccess) SIGNAL_RESUME_SUCCESS else SIGNAL_RESUME_FAILED
818
826
)
827
+
828
+ // 信号变更失败,说明现在信号是 SUSPEND
829
+ // 那么 value 就已经有一个 future 值了,或者它应该被初始化为一个 future
819
830
if (! resumed) {
820
831
// value is a Future.
821
832
@Suppress(" UNCHECKED_CAST" )
@@ -839,12 +850,14 @@ private class SuspendRunner<T>(override val context: CoroutineContext = EmptyCor
839
850
}
840
851
841
852
/* *
853
+ * @param isWaitTimeoutEnabled 是否输出长时间阻塞警告
854
+ *
842
855
* @see CompletableFuture.join
843
856
* @see CompletableFuture.get
844
857
* @throws CancellationException cancellation
845
858
* @throws CompletionException completion
846
- * @throws ExecutionException if [ExecutionException.cause] is null
847
- * @throws Exception [ExecutionException.cause]
859
+ * @throws InterruptedException
860
+ * @throws RunInBlockingException
848
861
*/
849
862
@Suppress(" UNCHECKED_CAST" , " ReturnCount" , " ThrowsCount" )
850
863
@Throws(Exception ::class )
@@ -875,29 +888,36 @@ private class SuspendRunner<T>(override val context: CoroutineContext = EmptyCor
875
888
throw value as Throwable
876
889
}
877
890
891
+ // 不需要检测长时间等待的日志,
892
+ // 或者不需要在virtual时输出日志,且当前是virtual thread
878
893
if (! isWaitTimeoutEnabled || (! logIfVirtual && Thread .currentThread().isVirtualThread())) {
879
894
try {
880
895
return future.get()
881
896
} catch (cancellation: CancellationException ) {
882
- throw cancellation
897
+ throwRunInBlockingException( cancellation)
883
898
} catch (execution: ExecutionException ) {
884
- throw execution.cause ? : execution
899
+ // 一般来讲 ExecutionException.cause 不会是 null
900
+ throw execution.cause ? : throwRunInBlockingException(execution)
885
901
}
886
- // catch (other: Throwable) {
887
- // throw other // CompletionException(other)
888
- // }
902
+ // InterruptedException 直接向外传递
889
903
}
890
904
905
+ // 需要输出长时间等待日志
906
+
891
907
var times = 0
892
- while (! future.isDone && ! Thread .currentThread().isInterrupted) {
908
+ while (! future.isDone) {
909
+ if (Thread .interrupted()) {
910
+ throw InterruptedException ()
911
+ }
912
+
893
913
if (times > 0 ) {
894
914
val duration = (waitTimeout * times).milliseconds
895
915
if (logger.isDebugEnabled) {
896
916
val durationString = duration.toString()
897
917
logger.warn(" Blocking runner has been blocking for at least {}." , durationString)
898
- val e: Throwable = LongTimeBlockingException (durationString)
918
+ val e: Throwable = ProlongedBlockingException (durationString)
899
919
logger.debug(
900
- " Long time blocking duration at least {}" ,
920
+ " Prolonged blocking duration at least {}" ,
901
921
durationString,
902
922
e
903
923
)
@@ -916,21 +936,24 @@ private class SuspendRunner<T>(override val context: CoroutineContext = EmptyCor
916
936
} catch (ignore: TimeoutException ) {
917
937
times + = 1
918
938
} catch (cancellation: CancellationException ) {
919
- throw cancellation
939
+ throwRunInBlockingException( cancellation)
920
940
} catch (execution: ExecutionException ) {
921
- throw execution.cause ? : execution
941
+ throw execution.cause ? : throwRunInBlockingException( execution)
922
942
}
923
- // catch (other: Throwable) {
924
- // throw other // CompletionException(other)
925
- // }
926
943
}
927
944
928
- // done.
929
- return future.join()
945
+ // Is done, but not in the future.get(timeout)
946
+ try {
947
+ return future.join()
948
+ } catch (cancellation: CancellationException ) {
949
+ throwRunInBlockingException(cancellation)
950
+ } catch (execution: CompletionException ) {
951
+ throwRunInBlockingException(execution)
952
+ }
930
953
}
931
954
932
- // for displaying the stack only
933
- private class LongTimeBlockingException (message : String ) : RuntimeException(message)
955
+ // Used only to show the stack
956
+ private class ProlongedBlockingException (message : String ) : RuntimeException(message)
934
957
935
958
companion object {
936
959
private const val SIGNAL_NONE = 0
0 commit comments