diff --git a/Libraries/LibC/sys/types.h b/Libraries/LibC/sys/types.h index 9f7f3edab2..45c376dc01 100644 --- a/Libraries/LibC/sys/types.h +++ b/Libraries/LibC/sys/types.h @@ -66,10 +66,16 @@ typedef void* pthread_once_t; typedef uint32_t pthread_mutex_t; typedef void* pthread_attr_t; typedef void* pthread_mutexattr_t; -typedef void* pthread_cond_t; + +typedef struct __pthread_cond_t { + void* storage; +} pthread_cond_t; + typedef void* pthread_rwlock_t; typedef void* pthread_rwlockatrr_t; typedef void* pthread_spinlock_t; -typedef void* pthread_condattr_t; +typedef struct __pthread_condattr_t { + int clockid; // clockid_t +} pthread_condattr_t; __END_DECLS diff --git a/Libraries/LibPthread/pthread.cpp b/Libraries/LibPthread/pthread.cpp index 2057a25554..16416293e4 100644 --- a/Libraries/LibPthread/pthread.cpp +++ b/Libraries/LibPthread/pthread.cpp @@ -1,11 +1,13 @@ #include #include +#include #include #include #include #include #include #include +#include #include #define PTHREAD_DEBUG @@ -327,4 +329,100 @@ int pthread_attr_setstacksize(pthread_attr_t* attributes, size_t stack_size) return 0; } + +struct WaitNode : public InlineLinkedListNode { + bool waiting { true }; + WaitNode* m_next { nullptr }; + WaitNode* m_prev { nullptr }; +}; + +struct ConditionVariable { + InlineLinkedList waiters; + clockid_t clock; +}; + +int pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* attr) +{ + auto& condvar = *new ConditionVariable; + cond->storage = &condvar; + if (attr) + condvar.clock = attr->clockid; + return 0; +} + +int pthread_cond_destroy(pthread_cond_t* cond) +{ + delete static_cast(cond->storage); + return 0; +} + +int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) +{ + WaitNode node; + auto& condvar = *(ConditionVariable*)cond->storage; + condvar.waiters.append(&node); + while (node.waiting) { + pthread_mutex_unlock(mutex); + sched_yield(); + pthread_mutex_lock(mutex); + } + return 0; +} + +int pthread_condattr_init(pthread_condattr_t* attr) +{ + attr->clockid = CLOCK_MONOTONIC; + return 0; +} + +int pthread_condattr_destroy(pthread_condattr_t*) +{ + return 0; +} + +int pthread_condattr_setclock(pthread_condattr_t* attr, clockid_t clock) +{ + attr->clockid = clock; + return 0; +} + +int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const struct timespec* abstime) +{ + WaitNode node; + auto& condvar = *(ConditionVariable*)cond->storage; + condvar.waiters.append(&node); + while (node.waiting) { + struct timespec now; + if (clock_gettime(condvar.clock, &now) < 0) + return -1; + if ((abstime->tv_sec < now.tv_sec) || (abstime->tv_sec == now.tv_sec && abstime->tv_nsec <= now.tv_nsec)) { + errno = ETIMEDOUT; + return -1; + } + pthread_mutex_unlock(mutex); + sched_yield(); + pthread_mutex_lock(mutex); + } + return 0; +} + +int pthread_cond_signal(pthread_cond_t* cond) +{ + auto& condvar = *(ConditionVariable*)cond->storage; + if (condvar.waiters.is_empty()) + return 0; + auto* node = condvar.waiters.remove_head(); + node->waiting = false; + return 0; +} + +int pthread_cond_broadcast(pthread_cond_t* cond) +{ + auto& condvar = *(ConditionVariable*)cond->storage; + while (!condvar.waiters.is_empty()) { + auto* node = condvar.waiters.remove_head(); + node->waiting = false; + } + return 0; +} } diff --git a/Libraries/LibPthread/pthread.h b/Libraries/LibPthread/pthread.h index 1bab9bf0b8..489a09aae0 100644 --- a/Libraries/LibPthread/pthread.h +++ b/Libraries/LibPthread/pthread.h @@ -4,6 +4,7 @@ #include #include #include +#include __BEGIN_DECLS @@ -56,6 +57,8 @@ int pthread_cond_broadcast(pthread_cond_t*); int pthread_cond_init(pthread_cond_t*, const pthread_condattr_t*); int pthread_cond_signal(pthread_cond_t*); int pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*); +int pthread_condattr_init(pthread_condattr_t*); +int pthread_condattr_setclock(pthread_condattr_t*, clockid_t); int pthread_condattr_destroy(pthread_condattr_t*); int pthread_cancel(pthread_t); int pthread_cond_destroy(pthread_cond_t*);