/* * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. * Distributed under the terms of the NewOS License. */ #include #include #include #include #include #define MAX_UNSUCCESSFUL_SPINS 100 extern int32 __gCPUCount; // #pragma mark - mutex void __mutex_init(mutex *lock, const char *name) { lock->name = name; lock->lock = 0; lock->flags = 0; } void __mutex_init_etc(mutex *lock, const char *name, uint32 flags) { lock->name = (flags & MUTEX_FLAG_CLONE_NAME) != 0 ? strdup(name) : name; lock->lock = 0; lock->flags = flags; if (__gCPUCount < 2) lock->flags &= ~uint32(MUTEX_FLAG_ADAPTIVE); } void __mutex_destroy(mutex *lock) { if ((lock->flags & MUTEX_FLAG_CLONE_NAME) != 0) free(const_cast(lock->name)); } status_t __mutex_lock(mutex *lock) { uint32 count = 0; const uint32 kMaxCount = (lock->flags & MUTEX_FLAG_ADAPTIVE) != 0 ? MAX_UNSUCCESSFUL_SPINS : 1; int32 oldValue; do { oldValue = atomic_test_and_set(&lock->lock, B_USER_MUTEX_LOCKED, 0); if (oldValue == 0 || (oldValue & B_USER_MUTEX_DISABLED) != 0) return B_OK; } while (count++ < kMaxCount && (oldValue & B_USER_MUTEX_WAITING) != 0); // we have to call the kernel status_t error; do { error = _kern_mutex_lock(&lock->lock, lock->name, 0, 0); } while (error == B_INTERRUPTED); return error; } void __mutex_unlock(mutex *lock) { // clear the locked flag int32 oldValue = atomic_and(&lock->lock, ~(int32)B_USER_MUTEX_LOCKED); if ((oldValue & B_USER_MUTEX_WAITING) != 0 && (oldValue & B_USER_MUTEX_DISABLED) == 0) { _kern_mutex_unblock(&lock->lock, 0); } if ((oldValue & B_USER_MUTEX_LOCKED) == 0) { #if 0 debugger("mutex was not actually locked!"); #else // The above happens too often at present (see bug #18451). _kern_debug_output("libroot __mutex_unlock: mutex was not actually locked!\n"); #endif } }