Skip to content

Commit acd89cd

Browse files
committed
Updating check if waiting on futex can be canceled
In __timedwait_cp updating test whether waiting on futex can be canceled (by calling pthread_cancel). This change allows to keep changes in musl minimal.
1 parent 4c4fd41 commit acd89cd

File tree

3 files changed

+26
-37
lines changed

3 files changed

+26
-37
lines changed

src/library_pthread.js

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -171,19 +171,7 @@ var LibraryPThread = {
171171
if (ENVIRONMENT_IS_PTHREAD && threadInfoStruct) ___pthread_tsd_run_dtors();
172172
},
173173

174-
// Called when we are performing a pthread_exit(), either explicitly called by programmer,
175-
// or implicitly when leaving the thread main function.
176-
threadExit: function(exitCode) {
177-
var tb = _pthread_self();
178-
if (tb) { // If we haven't yet exited?
179-
#if ASSERTIONS
180-
err('Pthread 0x' + tb.toString(16) + ' exited.');
181-
#endif
182-
#if PTHREADS_PROFILING
183-
var profilerBlock = Atomics.load(HEAPU32, (threadInfoStruct + {{{ C_STRUCTS.pthread.profilerBlock }}} ) >> 2);
184-
Atomics.store(HEAPU32, (threadInfoStruct + {{{ C_STRUCTS.pthread.profilerBlock }}} ) >> 2, 0);
185-
_free(profilerBlock);
186-
#endif
174+
onThreadExit: function(tb, exitCode) {
187175
// Disable all cancellation so that executing the cleanup handlers won't trigger another JS
188176
// canceled exception to be thrown.
189177
Atomics.store(HEAPU32, (tb + {{{ C_STRUCTS.pthread.canceldisable }}} ) >> 2, 1/*PTHREAD_CANCEL_DISABLE*/);
@@ -193,11 +181,28 @@ var LibraryPThread = {
193181
Atomics.store(HEAPU32, (tb + {{{ C_STRUCTS.pthread.threadExitCode }}} ) >> 2, exitCode);
194182
// When we publish this, the main thread is free to deallocate the thread object and we are done.
195183
// Therefore set threadInfoStruct = 0; above to 'release' the object in this worker thread.
196-
Atomics.store(HEAPU32, (tb + {{{ C_STRUCTS.pthread.threadStatus }}} ) >> 2, 1);
184+
Atomics.store(HEAPU32, (tb + {{{ C_STRUCTS.pthread.threadStatus }}} ) >> 2, 1); // Mark the thread as no longer running.
197185

198186
_emscripten_futex_wake(tb + {{{ C_STRUCTS.pthread.threadStatus }}}, {{{ cDefine('INT_MAX') }}});
187+
_emscripten_futex_wake(tb + {{{ C_STRUCTS.pthread.threadStatus }}}, {{{ cDefine('INT_MAX') }}}); // wake all threads
199188
__register_pthread_ptr(0, 0, 0); // Unregister the thread block also inside the asm.js scope.
200189
threadInfoStruct = 0;
190+
},
191+
192+
// Called when we are performing a pthread_exit(), either explicitly called by programmer,
193+
// or implicitly when leaving the thread main function.
194+
threadExit: function(exitCode) {
195+
var tb = _pthread_self();
196+
if (tb) { // If we haven't yet exited?
197+
#if ASSERTIONS
198+
err('Pthread 0x' + tb.toString(16) + ' exited.');
199+
#endif
200+
#if PTHREADS_PROFILING
201+
var profilerBlock = Atomics.load(HEAPU32, (threadInfoStruct + {{{ C_STRUCTS.pthread.profilerBlock }}} ) >> 2);
202+
Atomics.store(HEAPU32, (threadInfoStruct + {{{ C_STRUCTS.pthread.profilerBlock }}} ) >> 2, 0);
203+
_free(profilerBlock);
204+
#endif
205+
PThread.onThreadExit(tb, exitCode);
201206
if (ENVIRONMENT_IS_PTHREAD) {
202207
// Note: in theory we would like to return any offscreen canvases back to the main thread,
203208
// but if we ever fetched a rendering context for them that would not be valid, so we don't try.
@@ -207,16 +212,8 @@ var LibraryPThread = {
207212
},
208213

209214
threadCancel: function() {
210-
// Disable all cancellation so that executing the cleanup handlers won't trigger another JS
211-
// canceled exception to be thrown.
212-
Atomics.store(HEAPU32, (threadInfoStruct + {{{ C_STRUCTS.pthread.canceldisable }}} ) >> 2, 1/*PTHREAD_CANCEL_DISABLE*/);
213-
Atomics.store(HEAPU32, (threadInfoStruct + {{{ C_STRUCTS.pthread.cancelasync }}} ) >> 2, 0/*PTHREAD_CANCEL_DEFERRED*/);
214-
PThread.runExitHandlers();
215-
Atomics.store(HEAPU32, (threadInfoStruct + {{{ C_STRUCTS.pthread.threadExitCode }}} ) >> 2, -1/*PTHREAD_CANCELED*/);
216-
Atomics.store(HEAPU32, (threadInfoStruct + {{{ C_STRUCTS.pthread.threadStatus }}} ) >> 2, 1); // Mark the thread as no longer running.
217-
_emscripten_futex_wake(threadInfoStruct + {{{ C_STRUCTS.pthread.threadStatus }}}, {{{ cDefine('INT_MAX') }}}); // wake all threads
218-
threadInfoStruct = selfThreadId = 0; // Not hosting a pthread anymore in this worker, reset the info structures to null.
219-
__register_pthread_ptr(0, 0, 0); // Unregister the thread block also inside the asm.js scope.
215+
PThread.onThreadExit(threadInfoStruct, -1/*PTHREAD_CANCELED*/);
216+
selfThreadId = 0;
220217
postMessage({ 'cmd': 'cancelDone' });
221218
},
222219

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

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ int __timedwait_cp(volatile int *addr, int val,
4242
#ifdef __EMSCRIPTEN__
4343
double msecsToSleep = top ? (top->tv_sec * 1000 + top->tv_nsec / 1000000.0) : INFINITY;
4444
int is_main_thread = emscripten_is_main_browser_thread();
45-
int can_cancel_wait = pthread_self()->canceldisable == PTHREAD_CANCEL_ENABLE ||
46-
(pthread_self()->canceldisable == PTHREAD_CANCEL_MASKED &&
47-
pthread_self()->cancelasync == PTHREAD_CANCEL_ASYNCHRONOUS);
48-
if (is_main_thread || can_cancel_wait) {
45+
// cp suffix in the function name means "cancellation point", so this wait can be cancelled
46+
// by the users unless current threads cancelability is set to PTHREAD_CANCEL_DISABLE
47+
// which may be either done by the user of __timedwait() function.
48+
if (is_main_thread || pthread_self()->canceldisable != PTHREAD_CANCEL_DISABLE) {
4949
double sleepUntilTime = emscripten_get_now() + msecsToSleep;
5050
do {
5151
if (_pthread_isduecanceled(pthread_self())) {
@@ -83,13 +83,9 @@ int __timedwait(volatile int *addr, int val,
8383
clockid_t clk, const struct timespec *at, int priv)
8484
{
8585
int cs, r;
86-
86+
__pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
8787
#ifdef __EMSCRIPTEN__
88-
__pthread_setcancelstate(PTHREAD_CANCEL_MASKED, &cs);
89-
if (cs == PTHREAD_CANCEL_DISABLE) __pthread_setcancelstate(cs, 0);
9088
emscripten_conditional_set_current_thread_status(EM_THREAD_STATUS_RUNNING, EM_THREAD_STATUS_WAITMUTEX);
91-
#else
92-
__pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
9389
#endif
9490
r = __timedwait_cp(addr, val, clk, at, priv);
9591
#ifdef __EMSCRIPTEN__

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,8 @@ int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restri
115115

116116
__pthread_mutex_unlock(m);
117117

118-
#ifndef __EMSCRIPTEN__
119118
__pthread_setcancelstate(PTHREAD_CANCEL_MASKED, &cs);
120119
if (cs == PTHREAD_CANCEL_DISABLE) __pthread_setcancelstate(cs, 0);
121-
#endif
122120

123121
do e = __timedwait_cp(fut, seq, clock, ts, !shared);
124122
while (*fut==seq && (!e || e==EINTR));
@@ -182,9 +180,7 @@ int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restri
182180
if (e == ECANCELED) e = 0;
183181

184182
done:
185-
#ifndef __EMSCRIPTEN__
186183
__pthread_setcancelstate(cs, 0);
187-
#endif
188184

189185
if (e == ECANCELED) {
190186
__pthread_testcancel();

0 commit comments

Comments
 (0)