Skip to content

Commit 0a396d6

Browse files
committed
Use musl's pthread_detach
The musl version handles that case where pthread_detach is called on a thread that is in the middle of exit'ing.
1 parent 4e95fbb commit 0a396d6

File tree

6 files changed

+43
-58
lines changed

6 files changed

+43
-58
lines changed

.circleci/config.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,10 @@ commands:
235235
command: |
236236
# Using stable rather than beta until we can fix
237237
# https://github.com/emscripten-core/emscripten/issues/14369
238-
wget -O ~/chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
238+
# Currently downloading form our own buckets due to:
239+
# https://github.com/emscripten-core/emscripten/issues/14987
240+
#wget -O ~/chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
241+
wget -O ~/chrome.deb https://storage.googleapis.com/webassembly/chrome/google-chrome-stable_current_amd64.deb
239242
dpkg -i ~/chrome.deb
240243
- run:
241244
name: run tests

src/library_pthread.js

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,13 @@ var LibraryPThread = {
285285
err('Thread ' + d['threadId'] + ': ' + d['text']);
286286
} else if (cmd === 'alert') {
287287
alert('Thread ' + d['threadId'] + ': ' + d['text']);
288-
} else if (cmd === 'exit') {
289-
var detached = worker.pthread && Atomics.load(HEAPU32, (worker.pthread.threadInfoStruct + {{{ C_STRUCTS.pthread.detached }}}) >> 2);
290-
if (detached) {
291-
PThread.returnWorkerToPool(worker);
292-
}
288+
} else if (cmd === 'detachedExit') {
289+
#if ASSERTIONS
290+
assert(worker.pthread);
291+
var detached = Atomics.load(HEAPU32, (worker.pthread.threadInfoStruct + {{{ C_STRUCTS.pthread.detached }}}) >> 2);
292+
assert(detached);
293+
#endif
294+
PThread.returnWorkerToPool(worker);
293295
} else if (cmd === 'exitProcess') {
294296
// A pthread has requested to exit the whole application process (runtime).
295297
#if ASSERTIONS
@@ -331,7 +333,7 @@ var LibraryPThread = {
331333
worker.on('error', function(e) {
332334
worker.onerror(e);
333335
});
334-
worker.on('exit', function() {
336+
worker.on('detachedExit', function() {
335337
// TODO: update the worker queue?
336338
// See: https://github.com/emscripten-core/emscripten/issues/9763
337339
});
@@ -901,29 +903,14 @@ var LibraryPThread = {
901903
return 0;
902904
},
903905

904-
__pthread_detach_js__sig: 'vi',
905-
__pthread_detach_js: function(thread) {
906-
if (!thread) {
907-
err('pthread_detach attempted on a null thread pointer!');
908-
return {{{ cDefine('ESRCH') }}};
909-
}
910-
var self = {{{ makeGetValue('thread', C_STRUCTS.pthread.self, 'i32') }}};
911-
if (self !== thread) {
912-
err('pthread_detach attempted on thread ' + thread + ', which does not point to a valid thread, or does not exist anymore!');
913-
return {{{ cDefine('ESRCH') }}};
914-
}
915-
// Follow musl convention: detached:0 means not detached, 1 means the thread
916-
// was created as detached, and 2 means that the thread was detached via
917-
// pthread_detach.
918-
var wasDetached = Atomics.compareExchange(HEAPU32, (thread + {{{ C_STRUCTS.pthread.detached }}} ) >> 2, 0, 2);
919-
920-
return wasDetached ? {{{ cDefine('EINVAL') }}} : 0;
921-
},
922-
923906
__pthread_exit_run_handlers__deps: ['exit'],
924907
__pthread_exit_run_handlers: function(status) {
925908
// Called from pthread_exit, either when called explicitly called
926909
// by programmer, or implicitly when leaving the thread main function.
910+
//
911+
// Note: in theory we would like to return any offscreen canvases back to
912+
// the main thread, but if we ever fetched a rendering context for them that
913+
// would not be valid, so we don't try.
927914

928915
#if PTHREADS_DEBUG
929916
var tb = _pthread_self();
@@ -936,13 +923,10 @@ var LibraryPThread = {
936923
}
937924
},
938925

939-
__pthread_exit_done: function() {
940-
// Called at the end of pthread_exit, either when called explicitly called
941-
// by programmer, or implicitly when leaving the thread main function.
942-
//
943-
// Note: in theory we would like to return any offscreen canvases back to the main thread,
944-
// but if we ever fetched a rendering context for them that would not be valid, so we don't try.
945-
postMessage({ 'cmd': 'exit' });
926+
__pthread_detached_exit: function() {
927+
// Called at the end of pthread_exit (which occurs also when leaving the
928+
// thread main function) if an only if the thread is in a detached state.
929+
postMessage({ 'cmd': 'detachedExit' });
946930
},
947931

948932
__cxa_thread_atexit__sig: 'vii',

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ int __pthread_join(pthread_t, void **);
55

66
static int __pthread_detach(pthread_t t)
77
{
8+
// XXX EMSCRIPTEN: Add check for invalid (already joined) thread. Again
9+
// for the benefit of the conformance tests.
10+
if (t->self != t)
11+
return ESRCH;
12+
// XXX EMSCRIPTEN: Even though the man page says this is undefined behaviour
13+
// we have several tests in the posixtest suite that depend on this.
14+
if (t->detached)
15+
return EINVAL;
816
/* Cannot detach a thread that's already exiting */
917
if (a_swap(t->exitlock, 1))
1018
return __pthread_join(t, 0);
@@ -15,3 +23,5 @@ static int __pthread_detach(pthread_t t)
1523

1624
weak_alias(__pthread_detach, pthread_detach);
1725
weak_alias(__pthread_detach, thrd_detach);
26+
// XXX EMSCRIPTEN: add extra alias for asan.
27+
weak_alias(__pthread_detach, emscripten_builtin_pthread_detach);

system/lib/pthread/pthread_create.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ extern int __cxa_thread_atexit(void (*)(void *), void *, void *);
2020
extern int __pthread_create_js(struct pthread *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
2121
extern void _emscripten_thread_init(int, int, int);
2222
extern void __pthread_exit_run_handlers();
23-
extern void __pthread_exit_done();
23+
extern void __pthread_detached_exit();
2424
extern int8_t __dso_handle;
2525

2626
static void dummy_0()
@@ -97,6 +97,8 @@ void _emscripten_thread_exit(void* result) {
9797
// Call into the musl function that runs destructors of all thread-specific data.
9898
__pthread_tsd_run_dtors();
9999

100+
__lock(self->exitlock);
101+
100102
if (self == emscripten_main_browser_thread_id()) {
101103
// FIXME(sbc): When pthread_exit causes the entire application to exit
102104
// we should be returning zero (according to the man page for pthread_exit).
@@ -112,13 +114,19 @@ void _emscripten_thread_exit(void* result) {
112114
// Not hosting a pthread anymore in this worker set __pthread_self to NULL
113115
_emscripten_thread_init(0, 0, 0);
114116

115-
// Mark the thread as no longer running.
117+
// Cache deteched state since once we set threadStatus to 1, the `self` struct
118+
// could be freed and reused.
119+
int detatched = self->detached;
120+
121+
// Mark the thread as no longer running so it can be joined.
116122
// Once we publish this, any threads that are waiting to join with us can
117-
// proceed and this worker can be recycled and used to another thread.
123+
// proceed and this worker can be recycled and used on another thread.
118124
self->threadStatus = 1;
119125
emscripten_futex_wake(&self->threadStatus, INT_MAX); // wake all threads
120126

121-
__pthread_exit_done();
127+
if (detatched) {
128+
__pthread_detached_exit();
129+
}
122130
}
123131

124132
// Mark as `no_sanitize("address"` since emscripten_pthread_exit destroys

system/lib/pthread/pthread_detach.c

Lines changed: 0 additions & 19 deletions
This file was deleted.

tools/system_libs.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -748,15 +748,14 @@ def get_files(self):
748748
'lock_ptc.c',
749749
# 'pthread_setattr_default_np.c',
750750
# TODO: These could be moved away from JS in the upcoming musl upgrade.
751-
'pthread_cancel.c', 'pthread_detach.c',
751+
'pthread_cancel.c',
752752
'pthread_join.c', 'pthread_testcancel.c',
753753
]
754754
libc_files += files_in_path(
755755
path='system/lib/pthread',
756756
filenames=[
757757
'library_pthread.c',
758758
'pthread_create.c',
759-
'pthread_detach.c',
760759
'pthread_join.c',
761760
'pthread_testcancel.c',
762761
'emscripten_proxy_main.c',

0 commit comments

Comments
 (0)