1 /* 2 * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. 3 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 5 * Distributed under the terms of the MIT License. 6 * 7 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 8 * Distributed under the terms of the NewOS License. 9 */ 10 11 12 #include <locks.h> 13 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include <syscalls.h> 18 #include <user_mutex_defs.h> 19 20 21 #define MAX_UNSUCCESSFUL_SPINS 100 22 23 24 extern int32 __gCPUCount; 25 26 27 // #pragma mark - mutex 28 29 30 void 31 __mutex_init(mutex *lock, const char *name) 32 { 33 lock->name = name; 34 lock->lock = 0; 35 lock->flags = 0; 36 } 37 38 39 void 40 __mutex_init_etc(mutex *lock, const char *name, uint32 flags) 41 { 42 lock->name = (flags & MUTEX_FLAG_CLONE_NAME) != 0 ? strdup(name) : name; 43 lock->lock = 0; 44 lock->flags = flags; 45 46 if (__gCPUCount < 2) 47 lock->flags &= ~uint32(MUTEX_FLAG_ADAPTIVE); 48 } 49 50 51 void 52 __mutex_destroy(mutex *lock) 53 { 54 if ((lock->flags & MUTEX_FLAG_CLONE_NAME) != 0) 55 free(const_cast<char*>(lock->name)); 56 } 57 58 59 status_t 60 __mutex_lock(mutex *lock) 61 { 62 uint32 count = 0; 63 const uint32 kMaxCount 64 = (lock->flags & MUTEX_FLAG_ADAPTIVE) != 0 ? MAX_UNSUCCESSFUL_SPINS : 1; 65 66 int32 oldValue; 67 do { 68 oldValue = atomic_test_and_set(&lock->lock, B_USER_MUTEX_LOCKED, 0); 69 if (oldValue == 0 || (oldValue & B_USER_MUTEX_DISABLED) != 0) 70 return B_OK; 71 } while (count++ < kMaxCount && (oldValue & B_USER_MUTEX_WAITING) != 0); 72 73 // we have to call the kernel 74 status_t error; 75 do { 76 error = _kern_mutex_lock(&lock->lock, lock->name, 0, 0); 77 } while (error == B_INTERRUPTED); 78 79 return error; 80 } 81 82 83 void 84 __mutex_unlock(mutex *lock) 85 { 86 // clear the locked flag 87 int32 oldValue = atomic_and(&lock->lock, ~(int32)B_USER_MUTEX_LOCKED); 88 if ((oldValue & B_USER_MUTEX_WAITING) != 0 89 && (oldValue & B_USER_MUTEX_DISABLED) == 0) { 90 _kern_mutex_unblock(&lock->lock, 0); 91 } 92 93 if ((oldValue & B_USER_MUTEX_LOCKED) == 0) { 94 #if 0 95 debugger("mutex was not actually locked!"); 96 #else 97 // The above happens too often at present (see bug #18451). 98 _kern_debug_output("libroot __mutex_unlock: mutex was not actually locked!\n"); 99 #endif 100 } 101 } 102