Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions system/lib/libc/musl/src/thread/__timedwait.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ int __timedwait_cp(volatile int *addr, int val,
double msecsToSleep = top ? (top->tv_sec * 1000 + top->tv_nsec / 1000000.0) : INFINITY;

// cp suffix in the function name means "cancellation point", so this wait can be cancelled
// by the users unless current threads cancelability is set to PTHREAD_CANCEL_DISABLE
// which may be either done by the user of __timedwait() function.
// by the user, unless current thread has cancelation disabled (which may be either done
// directly, or indirectly, for example in the __timedwait() function).
pthread_t self = pthread_self();

if (self->canceldisable != PTHREAD_CANCEL_DISABLE) {
Expand All @@ -75,15 +75,14 @@ int __timedwait_cp(volatile int *addr, int val,
// __pthread_testcancel(), which won't return at all.
__pthread_testcancel();
// If __pthread_testcancel does return here it means that canceldisable
// must be set to PTHREAD_CANCEL_MASKED. This appears to mean "return
// ECANCELLED to the caller". See pthread_cond_timedwait.c for the only
// use of this that I could find.
// must be set to PTHREAD_CANCEL_MASKED. In this case we emulate the
// behaviour of the futex syscall and return ECANCELLED here.
// See pthread_cond_timedwait.c for the only use of this flag.
return ECANCELED;
}
msecsToSleep = sleepUntilTime - emscripten_get_now();
if (msecsToSleep <= 0) {
r = ETIMEDOUT;
break;
return ETIMEDOUT;
}
// Must wait in slices in case this thread is cancelled in between.
if (msecsToSleep > max_ms_slice_to_sleep)
Expand Down
11 changes: 0 additions & 11 deletions system/lib/libc/musl/src/thread/pthread_cancel.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ hidden long __cancel(), __syscall_cp_asm(), __syscall_cp_c();
long __cancel()
{
pthread_t self = __pthread_self();
#ifdef __EMSCRIPTEN__
// Emscripten doesn't have actual async cancelation so we make a best effort
// by cancelling cooperatively when self->cancelasync is set.
if (self->canceldisable == PTHREAD_CANCEL_ENABLE || self->cancelasync)
#else
if (self->canceldisable == PTHREAD_CANCEL_ENABLE)
#endif
pthread_exit(PTHREAD_CANCELED);
self->canceldisable = PTHREAD_CANCEL_DISABLE;
return -ECANCELED;
Expand Down Expand Up @@ -83,12 +77,7 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx)
void __testcancel()
{
pthread_t self = __pthread_self();
#ifdef __EMSCRIPTEN__
// See comment above about cancelasync under emscripten.
if (self->cancel && (self->cancelasync || !self->canceldisable))
#else
if (self->cancel && !self->canceldisable)
#endif
__cancel();
}

Expand Down
2 changes: 1 addition & 1 deletion system/lib/pthread/emscripten_futex_wait.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ int emscripten_futex_wait(volatile void *addr, uint32_t val, double max_wait_ms)

#ifdef __EMSCRIPTEN_PTHREADS__
pthread_t self = pthread_self();
bool cancelable = self->cancelasync;
bool cancelable = !self->canceldisable && self->cancelasync;
#else
bool cancelable = false;
#endif
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_minimal_pthreads.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 7363,
"a.out.js.gz": 3604,
"a.out.nodebug.wasm": 19239,
"a.out.nodebug.wasm.gz": 8916,
"total": 26602,
"total_gz": 12520,
"a.out.nodebug.wasm": 19244,
"a.out.nodebug.wasm.gz": 8919,
"total": 26607,
"total_gz": 12523,
"sent": [
"a (memory)",
"b (emscripten_get_now)",
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_minimal_pthreads_memgrowth.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 7765,
"a.out.js.gz": 3810,
"a.out.nodebug.wasm": 19240,
"a.out.nodebug.wasm.gz": 8917,
"total": 27005,
"total_gz": 12727,
"a.out.nodebug.wasm": 19245,
"a.out.nodebug.wasm.gz": 8920,
"total": 27010,
"total_gz": 12730,
"sent": [
"a (memory)",
"b (emscripten_get_now)",
Expand Down
20 changes: 15 additions & 5 deletions test/pthread/test_pthread_cancel_async.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ void emscripten_outf(const char* msg, ...) {

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
_Atomic bool started = false;
_Atomic bool timedlock_returned = false;
_Atomic bool done_cleanup = false;

void cleanup_handler(void *arg) {
Expand All @@ -47,12 +48,20 @@ void *thread_start(void *arg) {
// Signal the main thread that are started
started = true;

// This mutex is locked by the main thread so this call should never return.
// pthread_mutex_lock is not a cancellation point so deferred cancellation
// won't work here, async cancellation should.
pthread_mutex_lock(&mutex);
// At least under musl, async cancellation also does not work for
// pthread_mutex_lock so this call to pthread_mutex_timedlock should always
// timeout.
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 2;
int rc = pthread_mutex_timedlock(&mutex, &ts);
timedlock_returned = true;
assert(rc == ETIMEDOUT);
emscripten_out("pthread_mutex_timedlock timed out");

pthread_testcancel();

assert(false && "pthread_mutex_lock returned!");
assert(false && "pthread_testcancel returned!");
pthread_cleanup_pop(0);
}

Expand All @@ -79,6 +88,7 @@ int main() {
emscripten_out("Joining thread..");
s = pthread_join(thr, NULL);
assert(s == 0);
assert(timedlock_returned);
emscripten_out("done");
return 0;
}
1 change: 1 addition & 0 deletions test/pthread/test_pthread_cancel_async.out
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Starting thread..
Thread started!
Canceling thread..
pthread_mutex_timedlock timed out
Called clean-up handler with arg 42
Joining thread..
done
1 change: 1 addition & 0 deletions test/test_posixtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def get_tests():
'test_pthread_join_6_3': 'creates too many threads',
'test_pthread_barrier_wait_3_2': 'signals are not supported',
'test_pthread_cond_broadcast_1_2': 'tries to create 10,0000 threads, then depends on fork()',
'test_pthread_setcanceltype_1_1': 'async cancelation does not work withing pthread_mutex_lock',
}

unsupported = {
Expand Down
Loading