Skip to content

Commit 1bdace4

Browse files
committed
Move __cxa_thread_atexit to native code
Rather than using a separate JS array use pthread TLS key which get cleaned during `__pthread_tsd_run_dtors`. Followup to #14484 and #14464 which both move more of the cleanup handling for threads and processes onto the native side.
1 parent e8269a4 commit 1bdace4

10 files changed

+81
-21
lines changed

src/library_pthread.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ var LibraryPThread = {
9696
},
9797
// Maps pthread_t to pthread info objects
9898
pthreads: {},
99-
threadExitHandlers: [], // An array of C functions to run when this thread exits.
10099

101100
#if PTHREADS_PROFILING
102101
createProfilerBlock: function(pthreadPtr) {
@@ -165,10 +164,6 @@ var LibraryPThread = {
165164
#endif
166165

167166
runExitHandlers: function() {
168-
while (PThread.threadExitHandlers.length > 0) {
169-
PThread.threadExitHandlers.pop()();
170-
}
171-
172167
// Call into the musl function that runs destructors of all thread-specific data.
173168
#if ASSERTIONS
174169
assert(_pthread_self())
@@ -1062,13 +1057,6 @@ var LibraryPThread = {
10621057
throw 'unwind';
10631058
},
10641059

1065-
__cxa_thread_atexit__sig: 'vii',
1066-
__cxa_thread_atexit: function(routine, arg) {
1067-
PThread.threadExitHandlers.push(function() { {{{ makeDynCall('vi', 'routine') }}}(arg) });
1068-
},
1069-
__cxa_thread_atexit_impl: '__cxa_thread_atexit',
1070-
1071-
10721060
// Returns 0 on success, or one of the values -ETIMEDOUT, -EWOULDBLOCK or -EINVAL on error.
10731061
emscripten_futex_wait__deps: ['emscripten_main_thread_process_queued_calls'],
10741062
emscripten_futex_wait: function(addr, val, timeout) {

system/lib/libc/musl/src/thread/pthread_key_create.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,9 @@ int __pthread_key_delete(pthread_key_t k)
4040
}
4141

4242
#ifdef __EMSCRIPTEN__
43-
void EMSCRIPTEN_KEEPALIVE __pthread_tsd_run_dtors()
44-
#else
45-
void __pthread_tsd_run_dtors()
43+
EMSCRIPTEN_KEEPALIVE
4644
#endif
45+
void __pthread_tsd_run_dtors()
4746
{
4847
pthread_t self = __pthread_self();
4948
int i, j, not_finished = self->tsd_used;
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2019 The Emscripten Authors. All rights reserved.
3+
* Emscripten is available under two separate licenses, the MIT license and the
4+
* University of Illinois/NCSA Open Source License. Both these licenses can be
5+
* found in the LICENSE file.
6+
* Inspired by libcxxabi/src/cxa_thread_atexit.cpp.
7+
* The main reasons we don't use that version direclty are:
8+
* 1. We want to be able to use __cxa_thread_atexit in pure C programs
9+
* where libcxxabi is not linked in at all.
10+
* 2. The libcxxabi relies on TLS variables and we use to free our TLS data
11+
* block on thread exit. This would cause a chicken and egg issue
12+
* where the TLS variables in libcxxabi/src/cxa_thread_atexit.cpp would
13+
* be freed while processing the list of __cxa_thread_atexit handlers
14+
*/
15+
#include <assert.h>
16+
#include <stdbool.h>
17+
#include <stdatomic.h>
18+
#include <pthread.h>
19+
#include <stdlib.h>
20+
21+
#include "libc.h"
22+
23+
typedef void (*Dtor)(void*);
24+
25+
typedef struct DtorList {
26+
Dtor dtor;
27+
void* obj;
28+
struct DtorList* next;
29+
} DtorList;
30+
31+
void run_dtors(void* arg) {
32+
DtorList* dtors = (DtorList*)arg;
33+
DtorList* head;
34+
while ((head = dtors)) {
35+
dtors = head->next;
36+
head->dtor(head->obj);
37+
free(head);
38+
}
39+
}
40+
41+
static pthread_key_t key;
42+
atomic_bool key_created = false;
43+
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
44+
45+
static void ensure_key() {
46+
// can't use pthread_once here because it depends __cxa_thread_atexit
47+
// the first rime its called to register the cleanup handlers
48+
if (!key_created) {
49+
pthread_mutex_lock(&mutex);
50+
if (!key_created) {
51+
pthread_key_create(&key, run_dtors);
52+
key_created = true;
53+
}
54+
pthread_mutex_unlock(&mutex);
55+
}
56+
}
57+
58+
int __cxa_thread_atexit_impl(Dtor dtor, void* obj, void* dso_symbol) {
59+
ensure_key();
60+
DtorList* old_head = pthread_getspecific(key);
61+
DtorList* head = (DtorList*)(malloc(sizeof(DtorList)));
62+
assert(head);
63+
head->dtor = dtor;
64+
head->obj = obj;
65+
head->next = old_head;
66+
pthread_setspecific(key, head);
67+
return 0;
68+
}
69+
70+
weak_alias(__cxa_thread_atexit_impl, __cxa_thread_atexit);

system/lib/pthread/library_pthread.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
*/
77

88
#define _GNU_SOURCE
9-
#include "../internal/libc.h"
10-
#include "../internal/pthread_impl.h"
9+
1110
#include <assert.h>
1211
#include <dirent.h>
1312
#include <errno.h>
@@ -35,6 +34,9 @@
3534
#include <emscripten/threading.h>
3635
#include <emscripten/stack.h>
3736

37+
#include "libc.h"
38+
#include "pthread_impl.h"
39+
3840
// With LLVM 3.6, C11 is the default compilation mode.
3941
// gets() is deprecated under that standard, but emcc
4042
// still provides it, so always include it in the build.

tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.exports

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ L
1313
M
1414
N
1515
O
16-
P
16+
r
1717
s
1818
t
1919
u

tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ $emscripten_tls_init
3636
$free_tls
3737
$init_mparams
3838
$main
39+
$nodtor
40+
$run_dtors
3941
$sbrk
4042
$stackAlloc
4143
$stackRestore

tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.imports

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,3 @@ a.n
1515
a.o
1616
a.p
1717
a.q
18-
a.r

tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.sent

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,3 @@ n
1515
o
1616
p
1717
q
18-
r
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
16012
1+
16455

tools/system_libs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,7 @@ def get_files(self):
773773
filenames=[
774774
'library_pthread.c',
775775
'emscripten_thread_state.s',
776+
'cxa_thread_atexit.c',
776777
])
777778
else:
778779
ignore += ['thread']

0 commit comments

Comments
 (0)