Skip to content

Commit

Permalink
Fixing POSIX testsuite pthread test fails
Browse files Browse the repository at this point in the history
This patch aims for fixing failures in pthread related POSIX test from
clone of http://posixtest.sourceforge.net/

Following problems are addressed:
1. pthread_cond_wait/2-3 test hang
  - Disabling recursive thread cancellation.
  - Allowing __timedwait_cp to be true cancellation point as _cp
    suffix suggests
2. pthread_getschedparam/1-3 test hangs sometimes:
   In pthread_barrier_wait adding check if lock is held by main thread
   and waiting on futex in small slices of time there, to check if
   there is some work to do on behalf of Worker Threads.

Signed-off-by: Adam Bujalski <[email protected]>
  • Loading branch information
abujalski committed Dec 7, 2020
1 parent d977ddf commit 0eb64ed
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 6 deletions.
21 changes: 19 additions & 2 deletions src/library_pthread.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,21 +177,31 @@ var LibraryPThread = {
#endif

runExitHandlers: function() {
console.log('thread exit handlers count: ' + PThread.threadExitHandlers.length);
while (PThread.threadExitHandlers.length > 0) {
PThread.threadExitHandlers.pop()();
}

// Call into the musl function that runs destructors of all thread-specific data.
if (ENVIRONMENT_IS_PTHREAD && _pthread_self()) ___pthread_tsd_run_dtors();
if (ENVIRONMENT_IS_PTHREAD && _pthread_self()) {
console.log('Running ___pthread_tsd_run_dtors');
___pthread_tsd_run_dtors();
} else {
console.log('Not running musl code ENVIRONMENT_IS_PTHREAD: ' + ENVIRONMENT_IS_PTHREAD
+ ' _pthread_self(): ' + _pthread_self());
}
},

onThreadExit: function(tb, exitCode) {
console.log('onThreadExit: tb: ' + tb + ' code: ' + exitCode + ' ENVIRONMENT_IS_PTHREAD: ' + ENVIRONMENT_IS_PTHREAD);
// Disable all cancellation so that executing the cleanup handlers won't trigger another JS
// canceled exception to be thrown.
Atomics.store(HEAPU32, (tb + {{{ C_STRUCTS.pthread.canceldisable }}} ) >> 2, 1/*PTHREAD_CANCEL_DISABLE*/);
Atomics.store(HEAPU32, (tb + {{{ C_STRUCTS.pthread.cancelasync }}} ) >> 2, 0/*PTHREAD_CANCEL_DEFERRED*/);
PThread.runExitHandlers();

console.log('onThreadExit: clean-up handlers run...');

Atomics.store(HEAPU32, (tb + {{{ C_STRUCTS.pthread.threadExitCode }}} ) >> 2, exitCode);
// When we publish this, the main thread is free to deallocate the thread object and we are done.
// Therefore set _pthread_self = 0; above to 'release' the object in this worker thread.
Expand All @@ -207,6 +217,7 @@ var LibraryPThread = {
// by programmer, or implicitly when leaving the thread main function.
threadExit: function(exitCode) {
var tb = _pthread_self();
console.log('Thread exit: tb: ' + tb);
if (tb) { // If we haven't yet exited?
#if ASSERTIONS
err('Pthread 0x' + tb.toString(16) + ' exited.');
Expand All @@ -226,7 +237,9 @@ var LibraryPThread = {
},

threadCancel: function() {
PThread.onThreadExit(_pthread_self(), -1/*PTHREAD_CANCELED*/);
console.log('threadCancel: Thread cancelled...: ' + _pthread_self());
var tb = _pthread_self();
PThread.onThreadExit(tb, -1/*PTHREAD_CANCELED*/);
postMessage({ 'cmd': 'cancelDone' });
},

Expand Down Expand Up @@ -321,6 +334,8 @@ var LibraryPThread = {
return;
}

console.log('cmd: ' + cmd);

if (cmd === 'processQueuedMainThreadWork') {
// TODO: Must post message to main Emscripten thread in PROXY_TO_WORKER mode.
_emscripten_main_thread_process_queued_calls();
Expand Down Expand Up @@ -483,6 +498,7 @@ var LibraryPThread = {
},

$cancelThread: function(pthread_ptr) {
console.log('cancelThread tid: ' + pthread_ptr);
if (ENVIRONMENT_IS_PTHREAD) throw 'Internal Error! cancelThread() can only ever be called from main application thread!';
if (!pthread_ptr) throw 'Internal Error! Null pthread_ptr in cancelThread!';
var pthread = PThread.pthreads[pthread_ptr];
Expand Down Expand Up @@ -944,6 +960,7 @@ var LibraryPThread = {
pthread_cancel__deps: ['$cancelThread', 'emscripten_main_browser_thread_id'],
pthread_cancel: function(thread) {
console.log('pthread_cancel Canceling thread: ' + thread);
if (thread === _emscripten_main_browser_thread_id()) {
err('Main thread (id=' + thread + ') cannot be canceled!');
return ERRNO_CODES.ESRCH;
Expand Down
4 changes: 3 additions & 1 deletion system/lib/libc/musl/src/thread/__timedwait.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ int __timedwait_cp(volatile int *addr, int val,
// 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.
if (is_main_thread || pthread_self()->canceldisable != PTHREAD_CANCEL_DISABLE) {
if (is_main_thread ||
pthread_self()->canceldisable != PTHREAD_CANCEL_DISABLE ||
pthread_self()->cancelasync == PTHREAD_CANCEL_ASYNCHRONOUS) {
double sleepUntilTime = emscripten_get_now() + msecsToSleep;
do {
if (_pthread_isduecanceled(pthread_self())) {
Expand Down
3 changes: 0 additions & 3 deletions tests/test_posixtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,7 @@ def get_pthread_tests():
disabled = {
'test_pthread_create_11_1': 'never returns',
'test_pthread_barrier_wait_2_1': 'never returns',
'test_pthread_cond_timedwait_2_6': 'never returns',
'test_pthread_cond_timedwait_4_3': 'never returns',
'test_pthread_attr_setscope_5_1': 'internally skipped (PTS_UNTESTED)',
'test_pthread_cond_wait_2_3': 'never returns',
'test_pthread_create_5_1': 'never returns',
'test_pthread_exit_1_2': 'never returns',
'test_pthread_exit_2_2': 'never returns',
Expand Down

0 comments on commit 0eb64ed

Please sign in to comment.