[K/N] Refactor unhandled exception handling API
* Do not reset unhandled exception hook * Add processUnhandledException to perform default unhandled exception processing * Add terminateWithUnhandledException to report the unhandled exception and terminate the program * Use the default unhandled exception processing in entrypoint, interop boundaries and in Worker.executeAfter * Add -Xworker-exception-handling to control exception processing of Worker.executeAfter. By default its the old behaviour with the old MM, and new behaviour with the new MM.
This commit is contained in:
committed by
Space
parent
766857881a
commit
7e04bb4bf1
@@ -329,6 +329,15 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
||||
}
|
||||
})
|
||||
put(PROPERTY_LAZY_INITIALIZATION, arguments.propertyLazyInitialization)
|
||||
put(WORKER_EXCEPTION_HANDLING, when (arguments.workerExceptionHandling) {
|
||||
null -> if (memoryModel == MemoryModel.EXPERIMENTAL) WorkerExceptionHandling.USE_HOOK else WorkerExceptionHandling.LEGACY
|
||||
"legacy" -> WorkerExceptionHandling.LEGACY
|
||||
"use-hook" -> WorkerExceptionHandling.USE_HOOK
|
||||
else -> {
|
||||
configuration.report(ERROR, "Unsupported worker exception handling mode ${arguments.workerExceptionHandling}")
|
||||
WorkerExceptionHandling.LEGACY
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -320,6 +320,14 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
||||
@Argument(value="-Xruntime-asserts-mode", valueDescription = "<mode>", description = "Enable asserts in runtime. Possible values: 'ignore', 'log', 'panic'")
|
||||
var runtimeAssertsMode: String? = "ignore"
|
||||
|
||||
// TODO: Remove when legacy MM is gone.
|
||||
@Argument(
|
||||
value = "-Xworker-exception-handling",
|
||||
valueDescription = "<mode>",
|
||||
description = "Unhandled exception processing in Worker.executeAfter. Possible values: 'legacy', 'use-hook'. The default value is 'legacy', for -memory-model experimental the default value is 'use-hook'"
|
||||
)
|
||||
var workerExceptionHandling: String? = null
|
||||
|
||||
override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> =
|
||||
super.configureAnalysisFlags(collector, languageVersion).also {
|
||||
val useExperimental = it[AnalysisFlags.useExperimental] as List<*>
|
||||
|
||||
+3
-2
@@ -465,7 +465,7 @@ private class ExportedElement(val kind: ElementKind,
|
||||
"result", cfunction[0], Direction.KOTLIN_TO_C, builder)
|
||||
builder.append(" return $result;\n")
|
||||
}
|
||||
builder.append(" } catch (ExceptionObjHolder& e) { TerminateWithUnhandledException(e.GetExceptionObject()); } \n")
|
||||
builder.append(" } catch (ExceptionObjHolder& e) { std::terminate(); } \n")
|
||||
|
||||
builder.append("}\n")
|
||||
|
||||
@@ -902,6 +902,8 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
|
||||
// Include header into C++ source.
|
||||
headerFile.forEachLine { it -> output(it) }
|
||||
|
||||
output("#include <exception>")
|
||||
|
||||
output("""
|
||||
|struct KObjHeader;
|
||||
|typedef struct KObjHeader KObjHeader;
|
||||
@@ -924,7 +926,6 @@ internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVi
|
||||
|void Kotlin_initRuntimeIfNeeded();
|
||||
|void Kotlin_mm_switchThreadStateRunnable() RUNTIME_NOTHROW;
|
||||
|void Kotlin_mm_switchThreadStateNative() RUNTIME_NOTHROW;
|
||||
|void TerminateWithUnhandledException(KObjHeader*) RUNTIME_NORETURN;
|
||||
|
|
||||
|KObjHeader* CreateStringFromCString(const char*, KObjHeader**);
|
||||
|char* CreateCStringFromString(const KObjHeader*);
|
||||
|
||||
+4
-2
@@ -79,10 +79,12 @@ internal fun makeEntryPoint(context: Context): IrFunction {
|
||||
}
|
||||
catches += irCatch(context.irBuiltIns.throwableType).apply {
|
||||
result = irBlock {
|
||||
+irCall(context.ir.symbols.onUnhandledException).apply {
|
||||
+irCall(context.ir.symbols.processUnhandledException).apply {
|
||||
putValueArgument(0, irGet(catchParameter))
|
||||
}
|
||||
+irCall(context.ir.symbols.terminateWithUnhandledException).apply {
|
||||
putValueArgument(0, irGet(catchParameter))
|
||||
}
|
||||
+irReturn(irInt(1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -50,6 +50,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
val gc: GC get() = configuration.get(KonanConfigKeys.GARBAGE_COLLECTOR)!!
|
||||
val gcAggressive: Boolean get() = configuration.get(KonanConfigKeys.GARBAGE_COLLECTOR_AGRESSIVE)!!
|
||||
val runtimeAssertsMode: RuntimeAssertsMode get() = configuration.get(KonanConfigKeys.RUNTIME_ASSERTS_MODE)!!
|
||||
val workerExceptionHandling: WorkerExceptionHandling get() = configuration.get(KonanConfigKeys.WORKER_EXCEPTION_HANDLING)!!
|
||||
|
||||
val needVerifyIr: Boolean
|
||||
get() = configuration.get(KonanConfigKeys.VERIFY_IR) == true
|
||||
|
||||
+1
@@ -164,6 +164,7 @@ class KonanConfigKeys {
|
||||
val RUNTIME_ASSERTS_MODE: CompilerConfigurationKey<RuntimeAssertsMode> = CompilerConfigurationKey.create("enable runtime asserts")
|
||||
val PROPERTY_LAZY_INITIALIZATION: CompilerConfigurationKey<Boolean>
|
||||
= CompilerConfigurationKey.create("lazy top level properties initialization")
|
||||
val WORKER_EXCEPTION_HANDLING: CompilerConfigurationKey<WorkerExceptionHandling> = CompilerConfigurationKey.create("unhandled exception processing in Worker.executeAfter")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
// Must match `WorkerExceptionHandling` in CompilerConstants.hpp
|
||||
enum class WorkerExceptionHandling(val value: Int) {
|
||||
LEGACY(0),
|
||||
USE_HOOK(1),
|
||||
}
|
||||
+2
-1
@@ -117,7 +117,8 @@ internal class KonanSymbols(
|
||||
|
||||
val objCMethodImp = symbolTable.referenceClass(context.interopBuiltIns.objCMethodImp)
|
||||
|
||||
val onUnhandledException = internalFunction("OnUnhandledException")
|
||||
val processUnhandledException = irBuiltIns.findFunctions(Name.identifier("processUnhandledException"), "kotlin", "native").single()
|
||||
val terminateWithUnhandledException = irBuiltIns.findFunctions(Name.identifier("terminateWithUnhandledException"), "kotlin", "native").single()
|
||||
|
||||
val interopNativePointedGetRawPointer =
|
||||
symbolTable.referenceSimpleFunction(context.interopBuiltIns.nativePointedGetRawPointer)
|
||||
|
||||
+1
@@ -2631,6 +2631,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
overrideRuntimeGlobal("Kotlin_destroyRuntimeMode", Int32(context.config.destroyRuntimeMode.value))
|
||||
overrideRuntimeGlobal("Kotlin_gcAggressive", Int32(if (context.config.gcAggressive) 1 else 0))
|
||||
overrideRuntimeGlobal("Kotlin_workerExceptionHandling", Int32(context.config.workerExceptionHandling.value))
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
@@ -1008,6 +1008,98 @@ task worker_exception_messages(type: KonanLocalTest) {
|
||||
source = "runtime/workers/worker_exception_messages.kt"
|
||||
}
|
||||
|
||||
standaloneTest("worker_exceptions") {
|
||||
flags = ["-tr", "-Xworker-exception-handling=use-hook"]
|
||||
enabled = (project.testTarget != 'wasm32') // Workers need pthreads.
|
||||
outputChecker = {
|
||||
!it.contains("testExecuteAfterStartQuiet error") && it.contains("testExecuteStart error") && !it.contains("testExecuteStartQuiet error")
|
||||
}
|
||||
source = "runtime/workers/worker_exceptions.kt"
|
||||
}
|
||||
|
||||
standaloneTest("worker_exceptions_legacy") {
|
||||
flags = ["-tr", "-Xworker-exception-handling=legacy"]
|
||||
enabled = (project.testTarget != 'wasm32') // Workers need pthreads.
|
||||
outputChecker = {
|
||||
it.contains("testExecuteAfterStartLegacy error") && it.contains("testExecuteStartLegacy error")
|
||||
}
|
||||
source = "runtime/workers/worker_exceptions_legacy.kt"
|
||||
}
|
||||
|
||||
standaloneTest("worker_exceptions_terminate") {
|
||||
flags = ["-Xworker-exception-handling=use-hook"]
|
||||
enabled = (project.testTarget != 'wasm32') // Workers need pthreads.
|
||||
expectedExitStatusChecker = { it != 0 }
|
||||
outputChecker = {
|
||||
it.contains("some error") && !it.contains("Will not happen")
|
||||
}
|
||||
source = "runtime/workers/worker_exceptions_terminate.kt"
|
||||
}
|
||||
|
||||
standaloneTest("worker_exceptions_terminate_legacy") {
|
||||
flags = ["-Xworker-exception-handling=legacy"]
|
||||
enabled = (project.testTarget != 'wasm32') // Workers need pthreads.
|
||||
outputChecker = {
|
||||
it.contains("some error") && it.contains("Will not happen")
|
||||
}
|
||||
source = "runtime/workers/worker_exceptions_terminate.kt"
|
||||
}
|
||||
|
||||
standaloneTest("worker_exceptions_terminate_hook") {
|
||||
flags = ["-Xworker-exception-handling=use-hook"]
|
||||
enabled = (project.testTarget != 'wasm32') // Workers need pthreads.
|
||||
outputChecker = {
|
||||
it.contains("hook called") && !it.contains("some error") && it.contains("Will happen")
|
||||
}
|
||||
source = "runtime/workers/worker_exceptions_terminate_hook.kt"
|
||||
}
|
||||
|
||||
standaloneTest("worker_exceptions_terminate_hook_legacy") {
|
||||
flags = ["-Xworker-exception-handling=legacy"]
|
||||
enabled = (project.testTarget != 'wasm32') // Workers need pthreads.
|
||||
outputChecker = {
|
||||
!it.contains("hook called") && it.contains("some error") && it.contains("Will happen")
|
||||
}
|
||||
source = "runtime/workers/worker_exceptions_terminate_hook.kt"
|
||||
}
|
||||
|
||||
standaloneTest("worker_exceptions_terminate_current") {
|
||||
flags = ["-Xworker-exception-handling=use-hook"]
|
||||
enabled = (project.testTarget != 'wasm32') // Workers need pthreads.
|
||||
expectedExitStatusChecker = { it != 0 }
|
||||
outputChecker = {
|
||||
it.contains("some error") && !it.contains("Will not happen")
|
||||
}
|
||||
source = "runtime/workers/worker_exceptions_terminate_current.kt"
|
||||
}
|
||||
|
||||
standaloneTest("worker_exceptions_terminate_current_legacy") {
|
||||
flags = ["-Xworker-exception-handling=legacy"]
|
||||
enabled = (project.testTarget != 'wasm32') // Workers need pthreads.
|
||||
outputChecker = {
|
||||
it.contains("some error") && it.contains("Will not happen")
|
||||
}
|
||||
source = "runtime/workers/worker_exceptions_terminate_current.kt"
|
||||
}
|
||||
|
||||
standaloneTest("worker_exceptions_terminate_hook_current") {
|
||||
flags = ["-Xworker-exception-handling=use-hook"]
|
||||
enabled = (project.testTarget != 'wasm32') // Workers need pthreads.
|
||||
outputChecker = {
|
||||
it.contains("hook called") && !it.contains("some error") && it.contains("Will happen")
|
||||
}
|
||||
source = "runtime/workers/worker_exceptions_terminate_hook_current.kt"
|
||||
}
|
||||
|
||||
standaloneTest("worker_exceptions_terminate_hook_current_legacy") {
|
||||
flags = ["-Xworker-exception-handling=legacy"]
|
||||
enabled = (project.testTarget != 'wasm32') // Workers need pthreads.
|
||||
outputChecker = {
|
||||
!it.contains("hook called") && it.contains("some error") && it.contains("Will happen")
|
||||
}
|
||||
source = "runtime/workers/worker_exceptions_terminate_hook_current.kt"
|
||||
}
|
||||
|
||||
standaloneTest("worker_threadlocal_no_leak") {
|
||||
disabled = (project.testTarget == 'wasm32') // Needs pthreads.
|
||||
source = "runtime/workers/worker_threadlocal_no_leak.kt"
|
||||
@@ -2548,11 +2640,68 @@ standaloneTest("kt-37572") {
|
||||
|
||||
standaloneTest("custom_hook") {
|
||||
enabled = (project.testTarget != 'wasm32') // Uses exceptions.
|
||||
goldValue = "value 42: Error\n"
|
||||
expectedExitStatus = 1
|
||||
outputChecker = {
|
||||
it.contains("value 42: Error") && it.contains("Uncaught Kotlin exception: kotlin.Error: an error")
|
||||
}
|
||||
expectedExitStatusChecker = { it != 0 }
|
||||
source = "runtime/exceptions/custom_hook.kt"
|
||||
}
|
||||
|
||||
standaloneTest("custom_hook_memory_leak") {
|
||||
enabled = (project.testTarget != 'wasm32') // Uses exceptions.
|
||||
outputChecker = {
|
||||
it.contains("Hook 42") && it.contains("Uncaught Kotlin exception: kotlin.Error: an error")
|
||||
}
|
||||
expectedExitStatusChecker = { it != 0 }
|
||||
source = "runtime/exceptions/custom_hook_memory_leak.kt"
|
||||
}
|
||||
|
||||
standaloneTest("custom_hook_get") {
|
||||
source = "runtime/exceptions/custom_hook_get.kt"
|
||||
}
|
||||
|
||||
standaloneTest("custom_hook_no_reset") {
|
||||
enabled = (project.testTarget != 'wasm32') // Uses exceptions.
|
||||
outputChecker = {
|
||||
it.contains("Hook called") && it.contains("Uncaught Kotlin exception: kotlin.Error: some error")
|
||||
}
|
||||
expectedExitStatusChecker = { it != 0 }
|
||||
source = "runtime/exceptions/custom_hook_no_reset.kt"
|
||||
}
|
||||
|
||||
standaloneTest("custom_hook_throws") {
|
||||
enabled = (project.testTarget != 'wasm32') // Uses exceptions.
|
||||
outputChecker = {
|
||||
it.contains("Hook called") && it.contains("Uncaught Kotlin exception: kotlin.Error: another error") && !it.contains("some error")
|
||||
}
|
||||
expectedExitStatusChecker = { it != 0 }
|
||||
source = "runtime/exceptions/custom_hook_throws.kt"
|
||||
}
|
||||
|
||||
standaloneTest("custom_hook_unhandled_exception") {
|
||||
enabled = (project.testTarget != 'wasm32') // Uses exceptions.
|
||||
goldValue = ""
|
||||
source = "runtime/exceptions/custom_hook_unhandled_exception.kt"
|
||||
}
|
||||
|
||||
standaloneTest("custom_hook_terminate") {
|
||||
enabled = (project.testTarget != 'wasm32') // Uses exceptions.
|
||||
outputChecker = {
|
||||
it.contains("Hook called")
|
||||
}
|
||||
expectedExitStatusChecker = { it != 0 }
|
||||
source = "runtime/exceptions/custom_hook_terminate.kt"
|
||||
}
|
||||
|
||||
standaloneTest("custom_hook_terminate_unhandled_exception") {
|
||||
enabled = (project.testTarget != 'wasm32') // Uses exceptions.
|
||||
outputChecker = {
|
||||
it.contains("Hook called") && it.contains("Uncaught Kotlin exception: kotlin.Error: some error") && !it.contains("Not going to happen")
|
||||
}
|
||||
expectedExitStatusChecker = { it != 0 }
|
||||
source = "runtime/exceptions/custom_hook_terminate_unhandled_exception.kt"
|
||||
}
|
||||
|
||||
standaloneTest("exception_in_global_init") {
|
||||
enabled = (project.testTarget != 'wasm32') // Uses exceptions.
|
||||
source = "runtime/exceptions/exception_in_global_init.kt"
|
||||
@@ -2570,6 +2719,21 @@ task throw_from_catch(type: KonanLocalTest) {
|
||||
source = "runtime/exceptions/throw_from_catch.kt"
|
||||
}
|
||||
|
||||
standaloneTest("terminate") {
|
||||
enabled = (project.testTarget != 'wasm32') // Uses exceptions.
|
||||
expectedExitStatusChecker = { it != 0 }
|
||||
source = "runtime/exceptions/terminate.kt"
|
||||
}
|
||||
|
||||
standaloneTest("unhandled_exception") {
|
||||
enabled = (project.testTarget != 'wasm32') // Uses exceptions.
|
||||
outputChecker = {
|
||||
it.contains("Uncaught Kotlin exception: kotlin.Error: some error")
|
||||
}
|
||||
expectedExitStatusChecker = { it != 0 }
|
||||
source = "runtime/exceptions/unhandled_exception.kt"
|
||||
}
|
||||
|
||||
standaloneTest("runtime_math_exceptions") {
|
||||
enabled = (project.testTarget != 'wasm32')
|
||||
source = "stdlib_external/numbers/MathExceptionTest.kt"
|
||||
@@ -2789,7 +2953,7 @@ task runtime_basic_standard(type: KonanLocalTest) {
|
||||
}
|
||||
|
||||
standaloneTest("runtime_basic_assert_failed") {
|
||||
expectedExitStatus = 1
|
||||
expectedExitStatusChecker = { it != 0 }
|
||||
source = "runtime/basic/assert_failed.kt"
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
@file:OptIn(ExperimentalStdlibApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun main() {
|
||||
val exceptionHook = { _: Throwable ->
|
||||
println("Hook")
|
||||
}.freeze()
|
||||
|
||||
val oldHook = setUnhandledExceptionHook(exceptionHook)
|
||||
assertNull(oldHook)
|
||||
val hook1 = getUnhandledExceptionHook()
|
||||
assertEquals(exceptionHook, hook1)
|
||||
val hook2 = getUnhandledExceptionHook()
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
data class C(val x: Int)
|
||||
|
||||
fun main() {
|
||||
Platform.isMemoryLeakCheckerActive = true
|
||||
|
||||
val c = C(42)
|
||||
setUnhandledExceptionHook({ _: Throwable ->
|
||||
println("Hook ${c.x}")
|
||||
}.freeze())
|
||||
|
||||
throw Error("an error")
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
@file:OptIn(ExperimentalStdlibApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun customExceptionHook(throwable: Throwable) {
|
||||
println("Hook called")
|
||||
assertEquals(::customExceptionHook, getUnhandledExceptionHook())
|
||||
}
|
||||
|
||||
fun main() {
|
||||
setUnhandledExceptionHook((::customExceptionHook).freeze())
|
||||
|
||||
throw Error("some error")
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
@file:OptIn(ExperimentalStdlibApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun main() {
|
||||
setUnhandledExceptionHook({ t: Throwable ->
|
||||
println("Hook called")
|
||||
terminateWithUnhandledException(t)
|
||||
}.freeze())
|
||||
|
||||
throw Error("some error")
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
@file:OptIn(ExperimentalStdlibApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun main() {
|
||||
setUnhandledExceptionHook({ t: Throwable ->
|
||||
println("Hook called")
|
||||
terminateWithUnhandledException(t)
|
||||
}.freeze())
|
||||
|
||||
val exception = Error("some error")
|
||||
processUnhandledException(exception)
|
||||
println("Not going to happen")
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun customExceptionHook(throwable: Throwable) {
|
||||
println("Hook called")
|
||||
throw Error("another error")
|
||||
}
|
||||
|
||||
fun main() {
|
||||
setUnhandledExceptionHook((::customExceptionHook).freeze())
|
||||
|
||||
throw Error("some error")
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
@file:OptIn(ExperimentalStdlibApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun main() {
|
||||
val called = AtomicInt(0)
|
||||
setUnhandledExceptionHook({ _: Throwable ->
|
||||
called.value = 1
|
||||
}.freeze())
|
||||
|
||||
val exception = Error("some error")
|
||||
processUnhandledException(exception)
|
||||
assertEquals(1, called.value)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
@file:OptIn(ExperimentalStdlibApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
fun main() {
|
||||
val exception = Error("some error")
|
||||
terminateWithUnhandledException(exception)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
@file:OptIn(ExperimentalStdlibApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
fun main() {
|
||||
val exception = Error("some error")
|
||||
processUnhandledException(exception)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package runtime.workers.worker_exceptions
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
@Test
|
||||
fun testExecuteAfterStartQuiet() {
|
||||
val worker = Worker.start(errorReporting = false)
|
||||
worker.executeAfter(0L, {
|
||||
throw Error("testExecuteAfterStartQuiet error")
|
||||
}.freeze())
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExecuteStart() {
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, {}) {
|
||||
throw Error("testExecuteStart error")
|
||||
}
|
||||
assertFailsWith<Throwable> {
|
||||
future.result
|
||||
}
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExecuteStartQuiet() {
|
||||
val worker = Worker.start(errorReporting = false)
|
||||
val future = worker.execute(TransferMode.SAFE, {}) {
|
||||
throw Error("testExecuteStartQuiet error")
|
||||
}
|
||||
assertFailsWith<Throwable> {
|
||||
future.result
|
||||
}
|
||||
worker.requestTermination().result
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package runtime.workers.worker_exceptions_legacy
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
@Test
|
||||
fun testExecuteAfterStartLegacy() {
|
||||
val worker = Worker.start()
|
||||
worker.executeAfter(0L, {
|
||||
throw Error("testExecuteAfterStartLegacy error")
|
||||
}.freeze())
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExecuteStartLegacy() {
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, {}) {
|
||||
throw Error("testExecuteStartLegacy error")
|
||||
}
|
||||
assertFailsWith<Throwable> {
|
||||
future.result
|
||||
}
|
||||
worker.requestTermination().result
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun main() {
|
||||
val worker = Worker.start()
|
||||
worker.executeAfter(0L, {
|
||||
throw Error("some error")
|
||||
}.freeze())
|
||||
worker.requestTermination().result
|
||||
println("Will not happen")
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun main() {
|
||||
Worker.current.executeAfter(0L, {
|
||||
throw Error("some error")
|
||||
}.freeze())
|
||||
Worker.current.processQueue()
|
||||
println("Will not happen")
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun main() {
|
||||
setUnhandledExceptionHook({ _: Throwable ->
|
||||
println("hook called")
|
||||
}.freeze())
|
||||
|
||||
|
||||
val worker = Worker.start()
|
||||
worker.executeAfter(0L, {
|
||||
throw Error("some error")
|
||||
}.freeze())
|
||||
worker.requestTermination().result
|
||||
println("Will happen")
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun main() {
|
||||
setUnhandledExceptionHook({ _: Throwable ->
|
||||
println("hook called")
|
||||
}.freeze())
|
||||
|
||||
Worker.current.executeAfter(0L, {
|
||||
throw Error("some error")
|
||||
}.freeze())
|
||||
Worker.current.processQueue()
|
||||
println("Will happen")
|
||||
}
|
||||
Reference in New Issue
Block a user