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:
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Michael Lotz, [email protected].
|
||||||
|
* 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_query.cpp
|
||||||
fs_volume.c
|
fs_volume.c
|
||||||
image.cpp
|
image.cpp
|
||||||
|
locks.cpp
|
||||||
parsedate.cpp
|
parsedate.cpp
|
||||||
port.c
|
port.c
|
||||||
scheduler.c
|
scheduler.c
|
||||||
|
|||||||
@@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Michael Lotz, [email protected].
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user