Skip to content

Commit 919d34a

Browse files
committed
Use pthread_{testcancel,join} from musl
1 parent a9b8f72 commit 919d34a

File tree

9 files changed

+57
-109
lines changed

9 files changed

+57
-109
lines changed

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33

44
static int __pthread_detach(pthread_t t)
55
{
6-
// XXX EMSCRIPTEN: Add check for invalid (already joined) thread. Again
7-
// for the benefit of the conformance tests.
8-
if (t->self != t)
9-
return ESRCH;
6+
#ifdef __EMSCRIPTEN__
7+
// Attempt to detach a thread which does not point to a valid thread, or
8+
// does not exist anymore.
9+
if (!t || t->self != t) return ESRCH;
10+
#endif
1011
/* If the cas fails, detach state is either already-detached
1112
* or exiting/exited, and pthread_join will trap or cleanup. */
1213
if (a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED) != DT_JOINABLE)
@@ -16,5 +17,6 @@ static int __pthread_detach(pthread_t t)
1617

1718
weak_alias(__pthread_detach, pthread_detach);
1819
weak_alias(__pthread_detach, thrd_detach);
19-
// XXX EMSCRIPTEN: add extra alias for asan.
20+
#ifdef __EMSCRIPTEN__ // XXX Emscripten add an extra alias for ASan/LSan.
2021
weak_alias(__pthread_detach, emscripten_builtin_pthread_detach);
22+
#endif

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,55 @@ static void dummy1(pthread_t t)
77
}
88
weak_alias(dummy1, __tl_sync);
99

10+
#ifdef __EMSCRIPTEN__ // XXX Emscripten add extern for __emscripten_thread_cleanup
11+
extern void __emscripten_thread_cleanup(pthread_t thread);
12+
#endif
13+
1014
static int __pthread_timedjoin_np(pthread_t t, void **res, const struct timespec *at)
1115
{
16+
#ifdef __EMSCRIPTEN__
17+
// Attempt to join a thread which does not point to a valid thread, or
18+
// does not exist anymore.
19+
if (!t || t->self != t) return ESRCH;
20+
// Thread is attempting to join to itself. Already detached threads are
21+
// handled below by returning EINVAL instead.
22+
if (t->detach_state != DT_DETACHED && __pthread_self() == t) return EDEADLK;
23+
#endif
1224
int state, cs, r = 0;
1325
__pthread_testcancel();
1426
__pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
1527
if (cs == PTHREAD_CANCEL_ENABLE) __pthread_setcancelstate(cs, 0);
1628
while ((state = t->detach_state) && r != ETIMEDOUT && r != EINVAL) {
29+
#ifdef __EMSCRIPTEN__
30+
// The thread is (already) detached and therefore not joinable.
31+
// This also handle cases where the thread becomes detached
32+
// *during* the join.
33+
if (state >= DT_DETACHED) {
34+
// Even though the man page says this is undefined
35+
// behaviour we ave several tests in the posixtest suite
36+
// that depend on this.
37+
r = EINVAL;
38+
break;
39+
}
40+
// Check whether blocking is allowed when the state is joinable.
41+
// This is not necessary for exiting threads because they can be
42+
// joined without blocking.
43+
if (state == DT_JOINABLE) emscripten_check_blocking_allowed();
44+
#else
1745
if (state >= DT_DETACHED) a_crash();
46+
#endif
1847
r = __timedwait_cp(&t->detach_state, state, CLOCK_REALTIME, at, 1);
1948
}
2049
__pthread_setcancelstate(cs, 0);
2150
if (r == ETIMEDOUT || r == EINVAL) return r;
2251
__tl_sync(t);
2352
if (res) *res = t->result;
53+
#ifdef __EMSCRIPTEN__
54+
// Thread was exited during this call, be sure to clean it up.
55+
if (state == DT_EXITED) __emscripten_thread_cleanup(t);
56+
#else // XXX Emscripten map_base unused
2457
if (t->map_base) __munmap(t->map_base, t->map_size);
58+
#endif
2559
return 0;
2660
}
2761

@@ -38,3 +72,6 @@ static int __pthread_tryjoin_np(pthread_t t, void **res)
3872
weak_alias(__pthread_tryjoin_np, pthread_tryjoin_np);
3973
weak_alias(__pthread_timedjoin_np, pthread_timedjoin_np);
4074
weak_alias(__pthread_join, pthread_join);
75+
#ifdef __EMSCRIPTEN__ // XXX Emscripten add an extra alias for LSan
76+
weak_alias(__pthread_join, emscripten_builtin_pthread_join);
77+
#endif

system/lib/pthread/library_pthread.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@
3434
#include <emscripten/threading.h>
3535
#include <emscripten/stack.h>
3636

37-
void __pthread_testcancel();
38-
3937
int emscripten_pthread_attr_gettransferredcanvases(const pthread_attr_t* a, const char** str) {
4038
*str = a->_a_transferredcanvases;
4139
return 0;

system/lib/pthread/library_pthread_stub.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ int pthread_cancel(pthread_t thread) {
206206
return 0;
207207
}
208208

209+
void pthread_testcancel() {}
210+
209211
_Noreturn void __pthread_exit(void* status) {
210212
exit(0);
211213
}

system/lib/pthread/pthread_create.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,16 +231,14 @@ void _emscripten_thread_exit(void* result) {
231231
// call; the loser is responsible for freeing thread resources.
232232
int state = a_cas(&self->detach_state, DT_JOINABLE, DT_EXITING);
233233

234-
// Mark the thread as no longer running.
235-
// When we publish this, the main thread is free to deallocate the thread
236-
// object and we are done.
237234
if (state == DT_DETACHED) {
238-
self->detach_state = DT_EXITED;
239235
__emscripten_thread_cleanup(self);
240236
} else {
241-
self->detach_state = DT_EXITING;
242-
// wake any threads that might be waiting for us to exit
243-
emscripten_futex_wake(&self->detach_state, INT_MAX);
237+
// Mark the thread as no longer running, so it can be joined.
238+
// Once we publish this, any threads that are waiting to join with us can
239+
// proceed and this worker can be recycled and used on another thread.
240+
a_store(&self->detach_state, DT_EXITED);
241+
__wake(&self->detach_state, 1, 1); // Wake any joiner.
244242
}
245243
}
246244

system/lib/pthread/pthread_join.c

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

system/lib/pthread/pthread_testcancel.c

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

tests/pthread/main_thread_join.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <assert.h>
77
#include <emscripten.h>
8+
#include <emscripten/threading.h>
89
#include <pthread.h>
910
#include <stdio.h>
1011

@@ -32,8 +33,12 @@ void *ThreadMain(void *arg) {
3233
// Delay to force the main thread to try and fail a few times before
3334
// succeeding.
3435
while (tries.load() < EXPECTED_TRIES) {}
36+
#else
37+
// Delay a bit to force the main thread to actually block, as exited
38+
// threads can be joined without blocking.
39+
emscripten_thread_sleep(1000);
3540
#endif
36-
pthread_exit((void*)0);
41+
pthread_exit((void*)0);
3742
}
3843

3944
pthread_t CreateThread() {

tools/system_libs.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -814,16 +814,12 @@ def get_files(self):
814814
'syscall_cp.c', 'tls.c',
815815
# TODO: Support this. See #12216.
816816
'pthread_setname_np.c',
817-
# TODO: These could be moved away from JS in the upcoming musl upgrade.
818-
'pthread_join.c', 'pthread_testcancel.c',
819817
]
820818
libc_files += files_in_path(
821819
path='system/lib/pthread',
822820
filenames=[
823821
'library_pthread.c',
824822
'pthread_create.c',
825-
'pthread_join.c',
826-
'pthread_testcancel.c',
827823
'emscripten_proxy_main.c',
828824
'emscripten_thread_state.S',
829825
])

0 commit comments

Comments
 (0)