Thread cleanup handlers (#866)
This commit is contained in:
@@ -22,6 +22,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if !KONAN_NO_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#if KONAN_WINDOWS
|
||||
#include <windows.h>
|
||||
@@ -90,6 +93,53 @@ void consolePrintf(const char* format, ...) {
|
||||
}
|
||||
|
||||
|
||||
// Thread execution.
|
||||
#if !KONAN_NO_THREADS
|
||||
|
||||
pthread_key_t terminationKey;
|
||||
pthread_once_t terminationKeyOnceControl = PTHREAD_ONCE_INIT;
|
||||
|
||||
typedef void (*destructor_t)();
|
||||
|
||||
struct DestructorRecord {
|
||||
struct DestructorRecord* next;
|
||||
destructor_t destructor;
|
||||
};
|
||||
|
||||
static void onThreadExitCallback(void* value) {
|
||||
DestructorRecord* record = reinterpret_cast<DestructorRecord*>(value);
|
||||
while (record != nullptr) {
|
||||
record->destructor();
|
||||
auto next = record->next;
|
||||
free(record);
|
||||
record = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void onThreadExitInit() {
|
||||
pthread_key_create(&terminationKey, onThreadExitCallback);
|
||||
}
|
||||
|
||||
#endif // !KONAN_NO_THREADS
|
||||
|
||||
void onThreadExit(void (*destructor)()) {
|
||||
#if KONAN_NO_THREADS
|
||||
#ifdef KONAN_WASM
|
||||
// No way to do that.
|
||||
#else
|
||||
::atexit(destructor);
|
||||
#endif
|
||||
#else // !KONAN_NO_THREADS
|
||||
// We cannot use pthread_cleanup_push() as it is lexical scope bound.
|
||||
pthread_once(&terminationKeyOnceControl, onThreadExitInit);
|
||||
DestructorRecord* destructorRecord = (DestructorRecord*)calloc(1, sizeof(DestructorRecord));
|
||||
destructorRecord->destructor = destructor;
|
||||
destructorRecord->next =
|
||||
reinterpret_cast<DestructorRecord*>(pthread_getspecific(terminationKey));
|
||||
pthread_setspecific(terminationKey, destructorRecord);
|
||||
#endif // !KONAN_NO_THREADS
|
||||
}
|
||||
|
||||
// Process execution.
|
||||
void abort() {
|
||||
::abort();
|
||||
|
||||
@@ -33,6 +33,9 @@ uint32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes);
|
||||
void abort();
|
||||
void exit(int32_t status);
|
||||
|
||||
// Thread control.
|
||||
void onThreadExit(void (*destructor)());
|
||||
|
||||
// String/byte operations.
|
||||
// memcpy/memmove/memcmp are not here intentionally, as frequently implemented/optimized
|
||||
// by C compiler.
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Alloc.h"
|
||||
#include "Exceptions.h"
|
||||
#include "Memory.h"
|
||||
@@ -82,8 +80,11 @@ void DeinitRuntime(RuntimeState* state) {
|
||||
}
|
||||
|
||||
void Kotlin_initRuntimeIfNeeded() {
|
||||
if (runtimeState == nullptr)
|
||||
if (runtimeState == nullptr) {
|
||||
runtimeState = InitRuntime();
|
||||
// Register runtime deinit function at thread cleanup.
|
||||
konan::onThreadExit(Kotlin_deinitRuntimeIfNeeded);
|
||||
}
|
||||
}
|
||||
|
||||
void Kotlin_deinitRuntimeIfNeeded() {
|
||||
|
||||
@@ -26,6 +26,8 @@ extern "C" {
|
||||
|
||||
RuntimeState* InitRuntime();
|
||||
void DeinitRuntime(RuntimeState* state);
|
||||
void Kotlin_initRuntimeIfNeeded();
|
||||
void Kotlin_deinitRuntimeIfNeeded();
|
||||
|
||||
// Appends given node to an initializer list.
|
||||
void AppendToInitializersTail(struct InitNode*);
|
||||
|
||||
Reference in New Issue
Block a user