diff --git a/userspace/libraries/LibC/include/bits/pthread_types.h b/userspace/libraries/LibC/include/bits/pthread_types.h index 2144dc28..084a847c 100644 --- a/userspace/libraries/LibC/include/bits/pthread_types.h +++ b/userspace/libraries/LibC/include/bits/pthread_types.h @@ -31,8 +31,9 @@ typedef struct { pthread_mutexattr_t attr; pthread_t locker; unsigned lock_depth typedef int pthread_barrierattr_t; typedef int pthread_barrier_t; -typedef int pthread_condattr_t; -typedef int pthread_cond_t; +typedef struct { int clock; int shared; } pthread_condattr_t; +struct _pthread_cond_block { struct _pthread_cond_block* next; int signaled; }; +typedef struct { pthread_condattr_t attr; pthread_spinlock_t lock; struct _pthread_cond_block* block_list; } pthread_cond_t; typedef struct { int shared; } pthread_rwlockattr_t; typedef struct { pthread_rwlockattr_t attr; unsigned lockers; unsigned writers; } pthread_rwlock_t; diff --git a/userspace/libraries/LibC/include/pthread.h b/userspace/libraries/LibC/include/pthread.h index a66c8cff..ae8ebcfc 100644 --- a/userspace/libraries/LibC/include/pthread.h +++ b/userspace/libraries/LibC/include/pthread.h @@ -54,7 +54,7 @@ struct uthread #define PTHREAD_MUTEX_RECURSIVE 3 #define PTHREAD_SPIN_INITIALIZER (pthread_spinlock_t)0 -#define PTHREAD_COND_INITIALIZER (pthread_cond_t)0 +#define PTHREAD_COND_INITIALIZER (pthread_cond_t){ { CLOCK_REALTIME, 0 }, PTHREAD_SPIN_INITIALIZER, NULL } #define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t){ { PTHREAD_MUTEX_DEFAULT, false }, 0, 0 } #define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t){ { false }, 0, 0 } diff --git a/userspace/libraries/LibC/pthread.cpp b/userspace/libraries/LibC/pthread.cpp index d6467a04..4899c964 100644 --- a/userspace/libraries/LibC/pthread.cpp +++ b/userspace/libraries/LibC/pthread.cpp @@ -669,6 +669,155 @@ int pthread_rwlock_unlock(pthread_rwlock_t* rwlock) return 0; } +int pthread_condattr_destroy(pthread_condattr_t* attr) +{ + (void)attr; + return 0; +} + +int pthread_condattr_init(pthread_condattr_t* attr) +{ + *attr = { + .clock = CLOCK_REALTIME, + .shared = false, + }; + return 0; +} + +int pthread_condattr_getclock(const pthread_condattr_t* __restrict attr, clockid_t* __restrict clock_id) +{ + *clock_id = attr->clock; + return 0; +} + +int pthread_condattr_setclock(pthread_condattr_t* attr, clockid_t clock_id) +{ + switch (clock_id) + { + case CLOCK_MONOTONIC: + case CLOCK_REALTIME: + break; + default: + return EINVAL; + } + attr->clock = clock_id; + return 0; +} + +int pthread_condattr_getpshared(const pthread_condattr_t* __restrict attr, int* __restrict pshared) +{ + *pshared = attr->shared ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int pthread_condattr_setpshared(pthread_barrierattr_t* attr, int pshared) +{ + switch (pshared) + { + case PTHREAD_PROCESS_PRIVATE: + attr->shared = false; + return 0; + case PTHREAD_PROCESS_SHARED: + attr->shared = true; + return 0; + } + return EINVAL; +} + +int pthread_cond_destroy(pthread_cond_t* cond) +{ + (void)cond; + return 0; +} + +int pthread_cond_init(pthread_cond_t* __restrict cond, const pthread_condattr_t* __restrict attr) +{ + const pthread_condattr_t default_attr = { + .clock = CLOCK_MONOTONIC, + .shared = false, + }; + if (attr == nullptr) + attr = &default_attr; + *cond = { + .attr = *attr, + .lock = PTHREAD_SPIN_INITIALIZER, + .block_list = nullptr, + }; + return 0; +} + +int pthread_cond_broadcast(pthread_cond_t* cond) +{ + pthread_spin_lock(&cond->lock); + for (auto* block = cond->block_list; block; block = block->next) + BAN::atomic_store(block->signaled, 1); + pthread_spin_unlock(&cond->lock); + return 0; +} + +int pthread_cond_signal(pthread_cond_t* cond) +{ + pthread_spin_lock(&cond->lock); + if (cond->block_list) + BAN::atomic_store(cond->block_list->signaled, 1); + pthread_spin_unlock(&cond->lock); + return 0; +} + +int pthread_cond_wait(pthread_cond_t* __restrict cond, pthread_mutex_t* __restrict mutex) +{ + return pthread_cond_timedwait(cond, mutex, nullptr); +} + +int pthread_cond_timedwait(pthread_cond_t* __restrict cond, pthread_mutex_t* __restrict mutex, const struct timespec* __restrict abstime) +{ + constexpr auto has_timed_out = + [](const struct timespec* abstime, clockid_t clock_id) -> bool + { + if (abstime == nullptr) + return false; + struct timespec curtime; + clock_gettime(clock_id, &curtime); + if (curtime.tv_sec < abstime->tv_sec) + return false; + if (curtime.tv_sec > abstime->tv_sec) + return true; + return curtime.tv_nsec >= abstime->tv_nsec; + }; + + pthread_spin_lock(&cond->lock); + _pthread_cond_block block = { + .next = cond->block_list, + .signaled = 0, + }; + cond->block_list = █ + pthread_spin_unlock(&cond->lock); + + pthread_mutex_unlock(mutex); + + while (BAN::atomic_load(block.signaled) == 0) + { + if (has_timed_out(abstime, cond->attr.clock)) + return ETIMEDOUT; + sched_yield(); + } + + pthread_spin_lock(&cond->lock); + if (&block == cond->block_list) + cond->block_list = block.next; + else + { + _pthread_cond_block* prev = cond->block_list; + while (prev->next != &block) + prev = prev->next; + prev->next = block.next; + } + pthread_spin_unlock(&cond->lock); + + pthread_mutex_lock(mutex); + return 0; +} + #if not __disable_thread_local_storage struct tls_index {