Thread cleanup handlers (#866)
This commit is contained in:
@@ -22,6 +22,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#if !KONAN_NO_THREADS
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#if KONAN_WINDOWS
|
#if KONAN_WINDOWS
|
||||||
#include <windows.h>
|
#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.
|
// Process execution.
|
||||||
void abort() {
|
void abort() {
|
||||||
::abort();
|
::abort();
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ uint32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes);
|
|||||||
void abort();
|
void abort();
|
||||||
void exit(int32_t status);
|
void exit(int32_t status);
|
||||||
|
|
||||||
|
// Thread control.
|
||||||
|
void onThreadExit(void (*destructor)());
|
||||||
|
|
||||||
// String/byte operations.
|
// String/byte operations.
|
||||||
// memcpy/memmove/memcmp are not here intentionally, as frequently implemented/optimized
|
// memcpy/memmove/memcmp are not here intentionally, as frequently implemented/optimized
|
||||||
// by C compiler.
|
// by C compiler.
|
||||||
|
|||||||
@@ -14,8 +14,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "Alloc.h"
|
#include "Alloc.h"
|
||||||
#include "Exceptions.h"
|
#include "Exceptions.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
@@ -82,8 +80,11 @@ void DeinitRuntime(RuntimeState* state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Kotlin_initRuntimeIfNeeded() {
|
void Kotlin_initRuntimeIfNeeded() {
|
||||||
if (runtimeState == nullptr)
|
if (runtimeState == nullptr) {
|
||||||
runtimeState = InitRuntime();
|
runtimeState = InitRuntime();
|
||||||
|
// Register runtime deinit function at thread cleanup.
|
||||||
|
konan::onThreadExit(Kotlin_deinitRuntimeIfNeeded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kotlin_deinitRuntimeIfNeeded() {
|
void Kotlin_deinitRuntimeIfNeeded() {
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ extern "C" {
|
|||||||
|
|
||||||
RuntimeState* InitRuntime();
|
RuntimeState* InitRuntime();
|
||||||
void DeinitRuntime(RuntimeState* state);
|
void DeinitRuntime(RuntimeState* state);
|
||||||
|
void Kotlin_initRuntimeIfNeeded();
|
||||||
|
void Kotlin_deinitRuntimeIfNeeded();
|
||||||
|
|
||||||
// Appends given node to an initializer list.
|
// Appends given node to an initializer list.
|
||||||
void AppendToInitializersTail(struct InitNode*);
|
void AppendToInitializersTail(struct InitNode*);
|
||||||
|
|||||||
Reference in New Issue
Block a user