static status_t mutex_lock(pthread_mutex_t* mutex, bigtime_t timeout) { thread_id thisThread = find_thread(NULL); if (mutex->owner == thisThread) { // recursive locking handling if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE) { if (mutex->owner_count == INT32_MAX) return EAGAIN; mutex->owner_count++; return 0; } // deadlock check (not for PTHREAD_MUTEX_NORMAL as per the specs) if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_ERRORCHECK || MUTEX_TYPE(mutex) == PTHREAD_MUTEX_DEFAULT) { // we detect this kind of deadlock and return an error return timeout < 0 ? EBUSY : EDEADLK; } } // set the locked flag int32 oldValue = atomic_or((int32*)&mutex->lock, B_USER_MUTEX_LOCKED); if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) != 0) { // someone else has the lock or is at least waiting for it if (timeout < 0) return EBUSY; // we have to call the kernel status_t error; do { error = _kern_mutex_lock((int32*)&mutex->lock, NULL, timeout == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT, timeout); } while (error == B_INTERRUPTED); if (error != B_OK) return error; } // we have locked the mutex for the first time mutex->owner = thisThread; mutex->owner_count = 1; return 0; }
static status_t mutex_lock(pthread_mutex_t *mutex, bigtime_t timeout) { thread_id thisThread = find_thread(NULL); status_t status = B_OK; if (mutex == NULL) return B_BAD_VALUE; // If statically initialized, we need to create the semaphore, now. if (mutex->sem == -42) { sem_id sem = create_sem(0, "pthread_mutex"); if (sem < 0) return EAGAIN; if (atomic_test_and_set((vint32*)&mutex->sem, sem, -42) != -42) delete_sem(sem); } if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_ERRORCHECK && mutex->owner == thisThread) { // we detect this kind of deadlock and return an error return EDEADLK; } if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE && mutex->owner == thisThread) { // if we already hold the mutex, we don't need to grab it again mutex->owner_count++; return B_OK; } if (atomic_add((vint32*)&mutex->count, 1) > 0) { // this mutex is already locked by someone else, so we need // to wait status = acquire_sem_etc(mutex->sem, 1, timeout == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT, timeout); } if (status == B_OK) { // we have locked the mutex for the first time mutex->owner = thisThread; mutex->owner_count = 1; } return status; }
int pthread_mutex_unlock(pthread_mutex_t *mutex) { if (mutex == NULL) return B_BAD_VALUE; if (mutex->owner != find_thread(NULL)) return EPERM; if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE && mutex->owner_count-- > 1) { return B_OK; } mutex->owner = -1; if (atomic_add((vint32*)&mutex->count, -1) > 1) return release_sem(mutex->sem); return B_OK; }
int pthread_mutex_unlock(pthread_mutex_t* mutex) { if (mutex->owner != find_thread(NULL)) return EPERM; if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE && --mutex->owner_count > 0) { // still locked return 0; } mutex->owner = -1; // clear the locked flag int32 oldValue = atomic_and((int32*)&mutex->lock, ~(int32)B_USER_MUTEX_LOCKED); if ((oldValue & B_USER_MUTEX_WAITING) != 0) _kern_mutex_unlock((int32*)&mutex->lock, 0); return 0; }