Adding mutex and rw_lock with the same interface as the kernel versions to
libroot. The mutex is a simple benaphore, the rw_lock is pretty much the same as the one from libkernelland_emu but uses a mutex per lock instead of emulating a global thread lock. Also added MutexLocking and RWLock{Read|Write}Locking and AutoLockers based on them. It's cased with __cplusplus so the locks are also usable from C. Everything's currently exposed in shared/private/locks.h but I think we should make these locking primitves public. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33543 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
d75e3d6c23
commit
93b63126e1
97
headers/private/shared/locks.h
Normal file
97
headers/private/shared/locks.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2009, Michael Lotz, mmlr@mlotz.ch.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _LOCKS_H_
|
||||
#define _LOCKS_H_
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct mutex {
|
||||
int32 benaphore;
|
||||
sem_id semaphore;
|
||||
} mutex;
|
||||
|
||||
status_t mutex_init(mutex *lock, const char *name);
|
||||
void mutex_destroy(mutex *lock);
|
||||
status_t mutex_lock(mutex *lock);
|
||||
void mutex_unlock(mutex *lock);
|
||||
|
||||
|
||||
typedef struct rw_lock {
|
||||
const char * name;
|
||||
mutex lock;
|
||||
struct rw_lock_waiter * waiters;
|
||||
struct rw_lock_waiter * last_waiter;
|
||||
thread_id holder;
|
||||
int32 reader_count;
|
||||
int32 writer_count;
|
||||
int32 owner_count;
|
||||
} rw_lock;
|
||||
|
||||
status_t rw_lock_init(rw_lock *lock, const char *name);
|
||||
void rw_lock_destroy(rw_lock *lock);
|
||||
status_t rw_lock_read_lock(rw_lock *lock);
|
||||
status_t rw_lock_read_unlock(rw_lock *lock);
|
||||
status_t rw_lock_write_lock(rw_lock *lock);
|
||||
status_t rw_lock_write_unlock(rw_lock *lock);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
class MutexLocking {
|
||||
public:
|
||||
inline bool Lock(struct mutex *lock)
|
||||
{
|
||||
return mutex_lock(lock) == B_OK;
|
||||
}
|
||||
|
||||
inline void Unlock(struct mutex *lock)
|
||||
{
|
||||
mutex_unlock(lock);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class RWLockReadLocking {
|
||||
public:
|
||||
inline bool Lock(struct rw_lock *lock)
|
||||
{
|
||||
return rw_lock_read_lock(lock) == B_OK;
|
||||
}
|
||||
|
||||
inline void Unlock(struct rw_lock *lock)
|
||||
{
|
||||
rw_lock_read_unlock(lock);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class RWLockWriteLocking {
|
||||
public:
|
||||
inline bool Lock(struct rw_lock *lock)
|
||||
{
|
||||
return rw_lock_write_lock(lock) == B_OK;
|
||||
}
|
||||
|
||||
inline void Unlock(struct rw_lock *lock)
|
||||
{
|
||||
rw_lock_write_unlock(lock);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef AutoLocker<mutex, MutexLocking> MutexLocker;
|
||||
typedef AutoLocker<rw_lock, RWLockReadLocking> ReadLocker;
|
||||
typedef AutoLocker<rw_lock, RWLockWriteLocking> WriteLocker;
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // _LOCKS_H_
|
@ -17,6 +17,7 @@ MergeObject os_main.o :
|
||||
fs_query.cpp
|
||||
fs_volume.c
|
||||
image.cpp
|
||||
locks.cpp
|
||||
parsedate.cpp
|
||||
port.c
|
||||
scheduler.c
|
||||
|
248
src/system/libroot/os/locks.cpp
Normal file
248
src/system/libroot/os/locks.cpp
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright 2009, Michael Lotz, mmlr@mlotz.ch.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <locks.h>
|
||||
#include <syscalls.h>
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
|
||||
status_t
|
||||
mutex_init(mutex *lock, const char *name)
|
||||
{
|
||||
if (lock == NULL || name == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
lock->benaphore = 0;
|
||||
lock->semaphore = create_sem(0, name);
|
||||
if (lock->semaphore < 0)
|
||||
return lock->semaphore;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mutex_destroy(mutex *lock)
|
||||
{
|
||||
delete_sem(lock->semaphore);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
mutex_lock(mutex *lock)
|
||||
{
|
||||
if (atomic_add(&lock->benaphore, 1) == 0)
|
||||
return B_OK;
|
||||
|
||||
status_t result;
|
||||
do {
|
||||
result = acquire_sem(lock->semaphore);
|
||||
} while (result == B_INTERRUPTED);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mutex_unlock(mutex *lock)
|
||||
{
|
||||
if (atomic_add(&lock->benaphore, -1) != 1)
|
||||
release_sem(lock->semaphore);
|
||||
}
|
||||
|
||||
|
||||
typedef struct rw_lock_waiter {
|
||||
rw_lock_waiter * next;
|
||||
thread_id thread;
|
||||
bool writer;
|
||||
} rw_lock_waiter;
|
||||
|
||||
|
||||
static status_t
|
||||
rw_lock_wait(rw_lock *lock, bool writer)
|
||||
{
|
||||
rw_lock_waiter waiter;
|
||||
waiter.thread = find_thread(NULL);
|
||||
waiter.next = NULL;
|
||||
waiter.writer = writer;
|
||||
|
||||
if (lock->waiters != NULL)
|
||||
lock->last_waiter->next = &waiter;
|
||||
else
|
||||
lock->waiters = &waiter;
|
||||
|
||||
lock->last_waiter = &waiter;
|
||||
|
||||
// the rw_lock is locked when entering, release it before blocking
|
||||
mutex_unlock(&lock->lock);
|
||||
|
||||
status_t result;
|
||||
do {
|
||||
result = _kern_block_thread(0, 0);
|
||||
} while (result == B_INTERRUPTED);
|
||||
|
||||
// and lock it again before returning
|
||||
mutex_lock(&lock->lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
rw_lock_unblock(rw_lock *lock)
|
||||
{
|
||||
// this is called locked
|
||||
if (lock->holder >= 0)
|
||||
return;
|
||||
|
||||
rw_lock_waiter *waiter = lock->waiters;
|
||||
if (waiter == NULL)
|
||||
return;
|
||||
|
||||
if (waiter->writer) {
|
||||
if (lock->reader_count > 0)
|
||||
return;
|
||||
|
||||
lock->waiters = waiter->next;
|
||||
lock->holder = waiter->thread;
|
||||
_kern_unblock_thread(waiter->thread, B_OK);
|
||||
return;
|
||||
}
|
||||
|
||||
while (waiter != NULL && !waiter->writer) {
|
||||
lock->reader_count++;
|
||||
lock->waiters = waiter->next;
|
||||
_kern_unblock_thread(waiter->thread, B_OK);
|
||||
waiter = lock->waiters;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
rw_lock_init(rw_lock *lock, const char *name)
|
||||
{
|
||||
lock->name = name;
|
||||
lock->waiters = NULL;
|
||||
lock->holder = -1;
|
||||
lock->reader_count = 0;
|
||||
lock->writer_count = 0;
|
||||
lock->owner_count = 0;
|
||||
return mutex_init(&lock->lock, name);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rw_lock_destroy(rw_lock *lock)
|
||||
{
|
||||
mutex_lock(&lock->lock);
|
||||
|
||||
rw_lock_waiter *waiter = lock->waiters;
|
||||
while (waiter != NULL) {
|
||||
_kern_unblock_thread(waiter->thread, B_ERROR);
|
||||
waiter = waiter->next;
|
||||
}
|
||||
|
||||
mutex_destroy(&lock->lock);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
rw_lock_read_lock(rw_lock *lock)
|
||||
{
|
||||
MutexLocker locker(lock->lock);
|
||||
|
||||
if (lock->writer_count == 0) {
|
||||
lock->reader_count++;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
if (lock->holder == find_thread(NULL)) {
|
||||
lock->owner_count++;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return rw_lock_wait(lock, false);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
rw_lock_read_unlock(rw_lock *lock)
|
||||
{
|
||||
MutexLocker locker(lock->lock);
|
||||
|
||||
if (lock->holder == find_thread(NULL)) {
|
||||
if (--lock->owner_count > 0)
|
||||
return B_OK;
|
||||
|
||||
// this originally has been a write lock
|
||||
lock->writer_count--;
|
||||
lock->holder = -1;
|
||||
|
||||
rw_lock_unblock(lock);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
if (lock->reader_count <= 0) {
|
||||
debugger("rw_lock not read locked");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
lock->reader_count--;
|
||||
rw_lock_unblock(lock);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
rw_lock_write_lock(rw_lock *lock)
|
||||
{
|
||||
MutexLocker locker(lock->lock);
|
||||
|
||||
if (lock->reader_count == 0 && lock->writer_count == 0) {
|
||||
lock->writer_count++;
|
||||
lock->holder = find_thread(NULL);
|
||||
lock->owner_count = 1;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
if (lock->holder == find_thread(NULL)) {
|
||||
lock->owner_count++;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
lock->writer_count++;
|
||||
|
||||
status_t result = rw_lock_wait(lock, true);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if (lock->holder != find_thread(NULL)) {
|
||||
debugger("write locked but holder not set");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
lock->owner_count = 1;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
rw_lock_write_unlock(rw_lock *lock)
|
||||
{
|
||||
MutexLocker locker(lock->lock);
|
||||
|
||||
if (lock->holder != find_thread(NULL)) {
|
||||
debugger("rw_lock not write locked");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (--lock->owner_count > 0)
|
||||
return B_OK;
|
||||
|
||||
lock->writer_count--;
|
||||
lock->holder = -1;
|
||||
rw_lock_unblock(lock);
|
||||
return B_OK;
|
||||
}
|
Loading…
Reference in New Issue
Block a user