* 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

View File

@ -49,9 +49,11 @@ typedef struct cutex {
#else
int32 count;
#endif
int32 release_count;
uint8 flags;
} cutex;
#define CUTEX_FLAG_CLONE_NAME 0x1
#if 0 && KDEBUG // XXX disable this for now, it causes problems when including thread.h here
# 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);
// 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);
// implementation private:
extern void _cutex_lock(cutex* lock);
extern status_t _cutex_lock(cutex* lock);
extern void _cutex_unlock(cutex* lock);
extern status_t _cutex_trylock(cutex* lock);
static inline void
static inline status_t
cutex_lock(cutex* lock)
{
#ifdef KDEBUG
_cutex_lock(lock);
return _cutex_lock(lock);
#else
if (atomic_add(&lock->count, -1) < 0)
_cutex_lock(lock);
return _cutex_lock(lock);
return B_OK;
#endif
}
@ -149,6 +153,7 @@ cutex_trylock(cutex* lock)
#else
if (atomic_test_and_set(&lock->count, -1, 0) != 0)
return B_WOULD_BLOCK;
return B_OK;
#endif
}

View File

@ -11,6 +11,9 @@
#include <lock.h>
#include <stdlib.h>
#include <string.h>
#include <OS.h>
#include <debug.h>
@ -26,6 +29,9 @@ struct cutex_waiter {
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
recursive_lock_get_recursion(recursive_lock *lock)
@ -302,23 +308,67 @@ cutex_init(cutex* lock, const char *name)
#else
lock->count = 0;
#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
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)
{
#ifdef KDEBUG
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);
}
#endif
@ -328,14 +378,16 @@ _cutex_lock(cutex* lock)
// Might have been released after we decremented the count, but before
// we acquired the spinlock.
#ifdef KDEBUG
if (lock->release_count >= 0) {
if (lock->holder <= 0) {
lock->holder = thread_get_current_thread_id();
#else
if (lock->release_count > 0) {
#endif
lock->release_count--;
return;
return B_OK;
}
#else
if ((lock->flags & CUTEX_FLAG_RELEASED) != 0) {
lock->flags &= ~CUTEX_FLAG_RELEASED;
return B_OK;
}
#endif
// enqueue in waiter list
cutex_waiter waiter;
@ -351,11 +403,14 @@ _cutex_lock(cutex* lock)
// block
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
lock->holder = waiter.thread->id;
if (error == B_OK)
lock->holder = waiter.thread->id;
#endif
return error;
}
@ -371,8 +426,6 @@ _cutex_unlock(cutex* lock)
lock, lock->holder);
return;
}
lock->holder = -1;
#endif
cutex_waiter* waiter = lock->waiters;
@ -384,10 +437,22 @@ _cutex_unlock(cutex* lock)
// unblock thread
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 {
// We acquired the spinlock before the locker that is going to wait.
// Just increment the release count.
lock->release_count++;
// We've acquired the spinlock before the locker that is going to wait.
// Just mark the lock as released.
#ifdef KDEBUG
lock->holder = -1;
#else
lock->flags |= CUTEX_FLAG_RELEASED;
#endif
}
}
@ -398,9 +463,8 @@ _cutex_trylock(cutex* lock)
#ifdef KDEBUG
InterruptsSpinLocker _(thread_spinlock);
if (lock->release_count >= 0) {
if (lock->holder <= 0) {
lock->holder = thread_get_current_thread_id();
lock->release_count--;
return B_OK;
}
#endif
@ -425,7 +489,7 @@ dump_cutex_info(int argc, char** argv)
kprintf("cutex %p:\n", lock);
kprintf(" name: %s\n", lock->name);
kprintf(" release count: %ld\n", lock->release_count);
kprintf(" flags: 0x%x\n", lock->flags);
#ifdef KDEBUG
kprintf(" holder: %ld\n", lock->holder);
#else