1258b34c5SIngo Weinhold /* 2258b34c5SIngo Weinhold * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. 3f7127458SIngo Weinhold * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 4258b34c5SIngo Weinhold * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 5258b34c5SIngo Weinhold * Distributed under the terms of the MIT License. 6258b34c5SIngo Weinhold * 7258b34c5SIngo Weinhold * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 8258b34c5SIngo Weinhold * Distributed under the terms of the NewOS License. 9258b34c5SIngo Weinhold */ 10258b34c5SIngo Weinhold 11258b34c5SIngo Weinhold 12258b34c5SIngo Weinhold #include <locks.h> 13258b34c5SIngo Weinhold 14f7127458SIngo Weinhold #include <stdlib.h> 15f7127458SIngo Weinhold #include <string.h> 16f7127458SIngo Weinhold 17f7127458SIngo Weinhold #include <syscalls.h> 18f7127458SIngo Weinhold #include <user_mutex_defs.h> 19258b34c5SIngo Weinhold 20258b34c5SIngo Weinhold 217e1c4534SPawel Dziepak #define MAX_UNSUCCESSFUL_SPINS 100 227e1c4534SPawel Dziepak 237e1c4534SPawel Dziepak 247e1c4534SPawel Dziepak extern int32 __gCPUCount; 257e1c4534SPawel Dziepak 267e1c4534SPawel Dziepak 27258b34c5SIngo Weinhold // #pragma mark - mutex 28258b34c5SIngo Weinhold 29258b34c5SIngo Weinhold 30f7127458SIngo Weinhold void 31*b916156aSJulian Harnath __mutex_init(mutex *lock, const char *name) 32258b34c5SIngo Weinhold { 33f7127458SIngo Weinhold lock->name = name; 34f7127458SIngo Weinhold lock->lock = 0; 35f7127458SIngo Weinhold lock->flags = 0; 36f7127458SIngo Weinhold } 37258b34c5SIngo Weinhold 38258b34c5SIngo Weinhold 39f7127458SIngo Weinhold void 40*b916156aSJulian Harnath __mutex_init_etc(mutex *lock, const char *name, uint32 flags) 41f7127458SIngo Weinhold { 42f7127458SIngo Weinhold lock->name = (flags & MUTEX_FLAG_CLONE_NAME) != 0 ? strdup(name) : name; 43f7127458SIngo Weinhold lock->lock = 0; 44f7127458SIngo Weinhold lock->flags = flags; 457e1c4534SPawel Dziepak 467e1c4534SPawel Dziepak if (__gCPUCount < 2) 477e1c4534SPawel Dziepak lock->flags &= ~uint32(MUTEX_FLAG_ADAPTIVE); 48258b34c5SIngo Weinhold } 49258b34c5SIngo Weinhold 50258b34c5SIngo Weinhold 51258b34c5SIngo Weinhold void 52*b916156aSJulian Harnath __mutex_destroy(mutex *lock) 53258b34c5SIngo Weinhold { 54f7127458SIngo Weinhold if ((lock->flags & MUTEX_FLAG_CLONE_NAME) != 0) 55f7127458SIngo Weinhold free(const_cast<char*>(lock->name)); 56258b34c5SIngo Weinhold } 57258b34c5SIngo Weinhold 58258b34c5SIngo Weinhold 59258b34c5SIngo Weinhold status_t 60*b916156aSJulian Harnath __mutex_lock(mutex *lock) 61258b34c5SIngo Weinhold { 6282727571SPawel Dziepak uint32 count = 0; 637e1c4534SPawel Dziepak const uint32 kMaxCount 647e1c4534SPawel Dziepak = (lock->flags & MUTEX_FLAG_ADAPTIVE) != 0 ? MAX_UNSUCCESSFUL_SPINS : 1; 657e1c4534SPawel Dziepak 667e1c4534SPawel Dziepak int32 oldValue; 677e1c4534SPawel Dziepak do { 68f7127458SIngo Weinhold // set the locked flag 697e1c4534SPawel Dziepak oldValue = atomic_or(&lock->lock, B_USER_MUTEX_LOCKED); 70f7127458SIngo Weinhold 71f7127458SIngo Weinhold if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) == 0 72f7127458SIngo Weinhold || (oldValue & B_USER_MUTEX_DISABLED) != 0) { 73f7127458SIngo Weinhold // No one has the lock or is waiting for it, or the mutex has been 74f7127458SIngo Weinhold // disabled. 75258b34c5SIngo Weinhold return B_OK; 76f7127458SIngo Weinhold } 777e1c4534SPawel Dziepak } while (count++ < kMaxCount && (oldValue & B_USER_MUTEX_WAITING) != 0); 78258b34c5SIngo Weinhold 79f7127458SIngo Weinhold // we have to call the kernel 80f7127458SIngo Weinhold status_t error; 81258b34c5SIngo Weinhold do { 82f7127458SIngo Weinhold error = _kern_mutex_lock(&lock->lock, lock->name, 0, 0); 83f7127458SIngo Weinhold } while (error == B_INTERRUPTED); 84258b34c5SIngo Weinhold 85f7127458SIngo Weinhold return error; 86258b34c5SIngo Weinhold } 87258b34c5SIngo Weinhold 88258b34c5SIngo Weinhold 89258b34c5SIngo Weinhold void 90*b916156aSJulian Harnath __mutex_unlock(mutex *lock) 91258b34c5SIngo Weinhold { 92f7127458SIngo Weinhold // clear the locked flag 93f7127458SIngo Weinhold int32 oldValue = atomic_and(&lock->lock, ~(int32)B_USER_MUTEX_LOCKED); 94f7127458SIngo Weinhold if ((oldValue & B_USER_MUTEX_WAITING) != 0 95f7127458SIngo Weinhold && (oldValue & B_USER_MUTEX_DISABLED) == 0) { 96f7127458SIngo Weinhold _kern_mutex_unlock(&lock->lock, 0); 97258b34c5SIngo Weinhold } 98258b34c5SIngo Weinhold } 99