diff options
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibC/sys/types.h | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibPthread/pthread.cpp | 53 |
2 files changed, 46 insertions, 11 deletions
diff --git a/Userland/Libraries/LibC/sys/types.h b/Userland/Libraries/LibC/sys/types.h index 8fb86f0585..dd56e5be97 100644 --- a/Userland/Libraries/LibC/sys/types.h +++ b/Userland/Libraries/LibC/sys/types.h @@ -84,7 +84,9 @@ typedef struct __pthread_cond_t { typedef uint64_t pthread_rwlock_t; typedef void* pthread_rwlockattr_t; -typedef void* pthread_spinlock_t; +typedef struct __pthread_spinlock_t { + int m_lock; +} pthread_spinlock_t; typedef struct __pthread_condattr_t { int clockid; // clockid_t } pthread_condattr_t; diff --git a/Userland/Libraries/LibPthread/pthread.cpp b/Userland/Libraries/LibPthread/pthread.cpp index d9fcb48627..cba9533609 100644 --- a/Userland/Libraries/LibPthread/pthread.cpp +++ b/Userland/Libraries/LibPthread/pthread.cpp @@ -559,29 +559,62 @@ int pthread_setcanceltype([[maybe_unused]] int type, [[maybe_unused]] int* oldty TODO(); } -int pthread_spin_destroy([[maybe_unused]] pthread_spinlock_t* lock) +constexpr static pid_t spinlock_unlock_sentinel = 0; +int pthread_spin_destroy(pthread_spinlock_t* lock) { - TODO(); + auto current = AK::atomic_load(&lock->m_lock); + + if (current != spinlock_unlock_sentinel) + return EBUSY; + + return 0; } -int pthread_spin_init([[maybe_unused]] pthread_spinlock_t* lock, [[maybe_unused]] int shared) +int pthread_spin_init(pthread_spinlock_t* lock, [[maybe_unused]] int shared) { - TODO(); + lock->m_lock = spinlock_unlock_sentinel; + return 0; } -int pthread_spin_lock([[maybe_unused]] pthread_spinlock_t* lock) +int pthread_spin_lock(pthread_spinlock_t* lock) { - TODO(); + const auto desired = gettid(); + while (true) { + auto current = AK::atomic_load(&lock->m_lock); + + if (current == desired) + return EDEADLK; + + if (AK::atomic_compare_exchange_strong(&lock->m_lock, current, desired, AK::MemoryOrder::memory_order_acquire)) + break; + } + + return 0; } -int pthread_spin_trylock([[maybe_unused]] pthread_spinlock_t* lock) +int pthread_spin_trylock(pthread_spinlock_t* lock) { - TODO(); + // We expect the current value to be unlocked, as the specification + // states that trylock should lock ony if it is not held by ANY thread. + auto current = spinlock_unlock_sentinel; + auto desired = gettid(); + + if (AK::atomic_compare_exchange_strong(&lock->m_lock, current, desired, AK::MemoryOrder::memory_order_acquire)) { + return 0; + } else { + return EBUSY; + } } -int pthread_spin_unlock([[maybe_unused]] pthread_spinlock_t* lock) +int pthread_spin_unlock(pthread_spinlock_t* lock) { - TODO(); + auto current = AK::atomic_load(&lock->m_lock); + + if (gettid() != current) + return EPERM; + + AK::atomic_store(&lock->m_lock, spinlock_unlock_sentinel); + return 0; } int pthread_equal(pthread_t t1, pthread_t t2) |