diff --git a/headers/posix/pthread.h b/headers/posix/pthread.h index 489aace5ba..feaf8e340b 100644 --- a/headers/posix/pthread.h +++ b/headers/posix/pthread.h @@ -80,6 +80,8 @@ extern "C" { { PTHREAD_MUTEX_RECURSIVE, 0, -42, -1, 0 } #define PTHREAD_COND_INITIALIZER \ { 0, -42, NULL, 0, 0 } +#define PTHREAD_RWLOCK_INITIALIZER \ + { 0, -1, {{0}} } /* mutex functions */ extern int pthread_mutex_destroy(pthread_mutex_t *mutex); diff --git a/headers/posix/sys/types.h b/headers/posix/sys/types.h index b09aba569a..64d497eba9 100644 --- a/headers/posix/sys/types.h +++ b/headers/posix/sys/types.h @@ -105,15 +105,15 @@ struct _pthread_rwlock { __haiku_std_int32 owner; union { struct { - __haiku_std_int32 sem; - } shared; - struct { - __haiku_std_int32 lock_sem; - __haiku_std_int32 lock_count; + __haiku_std_int32 mutex; + __haiku_std_int32 unused; __haiku_std_int32 reader_count; __haiku_std_int32 writer_count; void* waiters[2]; } local; + struct { + __haiku_std_int32 sem; + } shared; } u; }; diff --git a/src/system/libroot/posix/pthread/pthread_rwlock.cpp b/src/system/libroot/posix/pthread/pthread_rwlock.cpp index 65e83bed37..b2470aea08 100644 --- a/src/system/libroot/posix/pthread/pthread_rwlock.cpp +++ b/src/system/libroot/posix/pthread/pthread_rwlock.cpp @@ -12,12 +12,12 @@ #include #include #include +#include #include #include #include "pthread_private.h" - #define MAX_READER_COUNT 1000000 #define RWLOCK_FLAG_SHARED 0x01 @@ -93,8 +93,8 @@ struct SharedRWLock { struct LocalRWLock { uint32_t flags; int32_t owner; - int32_t lock_sem; - int32_t lock_count; + int32_t mutex; + int32_t unused; int32_t reader_count; int32_t writer_count; // Note, that reader_count and writer_count are not used the same way. @@ -106,33 +106,47 @@ struct LocalRWLock { { flags = 0; owner = -1; - lock_sem = create_sem(0, "pthread rwlock"); - lock_count = 1; + mutex = 0; reader_count = 0; writer_count = 0; new(&waiters) WaiterList; - return lock_sem >= 0 ? B_OK : EAGAIN; + return B_OK; } status_t Destroy() { - if (lock_sem < 0) - return B_BAD_VALUE; - return delete_sem(lock_sem) == B_OK ? B_OK : B_BAD_VALUE; + Locker locker(this); + if (reader_count > 0 || waiters.Head() != NULL || writer_count > 0) + return EBUSY; + return B_OK; } bool StructureLock() { - if (atomic_add((int32*)&lock_count, -1) <= 0) - acquire_sem(lock_sem); + // Enter critical region: lock the mutex + int32 status = atomic_or((int32*)&mutex, B_USER_MUTEX_LOCKED); + + // If already locked, call the kernel + if ((status & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) != 0) { + do { + status = _kern_mutex_lock((int32*)&mutex, NULL, 0, 0); + } while (status == B_INTERRUPTED); + + if (status != B_OK) + return false; + } return true; } void StructureUnlock() { - if (atomic_add((int32*)&lock_count, 1) < 0) - release_sem(lock_sem); + // Exit critical region: unlock the mutex + int32 status = atomic_and((int32*)&mutex, + ~(int32)B_USER_MUTEX_LOCKED); + + if ((status & B_USER_MUTEX_WAITING) != 0) + _kern_mutex_unlock((int32*)&mutex, 0); } status_t ReadLock(bigtime_t timeout)