Skip to content

Commit 181cb72

Browse files
authored
Run atexit handlers before terminating all threads (#14481)
Although not defined by the POSIX standard, it seems that on most systems, atexit handlers are run before threads are terminated. Helps: #13837 Fixes: #14993
1 parent 2889555 commit 181cb72

File tree

6 files changed

+59
-5
lines changed

6 files changed

+59
-5
lines changed

src/postamble.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ function callMain(args) {
167167

168168
#if ABORT_ON_WASM_EXCEPTIONS
169169
// See abortWrapperDepth in preamble.js!
170-
abortWrapperDepth += 2;
170+
abortWrapperDepth += 2;
171171
#endif
172172

173173
#if STANDALONE_WASM
@@ -202,7 +202,7 @@ function callMain(args) {
202202

203203
#if ABORT_ON_WASM_EXCEPTIONS
204204
// See abortWrapperDepth in preamble.js!
205-
abortWrapperDepth -= 2;
205+
abortWrapperDepth -= 2;
206206
#endif
207207
}
208208
}
@@ -440,9 +440,6 @@ function exit(status, implicit) {
440440
}
441441
#endif // ASSERTIONS
442442
} else {
443-
#if USE_PTHREADS
444-
PThread.terminateAllThreads();
445-
#endif
446443
exitRuntime();
447444
}
448445

src/postamble_minimal.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ function run() {
2727
callRuntimeCallbacks(__ATEXIT__);
2828
<<< ATEXITS >>>
2929
#endif
30+
#if USE_PTHREADS
31+
PThread.terminateAllThreads();
32+
#endif
3033

3134
#if IN_TEST_HARNESS
3235
// fflush() filesystem stdio for test harness, since there are existing

src/preamble.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,9 @@ function exitRuntime() {
414414
#if EXIT_RUNTIME
415415
callRuntimeCallbacks(__ATEXIT__);
416416
<<< ATEXITS >>>
417+
#endif
418+
#if USE_PTHREADS
419+
PThread.terminateAllThreads();
417420
#endif
418421
runtimeExited = true;
419422
}

tests/pthread/test_pthread_atexit.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include <assert.h>
2+
#include <pthread.h>
3+
#include <stdbool.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
7+
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
8+
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
9+
bool should_exit;
10+
11+
pthread_t thread;
12+
13+
void *workerThread(void* arg) {
14+
pthread_mutex_lock(&mutex);
15+
while (!should_exit)
16+
pthread_cond_wait(&cond, &mutex);
17+
pthread_mutex_unlock(&mutex);
18+
19+
return NULL;
20+
}
21+
22+
void terminateThread() {
23+
pthread_mutex_lock(&mutex);
24+
should_exit = true;
25+
pthread_cond_signal(&cond);
26+
pthread_mutex_unlock(&mutex);
27+
28+
int res = 0;
29+
int rc = pthread_join(thread, (void**)&res);
30+
assert(rc == 0);
31+
assert(res == 0);
32+
33+
printf("done waiting - thread successfully terminated\n");
34+
}
35+
36+
int main(int argc, char* argv[]) {
37+
int rc = atexit(terminateThread);
38+
assert(rc == 0);
39+
40+
rc = pthread_create(&thread, NULL, workerThread, NULL);
41+
assert(rc == 0);
42+
return 0;
43+
}

tests/pthread/test_pthread_atexit.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
done waiting - thread successfully terminated

tests/test_core.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2323,6 +2323,13 @@ def test_pthread_equal(self):
23232323
def test_pthread_dispatch_after_exit(self):
23242324
self.do_run_in_out_file_test('pthread/test_pthread_dispatch_after_exit.c', interleaved_output=False)
23252325

2326+
@node_pthreads
2327+
def test_pthread_atexit(self):
2328+
# Test to ensure threads are still running when atexit-registered functions are called
2329+
self.set_setting('EXIT_RUNTIME')
2330+
self.set_setting('PTHREAD_POOL_SIZE', 1)
2331+
self.do_run_in_out_file_test('pthread/test_pthread_atexit.c')
2332+
23262333
@node_pthreads
23272334
def test_pthread_nested_work_queue(self):
23282335
self.set_setting('EXIT_RUNTIME')

0 commit comments

Comments
 (0)