1813d4cbeSIngo Weinhold /* 2*9dd4d2ddSJérôme Duval * Copyright 2018, Jérôme Duval, jerome.duval@gmail.com. 3d6d439f3SHamish Morrison * Copyright 2015, Hamish Morrison, hamishm53@gmail.com. 4813d4cbeSIngo Weinhold * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. 5813d4cbeSIngo Weinhold * Distributed under the terms of the MIT License. 6813d4cbeSIngo Weinhold */ 7813d4cbeSIngo Weinhold 8813d4cbeSIngo Weinhold 9813d4cbeSIngo Weinhold #include <user_mutex.h> 10813d4cbeSIngo Weinhold #include <user_mutex_defs.h> 11813d4cbeSIngo Weinhold 12813d4cbeSIngo Weinhold #include <condition_variable.h> 13813d4cbeSIngo Weinhold #include <kernel.h> 14813d4cbeSIngo Weinhold #include <lock.h> 15813d4cbeSIngo Weinhold #include <smp.h> 16813d4cbeSIngo Weinhold #include <syscall_restart.h> 17813d4cbeSIngo Weinhold #include <util/AutoLock.h> 18813d4cbeSIngo Weinhold #include <util/OpenHashTable.h> 19813d4cbeSIngo Weinhold #include <vm/vm.h> 20813d4cbeSIngo Weinhold #include <vm/VMArea.h> 21813d4cbeSIngo Weinhold 22813d4cbeSIngo Weinhold 23813d4cbeSIngo Weinhold struct UserMutexEntry; 24813d4cbeSIngo Weinhold typedef DoublyLinkedList<UserMutexEntry> UserMutexEntryList; 25813d4cbeSIngo Weinhold 26813d4cbeSIngo Weinhold struct UserMutexEntry : public DoublyLinkedListLinkImpl<UserMutexEntry> { 27813d4cbeSIngo Weinhold addr_t address; 28813d4cbeSIngo Weinhold ConditionVariable condition; 29813d4cbeSIngo Weinhold bool locked; 30813d4cbeSIngo Weinhold UserMutexEntryList otherEntries; 31813d4cbeSIngo Weinhold UserMutexEntry* hashNext; 32813d4cbeSIngo Weinhold }; 33813d4cbeSIngo Weinhold 34813d4cbeSIngo Weinhold struct UserMutexHashDefinition { 35813d4cbeSIngo Weinhold typedef addr_t KeyType; 36813d4cbeSIngo Weinhold typedef UserMutexEntry ValueType; 37813d4cbeSIngo Weinhold 38813d4cbeSIngo Weinhold size_t HashKey(addr_t key) const 39813d4cbeSIngo Weinhold { 40813d4cbeSIngo Weinhold return key >> 2; 41813d4cbeSIngo Weinhold } 42813d4cbeSIngo Weinhold 43813d4cbeSIngo Weinhold size_t Hash(const UserMutexEntry* value) const 44813d4cbeSIngo Weinhold { 45813d4cbeSIngo Weinhold return HashKey(value->address); 46813d4cbeSIngo Weinhold } 47813d4cbeSIngo Weinhold 48813d4cbeSIngo Weinhold bool Compare(addr_t key, const UserMutexEntry* value) const 49813d4cbeSIngo Weinhold { 50813d4cbeSIngo Weinhold return value->address == key; 51813d4cbeSIngo Weinhold } 52813d4cbeSIngo Weinhold 53813d4cbeSIngo Weinhold UserMutexEntry*& GetLink(UserMutexEntry* value) const 54813d4cbeSIngo Weinhold { 55813d4cbeSIngo Weinhold return value->hashNext; 56813d4cbeSIngo Weinhold } 57813d4cbeSIngo Weinhold }; 58813d4cbeSIngo Weinhold 59813d4cbeSIngo Weinhold typedef BOpenHashTable<UserMutexHashDefinition> UserMutexTable; 60813d4cbeSIngo Weinhold 61813d4cbeSIngo Weinhold 62813d4cbeSIngo Weinhold static UserMutexTable sUserMutexTable; 63813d4cbeSIngo Weinhold static mutex sUserMutexTableLock = MUTEX_INITIALIZER("user mutex table"); 64813d4cbeSIngo Weinhold 65813d4cbeSIngo Weinhold 66813d4cbeSIngo Weinhold static void 67813d4cbeSIngo Weinhold add_user_mutex_entry(UserMutexEntry* entry) 68813d4cbeSIngo Weinhold { 69813d4cbeSIngo Weinhold UserMutexEntry* firstEntry = sUserMutexTable.Lookup(entry->address); 70813d4cbeSIngo Weinhold if (firstEntry != NULL) 71813d4cbeSIngo Weinhold firstEntry->otherEntries.Add(entry); 72813d4cbeSIngo Weinhold else 73813d4cbeSIngo Weinhold sUserMutexTable.Insert(entry); 74813d4cbeSIngo Weinhold } 75813d4cbeSIngo Weinhold 76813d4cbeSIngo Weinhold 77813d4cbeSIngo Weinhold static bool 78813d4cbeSIngo Weinhold remove_user_mutex_entry(UserMutexEntry* entry) 79813d4cbeSIngo Weinhold { 80813d4cbeSIngo Weinhold UserMutexEntry* firstEntry = sUserMutexTable.Lookup(entry->address); 81813d4cbeSIngo Weinhold if (firstEntry != entry) { 82813d4cbeSIngo Weinhold // The entry is not the first entry in the table. Just remove it from 83813d4cbeSIngo Weinhold // the first entry's list. 84813d4cbeSIngo Weinhold firstEntry->otherEntries.Remove(entry); 85813d4cbeSIngo Weinhold return true; 86813d4cbeSIngo Weinhold } 87813d4cbeSIngo Weinhold 88813d4cbeSIngo Weinhold // The entry is the first entry in the table. Remove it from the table and, 89813d4cbeSIngo Weinhold // if any, add the next entry to the table. 90813d4cbeSIngo Weinhold sUserMutexTable.Remove(entry); 91813d4cbeSIngo Weinhold 920dffa8d4SIngo Weinhold firstEntry = entry->otherEntries.RemoveHead(); 93813d4cbeSIngo Weinhold if (firstEntry != NULL) { 94813d4cbeSIngo Weinhold firstEntry->otherEntries.MoveFrom(&entry->otherEntries); 95813d4cbeSIngo Weinhold sUserMutexTable.Insert(firstEntry); 96813d4cbeSIngo Weinhold return true; 97813d4cbeSIngo Weinhold } 98813d4cbeSIngo Weinhold 99813d4cbeSIngo Weinhold return false; 100813d4cbeSIngo Weinhold } 101813d4cbeSIngo Weinhold 102813d4cbeSIngo Weinhold 103813d4cbeSIngo Weinhold static status_t 104d6d439f3SHamish Morrison user_mutex_wait_locked(int32* mutex, addr_t physicalAddress, const char* name, 105d6d439f3SHamish Morrison uint32 flags, bigtime_t timeout, MutexLocker& locker, bool& lastWaiter) 106813d4cbeSIngo Weinhold { 107813d4cbeSIngo Weinhold // add the entry to the table 108813d4cbeSIngo Weinhold UserMutexEntry entry; 109813d4cbeSIngo Weinhold entry.address = physicalAddress; 110813d4cbeSIngo Weinhold entry.locked = false; 111813d4cbeSIngo Weinhold add_user_mutex_entry(&entry); 112813d4cbeSIngo Weinhold 113813d4cbeSIngo Weinhold // wait 114813d4cbeSIngo Weinhold ConditionVariableEntry waitEntry; 115813d4cbeSIngo Weinhold entry.condition.Init((void*)physicalAddress, "user mutex"); 116813d4cbeSIngo Weinhold entry.condition.Add(&waitEntry); 117813d4cbeSIngo Weinhold 118813d4cbeSIngo Weinhold locker.Unlock(); 119813d4cbeSIngo Weinhold status_t error = waitEntry.Wait(flags, timeout); 120813d4cbeSIngo Weinhold locker.Lock(); 121813d4cbeSIngo Weinhold 122d6d439f3SHamish Morrison if (error != B_OK && entry.locked) 123d6d439f3SHamish Morrison error = B_OK; 124d6d439f3SHamish Morrison 125d6d439f3SHamish Morrison if (!entry.locked) { 126d6d439f3SHamish Morrison // if nobody woke us up, we have to dequeue ourselves 127d6d439f3SHamish Morrison lastWaiter = !remove_user_mutex_entry(&entry); 128d6d439f3SHamish Morrison } else { 129d6d439f3SHamish Morrison // otherwise the waker has done the work of marking the 130d6d439f3SHamish Morrison // mutex or semaphore uncontended 131d6d439f3SHamish Morrison lastWaiter = false; 132813d4cbeSIngo Weinhold } 133813d4cbeSIngo Weinhold 134d6d439f3SHamish Morrison return error; 135813d4cbeSIngo Weinhold } 136813d4cbeSIngo Weinhold 137d6d439f3SHamish Morrison 138d6d439f3SHamish Morrison static status_t 139d6d439f3SHamish Morrison user_mutex_lock_locked(int32* mutex, addr_t physicalAddress, 140d6d439f3SHamish Morrison const char* name, uint32 flags, bigtime_t timeout, MutexLocker& locker) 141d6d439f3SHamish Morrison { 142d6d439f3SHamish Morrison // mark the mutex locked + waiting 143*9dd4d2ddSJérôme Duval set_ac(); 144d6d439f3SHamish Morrison int32 oldValue = atomic_or(mutex, 145d6d439f3SHamish Morrison B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING); 146*9dd4d2ddSJérôme Duval clear_ac(); 147d6d439f3SHamish Morrison 148d6d439f3SHamish Morrison if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) == 0 149d6d439f3SHamish Morrison || (oldValue & B_USER_MUTEX_DISABLED) != 0) { 150d6d439f3SHamish Morrison // clear the waiting flag and be done 151*9dd4d2ddSJérôme Duval set_ac(); 152d6d439f3SHamish Morrison atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 153*9dd4d2ddSJérôme Duval clear_ac(); 154d6d439f3SHamish Morrison return B_OK; 155d6d439f3SHamish Morrison } 156d6d439f3SHamish Morrison 157d6d439f3SHamish Morrison bool lastWaiter; 158d6d439f3SHamish Morrison status_t error = user_mutex_wait_locked(mutex, physicalAddress, name, 159d6d439f3SHamish Morrison flags, timeout, locker, lastWaiter); 160d6d439f3SHamish Morrison 161*9dd4d2ddSJérôme Duval if (lastWaiter) { 162*9dd4d2ddSJérôme Duval set_ac(); 163d6d439f3SHamish Morrison atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 164*9dd4d2ddSJérôme Duval clear_ac(); 165*9dd4d2ddSJérôme Duval } 166d6d439f3SHamish Morrison 167813d4cbeSIngo Weinhold return error; 168813d4cbeSIngo Weinhold } 169813d4cbeSIngo Weinhold 170813d4cbeSIngo Weinhold 171813d4cbeSIngo Weinhold static void 17273ad2473SPawel Dziepak user_mutex_unlock_locked(int32* mutex, addr_t physicalAddress, uint32 flags) 173813d4cbeSIngo Weinhold { 174fb67dbf0SHamish Morrison UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress); 175fb67dbf0SHamish Morrison if (entry == NULL) { 176fb67dbf0SHamish Morrison // no one is waiting -- clear locked flag 177*9dd4d2ddSJérôme Duval set_ac(); 178fb67dbf0SHamish Morrison atomic_and(mutex, ~(int32)B_USER_MUTEX_LOCKED); 179*9dd4d2ddSJérôme Duval clear_ac(); 180fb67dbf0SHamish Morrison return; 181fb67dbf0SHamish Morrison } 182fb67dbf0SHamish Morrison 1830dffa8d4SIngo Weinhold // Someone is waiting -- set the locked flag. It might still be set, 1840dffa8d4SIngo Weinhold // but when using userland atomic operations, the caller will usually 1850dffa8d4SIngo Weinhold // have cleared it already. 186*9dd4d2ddSJérôme Duval set_ac(); 1870dffa8d4SIngo Weinhold int32 oldValue = atomic_or(mutex, B_USER_MUTEX_LOCKED); 188*9dd4d2ddSJérôme Duval clear_ac(); 1890dffa8d4SIngo Weinhold 190813d4cbeSIngo Weinhold // unblock the first thread 191813d4cbeSIngo Weinhold entry->locked = true; 192813d4cbeSIngo Weinhold entry->condition.NotifyOne(); 193813d4cbeSIngo Weinhold 194813d4cbeSIngo Weinhold if ((flags & B_USER_MUTEX_UNBLOCK_ALL) != 0 1950dffa8d4SIngo Weinhold || (oldValue & B_USER_MUTEX_DISABLED) != 0) { 196fb67dbf0SHamish Morrison // unblock and dequeue all the other waiting threads as well 197fb67dbf0SHamish Morrison while (UserMutexEntry* otherEntry = entry->otherEntries.RemoveHead()) { 198813d4cbeSIngo Weinhold otherEntry->locked = true; 199813d4cbeSIngo Weinhold otherEntry->condition.NotifyOne(); 200813d4cbeSIngo Weinhold } 201fb67dbf0SHamish Morrison 202fb67dbf0SHamish Morrison // dequeue the first thread and mark the mutex uncontended 203fb67dbf0SHamish Morrison sUserMutexTable.Remove(entry); 204*9dd4d2ddSJérôme Duval set_ac(); 205fb67dbf0SHamish Morrison atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 206*9dd4d2ddSJérôme Duval clear_ac(); 2070dffa8d4SIngo Weinhold } else { 208fb67dbf0SHamish Morrison bool otherWaiters = remove_user_mutex_entry(entry); 209*9dd4d2ddSJérôme Duval if (!otherWaiters) { 210*9dd4d2ddSJérôme Duval set_ac(); 211fb67dbf0SHamish Morrison atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 212*9dd4d2ddSJérôme Duval clear_ac(); 213*9dd4d2ddSJérôme Duval } 214813d4cbeSIngo Weinhold } 215813d4cbeSIngo Weinhold } 216813d4cbeSIngo Weinhold 217813d4cbeSIngo Weinhold 218813d4cbeSIngo Weinhold static status_t 219d6d439f3SHamish Morrison user_mutex_sem_acquire_locked(int32* sem, addr_t physicalAddress, 220d6d439f3SHamish Morrison const char* name, uint32 flags, bigtime_t timeout, MutexLocker& locker) 221d6d439f3SHamish Morrison { 222d6d439f3SHamish Morrison // The semaphore may have been released in the meantime, and we also 223d6d439f3SHamish Morrison // need to mark it as contended if it isn't already. 224*9dd4d2ddSJérôme Duval set_ac(); 225d6d439f3SHamish Morrison int32 oldValue = atomic_get(sem); 226*9dd4d2ddSJérôme Duval clear_ac(); 227d6d439f3SHamish Morrison while (oldValue > -1) { 228*9dd4d2ddSJérôme Duval set_ac(); 229d6d439f3SHamish Morrison int32 value = atomic_test_and_set(sem, oldValue - 1, oldValue); 230*9dd4d2ddSJérôme Duval clear_ac(); 231d6d439f3SHamish Morrison if (value == oldValue && value > 0) 232d6d439f3SHamish Morrison return B_OK; 233d6d439f3SHamish Morrison oldValue = value; 234d6d439f3SHamish Morrison } 235d6d439f3SHamish Morrison 236d6d439f3SHamish Morrison bool lastWaiter; 237d6d439f3SHamish Morrison status_t error = user_mutex_wait_locked(sem, physicalAddress, name, flags, 238d6d439f3SHamish Morrison timeout, locker, lastWaiter); 239d6d439f3SHamish Morrison 240*9dd4d2ddSJérôme Duval if (lastWaiter) { 241*9dd4d2ddSJérôme Duval set_ac(); 242d6d439f3SHamish Morrison atomic_test_and_set(sem, 0, -1); 243*9dd4d2ddSJérôme Duval clear_ac(); 244*9dd4d2ddSJérôme Duval } 245d6d439f3SHamish Morrison 246d6d439f3SHamish Morrison return error; 247d6d439f3SHamish Morrison } 248d6d439f3SHamish Morrison 249d6d439f3SHamish Morrison 250d6d439f3SHamish Morrison static void 251d6d439f3SHamish Morrison user_mutex_sem_release_locked(int32* sem, addr_t physicalAddress) 252d6d439f3SHamish Morrison { 253d6d439f3SHamish Morrison UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress); 254d6d439f3SHamish Morrison if (!entry) { 255d6d439f3SHamish Morrison // no waiters - mark as uncontended and release 256*9dd4d2ddSJérôme Duval set_ac(); 257d6d439f3SHamish Morrison int32 oldValue = atomic_get(sem); 258*9dd4d2ddSJérôme Duval clear_ac(); 259d6d439f3SHamish Morrison while (true) { 260d6d439f3SHamish Morrison int32 inc = oldValue < 0 ? 2 : 1; 261*9dd4d2ddSJérôme Duval set_ac(); 262d6d439f3SHamish Morrison int32 value = atomic_test_and_set(sem, oldValue + inc, oldValue); 263*9dd4d2ddSJérôme Duval clear_ac(); 264d6d439f3SHamish Morrison if (value == oldValue) 265d6d439f3SHamish Morrison return; 266d6d439f3SHamish Morrison oldValue = value; 267d6d439f3SHamish Morrison } 268d6d439f3SHamish Morrison } 269d6d439f3SHamish Morrison 270d6d439f3SHamish Morrison bool otherWaiters = remove_user_mutex_entry(entry); 271d6d439f3SHamish Morrison 272d6d439f3SHamish Morrison entry->locked = true; 273d6d439f3SHamish Morrison entry->condition.NotifyOne(); 274d6d439f3SHamish Morrison 275d6d439f3SHamish Morrison if (!otherWaiters) { 276d6d439f3SHamish Morrison // mark the semaphore uncontended 277*9dd4d2ddSJérôme Duval set_ac(); 278d6d439f3SHamish Morrison atomic_test_and_set(sem, 0, -1); 279*9dd4d2ddSJérôme Duval clear_ac(); 280d6d439f3SHamish Morrison } 281d6d439f3SHamish Morrison } 282d6d439f3SHamish Morrison 283d6d439f3SHamish Morrison 284d6d439f3SHamish Morrison static status_t 285813d4cbeSIngo Weinhold user_mutex_lock(int32* mutex, const char* name, uint32 flags, bigtime_t timeout) 286813d4cbeSIngo Weinhold { 287813d4cbeSIngo Weinhold // wire the page and get the physical address 288813d4cbeSIngo Weinhold VMPageWiringInfo wiringInfo; 289813d4cbeSIngo Weinhold status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)mutex, true, 290813d4cbeSIngo Weinhold &wiringInfo); 291813d4cbeSIngo Weinhold if (error != B_OK) 292813d4cbeSIngo Weinhold return error; 293813d4cbeSIngo Weinhold 294813d4cbeSIngo Weinhold // get the lock 295813d4cbeSIngo Weinhold { 296813d4cbeSIngo Weinhold MutexLocker locker(sUserMutexTableLock); 297813d4cbeSIngo Weinhold error = user_mutex_lock_locked(mutex, wiringInfo.physicalAddress, name, 298813d4cbeSIngo Weinhold flags, timeout, locker); 299813d4cbeSIngo Weinhold } 300813d4cbeSIngo Weinhold 301813d4cbeSIngo Weinhold // unwire the page 302813d4cbeSIngo Weinhold vm_unwire_page(&wiringInfo); 303813d4cbeSIngo Weinhold 304813d4cbeSIngo Weinhold return error; 305813d4cbeSIngo Weinhold } 306813d4cbeSIngo Weinhold 307813d4cbeSIngo Weinhold 308813d4cbeSIngo Weinhold static status_t 309813d4cbeSIngo Weinhold user_mutex_switch_lock(int32* fromMutex, int32* toMutex, const char* name, 310813d4cbeSIngo Weinhold uint32 flags, bigtime_t timeout) 311813d4cbeSIngo Weinhold { 312813d4cbeSIngo Weinhold // wire the pages and get the physical addresses 313813d4cbeSIngo Weinhold VMPageWiringInfo fromWiringInfo; 314813d4cbeSIngo Weinhold status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)fromMutex, true, 315813d4cbeSIngo Weinhold &fromWiringInfo); 316813d4cbeSIngo Weinhold if (error != B_OK) 317813d4cbeSIngo Weinhold return error; 318813d4cbeSIngo Weinhold 319813d4cbeSIngo Weinhold VMPageWiringInfo toWiringInfo; 320813d4cbeSIngo Weinhold error = vm_wire_page(B_CURRENT_TEAM, (addr_t)toMutex, true, &toWiringInfo); 321813d4cbeSIngo Weinhold if (error != B_OK) { 322813d4cbeSIngo Weinhold vm_unwire_page(&fromWiringInfo); 323813d4cbeSIngo Weinhold return error; 324813d4cbeSIngo Weinhold } 325813d4cbeSIngo Weinhold 326813d4cbeSIngo Weinhold // unlock the first mutex and lock the second one 327813d4cbeSIngo Weinhold { 328813d4cbeSIngo Weinhold MutexLocker locker(sUserMutexTableLock); 329813d4cbeSIngo Weinhold user_mutex_unlock_locked(fromMutex, fromWiringInfo.physicalAddress, 330813d4cbeSIngo Weinhold flags); 331813d4cbeSIngo Weinhold 332813d4cbeSIngo Weinhold error = user_mutex_lock_locked(toMutex, toWiringInfo.physicalAddress, 333813d4cbeSIngo Weinhold name, flags, timeout, locker); 334813d4cbeSIngo Weinhold } 335813d4cbeSIngo Weinhold 336813d4cbeSIngo Weinhold // unwire the pages 337813d4cbeSIngo Weinhold vm_unwire_page(&toWiringInfo); 338813d4cbeSIngo Weinhold vm_unwire_page(&fromWiringInfo); 339813d4cbeSIngo Weinhold 340813d4cbeSIngo Weinhold return error; 341813d4cbeSIngo Weinhold } 342813d4cbeSIngo Weinhold 343813d4cbeSIngo Weinhold 344813d4cbeSIngo Weinhold // #pragma mark - kernel private 345813d4cbeSIngo Weinhold 346813d4cbeSIngo Weinhold 347813d4cbeSIngo Weinhold void 348813d4cbeSIngo Weinhold user_mutex_init() 349813d4cbeSIngo Weinhold { 350813d4cbeSIngo Weinhold if (sUserMutexTable.Init() != B_OK) 351813d4cbeSIngo Weinhold panic("user_mutex_init(): Failed to init table!"); 352813d4cbeSIngo Weinhold } 353813d4cbeSIngo Weinhold 354813d4cbeSIngo Weinhold 355813d4cbeSIngo Weinhold // #pragma mark - syscalls 356813d4cbeSIngo Weinhold 357813d4cbeSIngo Weinhold 358813d4cbeSIngo Weinhold status_t 359813d4cbeSIngo Weinhold _user_mutex_lock(int32* mutex, const char* name, uint32 flags, 360813d4cbeSIngo Weinhold bigtime_t timeout) 361813d4cbeSIngo Weinhold { 362813d4cbeSIngo Weinhold if (mutex == NULL || !IS_USER_ADDRESS(mutex) || (addr_t)mutex % 4 != 0) 363813d4cbeSIngo Weinhold return B_BAD_ADDRESS; 364813d4cbeSIngo Weinhold 365813d4cbeSIngo Weinhold syscall_restart_handle_timeout_pre(flags, timeout); 366813d4cbeSIngo Weinhold 367813d4cbeSIngo Weinhold status_t error = user_mutex_lock(mutex, name, flags | B_CAN_INTERRUPT, 368813d4cbeSIngo Weinhold timeout); 369813d4cbeSIngo Weinhold 370813d4cbeSIngo Weinhold return syscall_restart_handle_timeout_post(error, timeout); 371813d4cbeSIngo Weinhold } 372813d4cbeSIngo Weinhold 373813d4cbeSIngo Weinhold 374813d4cbeSIngo Weinhold status_t 375813d4cbeSIngo Weinhold _user_mutex_unlock(int32* mutex, uint32 flags) 376813d4cbeSIngo Weinhold { 377813d4cbeSIngo Weinhold if (mutex == NULL || !IS_USER_ADDRESS(mutex) || (addr_t)mutex % 4 != 0) 378813d4cbeSIngo Weinhold return B_BAD_ADDRESS; 379813d4cbeSIngo Weinhold 380813d4cbeSIngo Weinhold // wire the page and get the physical address 381813d4cbeSIngo Weinhold VMPageWiringInfo wiringInfo; 382813d4cbeSIngo Weinhold status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)mutex, true, 383813d4cbeSIngo Weinhold &wiringInfo); 384813d4cbeSIngo Weinhold if (error != B_OK) 385813d4cbeSIngo Weinhold return error; 386813d4cbeSIngo Weinhold 387813d4cbeSIngo Weinhold { 388813d4cbeSIngo Weinhold MutexLocker locker(sUserMutexTableLock); 389813d4cbeSIngo Weinhold user_mutex_unlock_locked(mutex, wiringInfo.physicalAddress, flags); 390813d4cbeSIngo Weinhold } 391813d4cbeSIngo Weinhold 392813d4cbeSIngo Weinhold vm_unwire_page(&wiringInfo); 393813d4cbeSIngo Weinhold 394813d4cbeSIngo Weinhold return B_OK; 395813d4cbeSIngo Weinhold } 396813d4cbeSIngo Weinhold 397813d4cbeSIngo Weinhold 398813d4cbeSIngo Weinhold status_t 399813d4cbeSIngo Weinhold _user_mutex_switch_lock(int32* fromMutex, int32* toMutex, const char* name, 400813d4cbeSIngo Weinhold uint32 flags, bigtime_t timeout) 401813d4cbeSIngo Weinhold { 402813d4cbeSIngo Weinhold if (fromMutex == NULL || !IS_USER_ADDRESS(fromMutex) 403813d4cbeSIngo Weinhold || (addr_t)fromMutex % 4 != 0 || toMutex == NULL 404813d4cbeSIngo Weinhold || !IS_USER_ADDRESS(toMutex) || (addr_t)toMutex % 4 != 0) { 405813d4cbeSIngo Weinhold return B_BAD_ADDRESS; 406813d4cbeSIngo Weinhold } 407813d4cbeSIngo Weinhold 4080dffa8d4SIngo Weinhold return user_mutex_switch_lock(fromMutex, toMutex, name, 409813d4cbeSIngo Weinhold flags | B_CAN_INTERRUPT, timeout); 410813d4cbeSIngo Weinhold } 411d6d439f3SHamish Morrison 412d6d439f3SHamish Morrison 413d6d439f3SHamish Morrison status_t 414d6d439f3SHamish Morrison _user_mutex_sem_acquire(int32* sem, const char* name, uint32 flags, 415d6d439f3SHamish Morrison bigtime_t timeout) 416d6d439f3SHamish Morrison { 417d6d439f3SHamish Morrison if (sem == NULL || !IS_USER_ADDRESS(sem) || (addr_t)sem % 4 != 0) 418d6d439f3SHamish Morrison return B_BAD_ADDRESS; 419d6d439f3SHamish Morrison 420d6d439f3SHamish Morrison syscall_restart_handle_timeout_pre(flags, timeout); 421d6d439f3SHamish Morrison 422d6d439f3SHamish Morrison // wire the page and get the physical address 423d6d439f3SHamish Morrison VMPageWiringInfo wiringInfo; 424d6d439f3SHamish Morrison status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)sem, true, 425d6d439f3SHamish Morrison &wiringInfo); 426d6d439f3SHamish Morrison if (error != B_OK) 427d6d439f3SHamish Morrison return error; 428d6d439f3SHamish Morrison 429d6d439f3SHamish Morrison { 430d6d439f3SHamish Morrison MutexLocker locker(sUserMutexTableLock); 431d6d439f3SHamish Morrison error = user_mutex_sem_acquire_locked(sem, wiringInfo.physicalAddress, 432d6d439f3SHamish Morrison name, flags | B_CAN_INTERRUPT, timeout, locker); 433d6d439f3SHamish Morrison } 434d6d439f3SHamish Morrison 435d6d439f3SHamish Morrison vm_unwire_page(&wiringInfo); 436d6d439f3SHamish Morrison return syscall_restart_handle_timeout_post(error, timeout); 437d6d439f3SHamish Morrison } 438d6d439f3SHamish Morrison 439d6d439f3SHamish Morrison 440d6d439f3SHamish Morrison status_t 441d6d439f3SHamish Morrison _user_mutex_sem_release(int32* sem) 442d6d439f3SHamish Morrison { 443d6d439f3SHamish Morrison if (sem == NULL || !IS_USER_ADDRESS(sem) || (addr_t)sem % 4 != 0) 444d6d439f3SHamish Morrison return B_BAD_ADDRESS; 445d6d439f3SHamish Morrison 446d6d439f3SHamish Morrison // wire the page and get the physical address 447d6d439f3SHamish Morrison VMPageWiringInfo wiringInfo; 448d6d439f3SHamish Morrison status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)sem, true, 449d6d439f3SHamish Morrison &wiringInfo); 450d6d439f3SHamish Morrison if (error != B_OK) 451d6d439f3SHamish Morrison return error; 452d6d439f3SHamish Morrison 453d6d439f3SHamish Morrison { 454d6d439f3SHamish Morrison MutexLocker locker(sUserMutexTableLock); 455d6d439f3SHamish Morrison user_mutex_sem_release_locked(sem, wiringInfo.physicalAddress); 456d6d439f3SHamish Morrison } 457d6d439f3SHamish Morrison 458d6d439f3SHamish Morrison vm_unwire_page(&wiringInfo); 459d6d439f3SHamish Morrison return B_OK; 460d6d439f3SHamish Morrison } 461