* The rw_lock is now able to nest read/write locks when you have a write lock.

It follows the semantics of the BFS R/W lock, though, that is, if you unlock
  your write lock before the read locks, the read locks effectively become
  write locks, too.
* Added a mutex_transfer_lock() function that will allow you to unlock a mutex
  in a different thread than the one which locked it (only matters if KDEBUG
  is enabled, though).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26316 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-07-08 07:56:49 +00:00
parent f90a5e346d
commit 78b32dd026
5 changed files with 81 additions and 4 deletions
@@ -993,6 +993,7 @@
#define mutex_lock fssh_mutex_lock #define mutex_lock fssh_mutex_lock
#define mutex_trylock fssh_mutex_trylock #define mutex_trylock fssh_mutex_trylock
#define mutex_unlock fssh_mutex_unlock #define mutex_unlock fssh_mutex_unlock
#define mutex_transfer_lock fssh_mutex_transfer_lock
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
+2
View File
@@ -32,6 +32,7 @@ typedef struct fssh_recursive_lock {
typedef struct fssh_rw_lock { typedef struct fssh_rw_lock {
fssh_sem_id sem; fssh_sem_id sem;
fssh_thread_id holder;
int32_t count; int32_t count;
} fssh_rw_lock; } fssh_rw_lock;
@@ -75,6 +76,7 @@ extern void fssh_mutex_destroy(fssh_mutex* lock);
extern fssh_status_t fssh_mutex_lock(fssh_mutex* lock); extern fssh_status_t fssh_mutex_lock(fssh_mutex* lock);
extern fssh_status_t fssh_mutex_trylock(fssh_mutex* lock); extern fssh_status_t fssh_mutex_trylock(fssh_mutex* lock);
extern void fssh_mutex_unlock(fssh_mutex* lock); extern void fssh_mutex_unlock(fssh_mutex* lock);
extern void fssh_mutex_transfer_lock(fssh_mutex* lock, fssh_thread_id thread);
#ifdef __cplusplus #ifdef __cplusplus
} }
+10
View File
@@ -46,6 +46,7 @@ typedef struct rw_lock {
thread_id holder; thread_id holder;
int32 reader_count; int32 reader_count;
int32 writer_count; int32 writer_count;
int32 owner_count;
uint32 flags; uint32 flags;
} rw_lock; } rw_lock;
@@ -159,6 +160,15 @@ mutex_unlock(mutex* lock)
} }
static inline void
mutex_transfer_lock(mutex* lock, thread_id thread)
{
#ifdef KDEBUG
lock->holder = thread;
#endif
}
extern void lock_debug_init(); extern void lock_debug_init();
#ifdef __cplusplus #ifdef __cplusplus
+33 -3
View File
@@ -191,7 +191,7 @@ rw_lock_unblock(rw_lock* lock)
lock->waiters->last = waiter->last; lock->waiters->last = waiter->last;
lock->holder = waiter->thread->id; lock->holder = waiter->thread->id;
// unblock thread // unblock thread
thread_unblock_locked(waiter->thread, B_OK); thread_unblock_locked(waiter->thread, B_OK);
} }
@@ -221,6 +221,7 @@ rw_lock_init(rw_lock* lock, const char* name)
lock->holder = -1; lock->holder = -1;
lock->reader_count = 0; lock->reader_count = 0;
lock->writer_count = 0; lock->writer_count = 0;
lock->owner_count = 0;
lock->flags = 0; lock->flags = 0;
} }
@@ -233,6 +234,7 @@ rw_lock_init_etc(rw_lock* lock, const char* name, uint32 flags)
lock->holder = -1; lock->holder = -1;
lock->reader_count = 0; lock->reader_count = 0;
lock->writer_count = 0; lock->writer_count = 0;
lock->owner_count = 0;
lock->flags = flags & RW_LOCK_FLAG_CLONE_NAME; lock->flags = flags & RW_LOCK_FLAG_CLONE_NAME;
} }
@@ -284,6 +286,10 @@ rw_lock_read_lock(rw_lock* lock)
lock->reader_count++; lock->reader_count++;
return B_OK; return B_OK;
} }
if (lock->holder == thread_get_current_thread_id()) {
lock->owner_count++;
return B_OK;
}
return rw_lock_wait(lock, false); return rw_lock_wait(lock, false);
} }
@@ -294,6 +300,18 @@ rw_lock_read_unlock(rw_lock* lock)
{ {
InterruptsSpinLocker locker(thread_spinlock); InterruptsSpinLocker locker(thread_spinlock);
if (lock->holder == thread_get_current_thread_id()) {
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) { if (lock->reader_count <= 0) {
panic("rw_lock_read_unlock(): lock %p not read-locked", lock); panic("rw_lock_read_unlock(): lock %p not read-locked", lock);
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -302,7 +320,6 @@ rw_lock_read_unlock(rw_lock* lock)
lock->reader_count--; lock->reader_count--;
rw_lock_unblock(lock); rw_lock_unblock(lock);
return B_OK; return B_OK;
} }
@@ -315,11 +332,22 @@ rw_lock_write_lock(rw_lock* lock)
if (lock->reader_count == 0 && lock->writer_count == 0) { if (lock->reader_count == 0 && lock->writer_count == 0) {
lock->writer_count++; lock->writer_count++;
lock->holder = thread_get_current_thread_id(); lock->holder = thread_get_current_thread_id();
lock->owner_count = 1;
return B_OK;
}
if (lock->holder == thread_get_current_thread_id()) {
lock->owner_count++;
return B_OK; return B_OK;
} }
lock->writer_count++; lock->writer_count++;
return rw_lock_wait(lock, true);
status_t status = rw_lock_wait(lock, true);
if (status == B_OK) {
lock->holder = thread_get_current_thread_id();
lock->owner_count = 1;
}
return status;
} }
@@ -333,6 +361,8 @@ rw_lock_write_unlock(rw_lock* lock)
lock); lock);
return B_BAD_VALUE; return B_BAD_VALUE;
} }
if (--lock->owner_count > 0)
return B_OK;
lock->writer_count--; lock->writer_count--;
lock->holder = -1; lock->holder = -1;
+35 -1
View File
@@ -176,6 +176,13 @@ fssh_mutex_unlock(fssh_mutex *mutex)
} }
extern "C" void
fssh_mutex_transfer_lock(fssh_mutex *mutex, fssh_thread_id thread)
{
mutex->holder = thread;
}
// #pragma mark - // #pragma mark -
@@ -188,6 +195,9 @@ fssh_rw_lock_init(fssh_rw_lock *lock, const char *name)
if (name == NULL) if (name == NULL)
name = "r/w lock"; name = "r/w lock";
lock->count = 0;
lock->holder = -1;
lock->sem = fssh_create_sem(FSSH_RW_MAX_READERS, name); lock->sem = fssh_create_sem(FSSH_RW_MAX_READERS, name);
if (lock->sem < FSSH_B_OK) if (lock->sem < FSSH_B_OK)
fssh_panic("could not create r/w lock"); fssh_panic("could not create r/w lock");
@@ -214,6 +224,11 @@ fssh_rw_lock_destroy(fssh_rw_lock *lock)
extern "C" fssh_status_t extern "C" fssh_status_t
fssh_rw_lock_read_lock(fssh_rw_lock *lock) fssh_rw_lock_read_lock(fssh_rw_lock *lock)
{ {
if (lock->holder == fssh_find_thread(NULL)) {
lock->count++;
return FSSH_B_OK;
}
return fssh_acquire_sem(lock->sem); return fssh_acquire_sem(lock->sem);
} }
@@ -221,6 +236,9 @@ fssh_rw_lock_read_lock(fssh_rw_lock *lock)
extern "C" fssh_status_t extern "C" fssh_status_t
fssh_rw_lock_read_unlock(fssh_rw_lock *lock) fssh_rw_lock_read_unlock(fssh_rw_lock *lock)
{ {
if (lock->holder == fssh_find_thread(NULL) && --lock->count > 0)
return FSSH_B_OK;
return fssh_release_sem(lock->sem); return fssh_release_sem(lock->sem);
} }
@@ -228,13 +246,29 @@ fssh_rw_lock_read_unlock(fssh_rw_lock *lock)
extern "C" fssh_status_t extern "C" fssh_status_t
fssh_rw_lock_write_lock(fssh_rw_lock *lock) fssh_rw_lock_write_lock(fssh_rw_lock *lock)
{ {
return fssh_acquire_sem_etc(lock->sem, FSSH_RW_MAX_READERS, 0, 0); if (lock->holder == fssh_find_thread(NULL)) {
lock->count++;
return FSSH_B_OK;
}
fssh_status_t status = fssh_acquire_sem_etc(lock->sem, FSSH_RW_MAX_READERS,
0, 0);
if (status == FSSH_B_OK) {
lock->holder = fssh_find_thread(NULL);
lock->count = 1;
}
return status;
} }
extern "C" fssh_status_t extern "C" fssh_status_t
fssh_rw_lock_write_unlock(fssh_rw_lock *lock) fssh_rw_lock_write_unlock(fssh_rw_lock *lock)
{ {
if (--lock->count > 0)
return FSSH_B_OK;
lock->holder = -1;
return fssh_release_sem_etc(lock->sem, FSSH_RW_MAX_READERS, 0); return fssh_release_sem_etc(lock->sem, FSSH_RW_MAX_READERS, 0);
} }