threads: implement support for conditional variables (#323)

The implementation is not as efficient as for native Linux platform due
to lack of FUTEX_REQUEUE-like system call in WASI.

For now we wake all the waiters which is inefficient; if that becomes
a bottleneck, I suggest we'll revisit the implementation.
This commit is contained in:
Marcin Kolny 2022-09-06 23:21:06 +02:00 committed by GitHub
parent 27ba71f95e
commit c40403f9b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 32 additions and 1 deletions

View File

@ -192,11 +192,17 @@ LIBC_TOP_HALF_MUSL_SOURCES += \
$(addprefix $(LIBC_TOP_HALF_MUSL_SRC_DIR)/, \
thread/__wait.c \
thread/__timedwait.c \
thread/pthread_cleanup_push.c \
thread/pthread_cond_broadcast.c \
thread/pthread_cond_destroy.c \
thread/pthread_cond_init.c \
thread/pthread_cond_signal.c \
thread/pthread_cond_timedwait.c \
thread/pthread_cond_wait.c \
thread/pthread_condattr_destroy.c \
thread/pthread_condattr_init.c \
thread/pthread_condattr_setclock.c \
thread/pthread_condattr_setpshared.c \
thread/pthread_cleanup_push.c \
thread/pthread_mutex_consistent.c \
thread/pthread_mutex_destroy.c \
thread/pthread_mutex_init.c \

View File

@ -179,8 +179,10 @@ __polevll
__posix_getopt
__pow_log_data
__powf_log2_data
__private_cond_signal
__progname
__progname_full
__pthread_cond_timedwait
__pthread_mutex_lock
__pthread_mutex_timedlock
__pthread_mutex_trylock
@ -937,6 +939,12 @@ program_invocation_name
program_invocation_short_name
pselect
psignal
pthread_cond_broadcast
pthread_cond_destroy
pthread_cond_init
pthread_cond_signal
pthread_cond_timedwait
pthread_cond_wait
pthread_condattr_destroy
pthread_condattr_init
pthread_condattr_setclock

View File

@ -1,5 +1,9 @@
#include "pthread_impl.h"
#ifndef __wasilibc_unmodified_upstream
#include <common/clock.h>
#endif
/*
* struct waiter
*
@ -48,9 +52,15 @@ static inline void unlock(volatile int *l)
static inline void unlock_requeue(volatile int *l, volatile int *r, int w)
{
a_store(l, 0);
#ifdef __wasilibc_unmodified_upstream
if (w) __wake(l, 1, 1);
else __syscall(SYS_futex, l, FUTEX_REQUEUE|FUTEX_PRIVATE, 0, 1, r) != -ENOSYS
|| __syscall(SYS_futex, l, FUTEX_REQUEUE, 0, 1, r);
#else
// Always wake due to lack of requeue system call in WASI
// This can impact the performance, so we might need to re-visit that decision
__wake(l, 1, 1);
#endif
}
enum {
@ -63,6 +73,9 @@ int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restri
{
struct waiter node = { 0 };
int e, seq, clock = c->_c_clock, cs, shared=0, oldstate, tmp;
#ifndef __wasilibc_unmodified_upstream
struct __clockid clock_id = { .id = clock };
#endif
volatile int *fut;
if ((m->_m_type&15) && (m->_m_lock&INT_MAX) != __pthread_self()->tid)
@ -97,7 +110,11 @@ int __pthread_cond_timedwait(pthread_cond_t *restrict c, pthread_mutex_t *restri
__pthread_setcancelstate(PTHREAD_CANCEL_MASKED, &cs);
if (cs == PTHREAD_CANCEL_DISABLE) __pthread_setcancelstate(cs, 0);
#ifdef __wasilibc_unmodified_upstream
do e = __timedwait_cp(fut, seq, clock, ts, !shared);
#else
do e = __timedwait_cp(fut, seq, &clock_id, ts, !shared);
#endif
while (*fut==seq && (!e || e==EINTR));
if (e == EINTR) e = 0;