diff --git a/runtime/src/main/cpp/Memory.cpp b/runtime/src/main/cpp/Memory.cpp index 4affea273dd..b518858878e 100644 --- a/runtime/src/main/cpp/Memory.cpp +++ b/runtime/src/main/cpp/Memory.cpp @@ -2453,6 +2453,7 @@ MemoryState* InitMemory() { } void DeinitMemory(MemoryState* memoryState) { + ::memoryState = memoryState; deinitMemory(memoryState); } diff --git a/runtime/src/main/cpp/Porting.cpp b/runtime/src/main/cpp/Porting.cpp index 183ddb772a4..6d5dbb3c9f6 100644 --- a/runtime/src/main/cpp/Porting.cpp +++ b/runtime/src/main/cpp/Porting.cpp @@ -127,17 +127,18 @@ void consolePrintf(const char* format, ...) { pthread_key_t terminationKey; pthread_once_t terminationKeyOnceControl = PTHREAD_ONCE_INIT; -typedef void (*destructor_t)(); +typedef void (*destructor_t)(void*); struct DestructorRecord { struct DestructorRecord* next; destructor_t destructor; + void* destructorParameter; }; static void onThreadExitCallback(void* value) { DestructorRecord* record = reinterpret_cast(value); while (record != nullptr) { - record->destructor(); + record->destructor(record->destructorParameter); auto next = record->next; free(record); record = next; @@ -150,7 +151,7 @@ static void onThreadExitInit() { #endif // !KONAN_NO_THREADS -void onThreadExit(void (*destructor)()) { +void onThreadExit(void (*destructor)(void*), void* destructorParameter) { #if KONAN_NO_THREADS #if KONAN_WASM || KONAN_ZEPHYR // No way to do that. @@ -162,6 +163,7 @@ void onThreadExit(void (*destructor)()) { pthread_once(&terminationKeyOnceControl, onThreadExitInit); DestructorRecord* destructorRecord = (DestructorRecord*)calloc(1, sizeof(DestructorRecord)); destructorRecord->destructor = destructor; + destructorRecord->destructorParameter = destructorParameter; destructorRecord->next = reinterpret_cast(pthread_getspecific(terminationKey)); pthread_setspecific(terminationKey, destructorRecord); diff --git a/runtime/src/main/cpp/Porting.h b/runtime/src/main/cpp/Porting.h index b66318c3627..aed271fe9c0 100644 --- a/runtime/src/main/cpp/Porting.h +++ b/runtime/src/main/cpp/Porting.h @@ -37,7 +37,7 @@ RUNTIME_NORETURN void abort(void); RUNTIME_NORETURN void exit(int32_t status); // Thread control. -void onThreadExit(void (*destructor)()); +void onThreadExit(void (*destructor)(void*), void* destructorParameter); // String/byte operations. // memcpy/memmove/memcmp are not here intentionally, as frequently implemented/optimized diff --git a/runtime/src/main/cpp/Runtime.cpp b/runtime/src/main/cpp/Runtime.cpp index 163c6183857..39b575fe1e2 100644 --- a/runtime/src/main/cpp/Runtime.cpp +++ b/runtime/src/main/cpp/Runtime.cpp @@ -22,7 +22,6 @@ #include "Porting.h" #include "Runtime.h" - struct RuntimeState { MemoryState* memoryState; volatile int executionStatus; @@ -72,17 +71,23 @@ void InitOrDeinitGlobalVariables(int initialize) { } } -THREAD_LOCAL_VARIABLE RuntimeState* runtimeState = nullptr; +constexpr RuntimeState* kInvalidRuntime = nullptr; + +THREAD_LOCAL_VARIABLE RuntimeState* runtimeState = kInvalidRuntime; THREAD_LOCAL_VARIABLE int isMainThread = 0; +inline bool isValidRuntime() { + return ::runtimeState != kInvalidRuntime; +} + int aliveRuntimesCount = 0; RuntimeState* initRuntime() { SetKonanTerminateHandler(); RuntimeState* result = konanConstructInstance(); - if (!result) return nullptr; - RuntimeCheck(runtimeState == nullptr, "No active runtimes allowed"); - runtimeState = result; + if (!result) return kInvalidRuntime; + RuntimeCheck(!isValidRuntime(), "No active runtimes allowed"); + ::runtimeState = result; result->memoryState = InitMemory(); bool firstRuntime = atomicAdd(&aliveRuntimesCount, 1) == 1; // Keep global variables in state as well. @@ -104,6 +109,12 @@ void deinitRuntime(RuntimeState* state) { konanDestructInstance(state); } +void Kotlin_deinitRuntimeCallback(void* argument) { + auto* state = reinterpret_cast(argument); + RuntimeCheck(updateStatusIf(state, RUNNING, DESTROYING), "Cannot transition state to DESTROYING"); + deinitRuntime(state); +} + } // namespace extern "C" { @@ -119,19 +130,18 @@ void AppendToInitializersTail(InitNode *next) { } void Kotlin_initRuntimeIfNeeded() { - if (runtimeState == nullptr) { + if (!isValidRuntime()) { initRuntime(); - RuntimeCheck(updateStatusIf(runtimeState, SUSPENDED, RUNNING), "Cannot transition state to RUNNING for init"); + RuntimeCheck(updateStatusIf(::runtimeState, SUSPENDED, RUNNING), "Cannot transition state to RUNNING for init"); // Register runtime deinit function at thread cleanup. - konan::onThreadExit(Kotlin_deinitRuntimeIfNeeded); + konan::onThreadExit(Kotlin_deinitRuntimeCallback, runtimeState); } } void Kotlin_deinitRuntimeIfNeeded() { - if (runtimeState != nullptr) { - RuntimeCheck(updateStatusIf(runtimeState, RUNNING, DESTROYING), "Cannot transition state to DESTROYING"); - deinitRuntime(runtimeState); - runtimeState = nullptr; + if (isValidRuntime()) { + deinitRuntime(::runtimeState); + ::runtimeState = kInvalidRuntime; } } @@ -145,23 +155,23 @@ void Kotlin_destroyRuntime(RuntimeState* state) { } RuntimeState* Kotlin_suspendRuntime() { - RuntimeCheck(::runtimeState != nullptr, "Runtime must be active on the current thread"); + RuntimeCheck(isValidRuntime(), "Runtime must be active on the current thread"); auto result = ::runtimeState; RuntimeCheck(updateStatusIf(result, RUNNING, SUSPENDED), "Cannot transition state to SUSPENDED for suspend"); result->memoryState = SuspendMemory(); - ::runtimeState = nullptr; + ::runtimeState = kInvalidRuntime; return result; } void Kotlin_resumeRuntime(RuntimeState* state) { - RuntimeCheck(::runtimeState == nullptr, "Runtime must not be active on the current thread"); + RuntimeCheck(!isValidRuntime(), "Runtime must not be active on the current thread"); RuntimeCheck(updateStatusIf(state, SUSPENDED, RUNNING), "Cannot transition state to RUNNING for resume"); ::runtimeState = state; ResumeMemory(state->memoryState); } RuntimeState* RUNTIME_USED Kotlin_getRuntime() { - RuntimeCheck(::runtimeState != nullptr, "Runtime must be active on the current thread"); + RuntimeCheck(isValidRuntime(), "Runtime must be active on the current thread"); return ::runtimeState; } diff --git a/runtime/src/main/cpp/Worker.cpp b/runtime/src/main/cpp/Worker.cpp index ee5ca370bce..1cb1ea06aa4 100644 --- a/runtime/src/main/cpp/Worker.cpp +++ b/runtime/src/main/cpp/Worker.cpp @@ -591,8 +591,6 @@ void* workerRoutine(void* argument) { konanDestructInstance(worker); - Kotlin_deinitRuntimeIfNeeded(); - return nullptr; } diff --git a/runtime/src/main/kotlin/kotlin/native/Runtime.kt b/runtime/src/main/kotlin/kotlin/native/Runtime.kt index f8873c02da4..0b4beb81fe9 100644 --- a/runtime/src/main/kotlin/kotlin/native/Runtime.kt +++ b/runtime/src/main/kotlin/kotlin/native/Runtime.kt @@ -15,8 +15,10 @@ external public fun initRuntimeIfNeeded(): Unit /** * Deinitializes Kotlin runtime for the current thread, if was inited. + * Cannot be called from Kotlin frames holding references, thus deprecated. */ @SymbolName("Kotlin_deinitRuntimeIfNeeded") +@Deprecated("Deinit runtime can not be called from Kotlin", level = DeprecationLevel.ERROR) external public fun deinitRuntimeIfNeeded(): Unit /**