Added locking primitive lazy_mutex, which has essentially the same behaviour

as a mutex, but allocates its semaphore lazily. This comes at the cost of an
additional atomic_add() when the semaphore has actually to be acquired, but
saves the semaphore creation completely in single-threaded programs and in
any program when there's no lock contention.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34339 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-11-29 10:44:07 +00:00
parent f2bb2575e6
commit 937b23cb21
2 changed files with 115 additions and 0 deletions

View File

@ -22,6 +22,19 @@ status_t mutex_lock(mutex *lock);
void mutex_unlock(mutex *lock);
typedef struct lazy_mutex {
int32 benaphore;
sem_id semaphore;
const char* name;
} lazy_mutex;
status_t lazy_mutex_init(lazy_mutex *lock, const char *name);
// name will not be cloned and must rename valid
void lazy_mutex_destroy(mutex *lock);
status_t lazy_mutex_lock(lazy_mutex *lock);
void lazy_mutex_unlock(lazy_mutex *lock);
typedef struct rw_lock {
const char * name;
mutex lock;

View File

@ -67,6 +67,108 @@ mutex_unlock(mutex *lock)
}
// #pragma mark - lazy mutex
enum {
STATE_UNINITIALIZED = -1,
STATE_INITIALIZING = -2,
STATE_SPIN_LOCKED = -3,
STATE_SPIN_UNLOCKED = -4
};
static inline bool
lazy_mutex_ensure_init(lazy_mutex *lock)
{
int32 value = atomic_test_and_set((vint32*)&lock->semaphore,
STATE_INITIALIZING, STATE_UNINITIALIZED);
if (value >= 0)
return true;
if (value == STATE_UNINITIALIZED) {
// we're the first -- perform the initialization
sem_id semaphore = create_sem(0, lock->name);
if (semaphore < 0)
semaphore = STATE_SPIN_UNLOCKED;
atomic_set((vint32*)&lock->semaphore, semaphore);
return semaphore >= 0;
}
if (value == STATE_INITIALIZING) {
// someone else is initializing -- spin until that is done
while (atomic_get((vint32*)&lock->semaphore) == STATE_INITIALIZING) {
}
}
return lock->semaphore >= 0;
}
status_t
lazy_mutex_init(lazy_mutex *lock, const char *name)
{
if (lock == NULL || name == NULL)
return B_BAD_VALUE;
lock->benaphore = 0;
lock->semaphore = STATE_UNINITIALIZED;
lock->name = name;
return B_OK;
}
void
lazy_mutex_destroy(lazy_mutex *lock)
{
if (lock->semaphore >= 0)
delete_sem(lock->semaphore);
}
status_t
lazy_mutex_lock(lazy_mutex *lock)
{
if (atomic_add(&lock->benaphore, 1) == 0)
return B_OK;
if (lazy_mutex_ensure_init(lock)) {
// acquire the semaphore
status_t result;
do {
result = acquire_sem(lock->semaphore);
} while (result == B_INTERRUPTED);
return result;
} else {
// the semaphore creation failed -- so we use it like a spinlock instead
while (atomic_test_and_set((vint32*)&lock->semaphore,
STATE_SPIN_LOCKED, STATE_SPIN_UNLOCKED)
!= STATE_SPIN_UNLOCKED) {
}
return B_OK;
}
}
void
lazy_mutex_unlock(lazy_mutex *lock)
{
if (atomic_add(&lock->benaphore, -1) == 1)
return;
if (lazy_mutex_ensure_init(lock)) {
// release the semaphore
release_sem(lock->semaphore);
} else {
// the semaphore creation failed -- so we use it like a spinlock instead
atomic_set((vint32*)&lock->semaphore, STATE_SPIN_UNLOCKED);
}
}
// #pragma mark - R/W lock