* Replaced cutex::release_count by flags field. It is only one thread

that can unlock the mutex, so one bit is sufficient.
* Added cutex_init_etc() which has an additional "flags" parameter.
  The only specifyable flag is CUTEX_FLAG_CLONE_NAME, which causes the
  function to strdup() the given name and free() its copy in
  cutex_destroy().
* cutex_destroy() does now unblock waiting threads.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25280 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2008-05-01 18:06:09 +00:00
parent 2988eab3dc
commit ee96aa8f6e
2 changed files with 94 additions and 25 deletions
+10 -5
View File
@@ -49,9 +49,11 @@ typedef struct cutex {
#else #else
int32 count; int32 count;
#endif #endif
int32 release_count; uint8 flags;
} cutex; } cutex;
#define CUTEX_FLAG_CLONE_NAME 0x1
#if 0 && KDEBUG // XXX disable this for now, it causes problems when including thread.h here #if 0 && KDEBUG // XXX disable this for now, it causes problems when including thread.h here
# include <thread.h> # include <thread.h>
@@ -121,22 +123,24 @@ extern status_t rw_lock_write_unlock(rw_lock *lock);
extern void cutex_init(cutex* lock, const char *name); extern void cutex_init(cutex* lock, const char *name);
// name is *not* cloned nor freed in cutex_destroy() // name is *not* cloned nor freed in cutex_destroy()
extern void cutex_init_etc(cutex* lock, const char *name, uint32 flags);
extern void cutex_destroy(cutex* lock); extern void cutex_destroy(cutex* lock);
// implementation private: // implementation private:
extern void _cutex_lock(cutex* lock); extern status_t _cutex_lock(cutex* lock);
extern void _cutex_unlock(cutex* lock); extern void _cutex_unlock(cutex* lock);
extern status_t _cutex_trylock(cutex* lock); extern status_t _cutex_trylock(cutex* lock);
static inline void static inline status_t
cutex_lock(cutex* lock) cutex_lock(cutex* lock)
{ {
#ifdef KDEBUG #ifdef KDEBUG
_cutex_lock(lock); return _cutex_lock(lock);
#else #else
if (atomic_add(&lock->count, -1) < 0) if (atomic_add(&lock->count, -1) < 0)
_cutex_lock(lock); return _cutex_lock(lock);
return B_OK;
#endif #endif
} }
@@ -149,6 +153,7 @@ cutex_trylock(cutex* lock)
#else #else
if (atomic_test_and_set(&lock->count, -1, 0) != 0) if (atomic_test_and_set(&lock->count, -1, 0) != 0)
return B_WOULD_BLOCK; return B_WOULD_BLOCK;
return B_OK;
#endif #endif
} }
+84 -20
View File
@@ -11,6 +11,9 @@
#include <lock.h> #include <lock.h>
#include <stdlib.h>
#include <string.h>
#include <OS.h> #include <OS.h>
#include <debug.h> #include <debug.h>
@@ -26,6 +29,9 @@ struct cutex_waiter {
cutex_waiter* last; // last in queue (valid for the first in queue) cutex_waiter* last; // last in queue (valid for the first in queue)
}; };
#define CUTEX_FLAG_OWNS_NAME CUTEX_FLAG_CLONE_NAME
#define CUTEX_FLAG_RELEASED 0x2
int32 int32
recursive_lock_get_recursion(recursive_lock *lock) recursive_lock_get_recursion(recursive_lock *lock)
@@ -302,23 +308,67 @@ cutex_init(cutex* lock, const char *name)
#else #else
lock->count = 0; lock->count = 0;
#endif #endif
lock->release_count = 0; lock->flags = 0;
}
void
cutex_init_etc(cutex* lock, const char *name, uint32 flags)
{
lock->name = (flags & CUTEX_FLAG_CLONE_NAME) != 0 ? strdup(name) : name;
lock->waiters = NULL;
#ifdef KDEBUG
lock->holder = -1;
#else
lock->count = 0;
#endif
lock->flags = flags & CUTEX_FLAG_CLONE_NAME;
} }
void void
cutex_destroy(cutex* lock) cutex_destroy(cutex* lock)
{ {
// no-op char* name = (lock->flags & CUTEX_FLAG_CLONE_NAME) != 0
? (char*)lock->name : NULL;
// unblock all waiters
InterruptsSpinLocker locker(thread_spinlock);
#ifdef KDEBUG
if (lock->waiters != NULL && thread_get_current_thread_id()
!= lock->holder) {
panic("cutex_destroy(): there are blocking threads, but caller doesn't "
"hold the lock (%p)", lock);
locker.Unlock();
if (_cutex_lock(lock) != B_OK)
return;
locker.Lock();
}
#endif
while (cutex_waiter* waiter = lock->waiters) {
// dequeue
lock->waiters = waiter->next;
// unblock thread
thread_unblock_locked(waiter->thread, B_ERROR);
}
lock->name = NULL;
locker.Unlock();
free(name);
} }
void status_t
_cutex_lock(cutex* lock) _cutex_lock(cutex* lock)
{ {
#ifdef KDEBUG #ifdef KDEBUG
if (!kernel_startup && !are_interrupts_enabled()) { if (!kernel_startup && !are_interrupts_enabled()) {
panic("_cutex_unlock: called with interrupts disabled for lock %p", panic("_cutex_unlock(): called with interrupts disabled for lock %p",
lock); lock);
} }
#endif #endif
@@ -328,14 +378,16 @@ _cutex_lock(cutex* lock)
// Might have been released after we decremented the count, but before // Might have been released after we decremented the count, but before
// we acquired the spinlock. // we acquired the spinlock.
#ifdef KDEBUG #ifdef KDEBUG
if (lock->release_count >= 0) { if (lock->holder <= 0) {
lock->holder = thread_get_current_thread_id(); lock->holder = thread_get_current_thread_id();
#else return B_OK;
if (lock->release_count > 0) {
#endif
lock->release_count--;
return;
} }
#else
if ((lock->flags & CUTEX_FLAG_RELEASED) != 0) {
lock->flags &= ~CUTEX_FLAG_RELEASED;
return B_OK;
}
#endif
// enqueue in waiter list // enqueue in waiter list
cutex_waiter waiter; cutex_waiter waiter;
@@ -351,11 +403,14 @@ _cutex_lock(cutex* lock)
// block // block
thread_prepare_to_block(waiter.thread, 0, THREAD_BLOCK_TYPE_CUTEX, lock); thread_prepare_to_block(waiter.thread, 0, THREAD_BLOCK_TYPE_CUTEX, lock);
thread_block_locked(waiter.thread); status_t error = thread_block_locked(waiter.thread);
#ifdef KDEBUG #ifdef KDEBUG
lock->holder = waiter.thread->id; if (error == B_OK)
lock->holder = waiter.thread->id;
#endif #endif
return error;
} }
@@ -371,8 +426,6 @@ _cutex_unlock(cutex* lock)
lock, lock->holder); lock, lock->holder);
return; return;
} }
lock->holder = -1;
#endif #endif
cutex_waiter* waiter = lock->waiters; cutex_waiter* waiter = lock->waiters;
@@ -384,10 +437,22 @@ _cutex_unlock(cutex* lock)
// unblock thread // unblock thread
thread_unblock_locked(waiter->thread, B_OK); thread_unblock_locked(waiter->thread, B_OK);
#ifdef KDEBUG
// Already set the holder to the unblocked thread. Besides that this
// actually reflects the current situation, setting it to -1 would
// cause a race condition, since another locker could think the lock
// is not held by anyone.
lock->holder = waiter->thread->id;
#endif
} else { } else {
// We acquired the spinlock before the locker that is going to wait. // We've acquired the spinlock before the locker that is going to wait.
// Just increment the release count. // Just mark the lock as released.
lock->release_count++; #ifdef KDEBUG
lock->holder = -1;
#else
lock->flags |= CUTEX_FLAG_RELEASED;
#endif
} }
} }
@@ -398,9 +463,8 @@ _cutex_trylock(cutex* lock)
#ifdef KDEBUG #ifdef KDEBUG
InterruptsSpinLocker _(thread_spinlock); InterruptsSpinLocker _(thread_spinlock);
if (lock->release_count >= 0) { if (lock->holder <= 0) {
lock->holder = thread_get_current_thread_id(); lock->holder = thread_get_current_thread_id();
lock->release_count--;
return B_OK; return B_OK;
} }
#endif #endif
@@ -425,7 +489,7 @@ dump_cutex_info(int argc, char** argv)
kprintf("cutex %p:\n", lock); kprintf("cutex %p:\n", lock);
kprintf(" name: %s\n", lock->name); kprintf(" name: %s\n", lock->name);
kprintf(" release count: %ld\n", lock->release_count); kprintf(" flags: 0x%x\n", lock->flags);
#ifdef KDEBUG #ifdef KDEBUG
kprintf(" holder: %ld\n", lock->holder); kprintf(" holder: %ld\n", lock->holder);
#else #else