1813d4cbeSIngo Weinhold /* 29dd4d2ddSJé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> { 27402b4156SAugustin Cavalier phys_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 { 35402b4156SAugustin Cavalier typedef phys_addr_t KeyType; 36813d4cbeSIngo Weinhold typedef UserMutexEntry ValueType; 37813d4cbeSIngo Weinhold 389686d931SAugustin Cavalier size_t HashKey(phys_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 48402b4156SAugustin Cavalier bool Compare(phys_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 66cf1b26a9SAugustin Cavalier // #pragma mark - user atomics 67cf1b26a9SAugustin Cavalier 68cf1b26a9SAugustin Cavalier 69cf1b26a9SAugustin Cavalier static int32 70cf1b26a9SAugustin Cavalier user_atomic_or(int32* value, int32 orValue) 71cf1b26a9SAugustin Cavalier { 72cf1b26a9SAugustin Cavalier set_ac(); 73cf1b26a9SAugustin Cavalier int32 result = atomic_or(value, orValue); 74cf1b26a9SAugustin Cavalier clear_ac(); 75cf1b26a9SAugustin Cavalier return result; 76cf1b26a9SAugustin Cavalier } 77cf1b26a9SAugustin Cavalier 78cf1b26a9SAugustin Cavalier 79cf1b26a9SAugustin Cavalier static int32 80cf1b26a9SAugustin Cavalier user_atomic_and(int32* value, int32 orValue) 81cf1b26a9SAugustin Cavalier { 82cf1b26a9SAugustin Cavalier set_ac(); 83cf1b26a9SAugustin Cavalier int32 result = atomic_and(value, orValue); 84cf1b26a9SAugustin Cavalier clear_ac(); 85cf1b26a9SAugustin Cavalier return result; 86cf1b26a9SAugustin Cavalier } 87cf1b26a9SAugustin Cavalier 88cf1b26a9SAugustin Cavalier 89cf1b26a9SAugustin Cavalier static int32 90cf1b26a9SAugustin Cavalier user_atomic_get(int32* value) 91cf1b26a9SAugustin Cavalier { 92cf1b26a9SAugustin Cavalier set_ac(); 93cf1b26a9SAugustin Cavalier int32 result = atomic_get(value); 94cf1b26a9SAugustin Cavalier clear_ac(); 95cf1b26a9SAugustin Cavalier return result; 96cf1b26a9SAugustin Cavalier } 97cf1b26a9SAugustin Cavalier 98cf1b26a9SAugustin Cavalier 99cf1b26a9SAugustin Cavalier static int32 100cf1b26a9SAugustin Cavalier user_atomic_test_and_set(int32* value, int32 newValue, int32 testAgainst) 101cf1b26a9SAugustin Cavalier { 102cf1b26a9SAugustin Cavalier set_ac(); 103cf1b26a9SAugustin Cavalier int32 result = atomic_test_and_set(value, newValue, testAgainst); 104cf1b26a9SAugustin Cavalier clear_ac(); 105cf1b26a9SAugustin Cavalier return result; 106cf1b26a9SAugustin Cavalier } 107cf1b26a9SAugustin Cavalier 108cf1b26a9SAugustin Cavalier 109cf1b26a9SAugustin Cavalier // #pragma mark - user mutex entries 110cf1b26a9SAugustin Cavalier 111cf1b26a9SAugustin Cavalier 112813d4cbeSIngo Weinhold static void 113813d4cbeSIngo Weinhold add_user_mutex_entry(UserMutexEntry* entry) 114813d4cbeSIngo Weinhold { 115813d4cbeSIngo Weinhold UserMutexEntry* firstEntry = sUserMutexTable.Lookup(entry->address); 116813d4cbeSIngo Weinhold if (firstEntry != NULL) 117813d4cbeSIngo Weinhold firstEntry->otherEntries.Add(entry); 118813d4cbeSIngo Weinhold else 119813d4cbeSIngo Weinhold sUserMutexTable.Insert(entry); 120813d4cbeSIngo Weinhold } 121813d4cbeSIngo Weinhold 122813d4cbeSIngo Weinhold 123813d4cbeSIngo Weinhold static bool 124813d4cbeSIngo Weinhold remove_user_mutex_entry(UserMutexEntry* entry) 125813d4cbeSIngo Weinhold { 126813d4cbeSIngo Weinhold UserMutexEntry* firstEntry = sUserMutexTable.Lookup(entry->address); 127813d4cbeSIngo Weinhold if (firstEntry != entry) { 128813d4cbeSIngo Weinhold // The entry is not the first entry in the table. Just remove it from 129813d4cbeSIngo Weinhold // the first entry's list. 130813d4cbeSIngo Weinhold firstEntry->otherEntries.Remove(entry); 131813d4cbeSIngo Weinhold return true; 132813d4cbeSIngo Weinhold } 133813d4cbeSIngo Weinhold 134813d4cbeSIngo Weinhold // The entry is the first entry in the table. Remove it from the table and, 135813d4cbeSIngo Weinhold // if any, add the next entry to the table. 136813d4cbeSIngo Weinhold sUserMutexTable.Remove(entry); 137813d4cbeSIngo Weinhold 1380dffa8d4SIngo Weinhold firstEntry = entry->otherEntries.RemoveHead(); 139813d4cbeSIngo Weinhold if (firstEntry != NULL) { 140813d4cbeSIngo Weinhold firstEntry->otherEntries.MoveFrom(&entry->otherEntries); 141813d4cbeSIngo Weinhold sUserMutexTable.Insert(firstEntry); 142813d4cbeSIngo Weinhold return true; 143813d4cbeSIngo Weinhold } 144813d4cbeSIngo Weinhold 145813d4cbeSIngo Weinhold return false; 146813d4cbeSIngo Weinhold } 147813d4cbeSIngo Weinhold 148813d4cbeSIngo Weinhold 149813d4cbeSIngo Weinhold static status_t 150402b4156SAugustin Cavalier user_mutex_wait_locked(int32* mutex, phys_addr_t physicalAddress, const char* name, 151d6d439f3SHamish Morrison uint32 flags, bigtime_t timeout, MutexLocker& locker, bool& lastWaiter) 152813d4cbeSIngo Weinhold { 153813d4cbeSIngo Weinhold // add the entry to the table 154813d4cbeSIngo Weinhold UserMutexEntry entry; 155813d4cbeSIngo Weinhold entry.address = physicalAddress; 156813d4cbeSIngo Weinhold entry.locked = false; 157813d4cbeSIngo Weinhold add_user_mutex_entry(&entry); 158813d4cbeSIngo Weinhold 159813d4cbeSIngo Weinhold // wait 160813d4cbeSIngo Weinhold entry.condition.Init((void*)physicalAddress, "user mutex"); 1618f68daedSAugustin Cavalier status_t error = entry.condition.Wait(locker.Get(), flags, timeout); 162813d4cbeSIngo Weinhold 163d6d439f3SHamish Morrison if (error != B_OK && entry.locked) 164d6d439f3SHamish Morrison error = B_OK; 165d6d439f3SHamish Morrison 166d6d439f3SHamish Morrison if (!entry.locked) { 167d6d439f3SHamish Morrison // if nobody woke us up, we have to dequeue ourselves 168d6d439f3SHamish Morrison lastWaiter = !remove_user_mutex_entry(&entry); 169d6d439f3SHamish Morrison } else { 170d6d439f3SHamish Morrison // otherwise the waker has done the work of marking the 171d6d439f3SHamish Morrison // mutex or semaphore uncontended 172d6d439f3SHamish Morrison lastWaiter = false; 173813d4cbeSIngo Weinhold } 174813d4cbeSIngo Weinhold 175d6d439f3SHamish Morrison return error; 176813d4cbeSIngo Weinhold } 177813d4cbeSIngo Weinhold 178d6d439f3SHamish Morrison 179d6d439f3SHamish Morrison static status_t 180402b4156SAugustin Cavalier user_mutex_lock_locked(int32* mutex, phys_addr_t physicalAddress, 181d6d439f3SHamish Morrison const char* name, uint32 flags, bigtime_t timeout, MutexLocker& locker) 182d6d439f3SHamish Morrison { 183cf1b26a9SAugustin Cavalier int32 oldValue = user_atomic_or(mutex, 184d6d439f3SHamish Morrison B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING); 185*6f3f29c7SAugustin Cavalier if ((oldValue & B_USER_MUTEX_LOCKED) == 0 186d6d439f3SHamish Morrison || (oldValue & B_USER_MUTEX_DISABLED) != 0) { 187d6d439f3SHamish Morrison // clear the waiting flag and be done 188*6f3f29c7SAugustin Cavalier if ((oldValue & B_USER_MUTEX_WAITING) == 0) 189cf1b26a9SAugustin Cavalier user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 190d6d439f3SHamish Morrison return B_OK; 191d6d439f3SHamish Morrison } 192d6d439f3SHamish Morrison 193d6d439f3SHamish Morrison bool lastWaiter; 194d6d439f3SHamish Morrison status_t error = user_mutex_wait_locked(mutex, physicalAddress, name, 195d6d439f3SHamish Morrison flags, timeout, locker, lastWaiter); 196d6d439f3SHamish Morrison 197*6f3f29c7SAugustin Cavalier if (lastWaiter) 198cf1b26a9SAugustin Cavalier user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 199d6d439f3SHamish Morrison 200813d4cbeSIngo Weinhold return error; 201813d4cbeSIngo Weinhold } 202813d4cbeSIngo Weinhold 203813d4cbeSIngo Weinhold 204813d4cbeSIngo Weinhold static void 205*6f3f29c7SAugustin Cavalier user_mutex_unblock_locked(int32* mutex, phys_addr_t physicalAddress, uint32 flags) 206813d4cbeSIngo Weinhold { 207fb67dbf0SHamish Morrison UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress); 208fb67dbf0SHamish Morrison if (entry == NULL) { 209*6f3f29c7SAugustin Cavalier // no one is waiting 210*6f3f29c7SAugustin Cavalier user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 211fb67dbf0SHamish Morrison return; 212fb67dbf0SHamish Morrison } 213fb67dbf0SHamish Morrison 214*6f3f29c7SAugustin Cavalier // Someone is waiting: try to hand off the lock to them, if possible. 215cf1b26a9SAugustin Cavalier int32 oldValue = user_atomic_or(mutex, B_USER_MUTEX_LOCKED); 216*6f3f29c7SAugustin Cavalier if ((oldValue & B_USER_MUTEX_LOCKED) != 0) 217*6f3f29c7SAugustin Cavalier return; 2180dffa8d4SIngo Weinhold 219813d4cbeSIngo Weinhold // unblock the first thread 220813d4cbeSIngo Weinhold entry->locked = true; 221813d4cbeSIngo Weinhold entry->condition.NotifyOne(); 222813d4cbeSIngo Weinhold 223813d4cbeSIngo Weinhold if ((flags & B_USER_MUTEX_UNBLOCK_ALL) != 0 2240dffa8d4SIngo Weinhold || (oldValue & B_USER_MUTEX_DISABLED) != 0) { 225fb67dbf0SHamish Morrison // unblock and dequeue all the other waiting threads as well 226fb67dbf0SHamish Morrison while (UserMutexEntry* otherEntry = entry->otherEntries.RemoveHead()) { 227813d4cbeSIngo Weinhold otherEntry->locked = true; 228813d4cbeSIngo Weinhold otherEntry->condition.NotifyOne(); 229813d4cbeSIngo Weinhold } 230fb67dbf0SHamish Morrison 231fb67dbf0SHamish Morrison // dequeue the first thread and mark the mutex uncontended 232fb67dbf0SHamish Morrison sUserMutexTable.Remove(entry); 233cf1b26a9SAugustin Cavalier user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 2340dffa8d4SIngo Weinhold } else { 235fb67dbf0SHamish Morrison bool otherWaiters = remove_user_mutex_entry(entry); 2369dd4d2ddSJérôme Duval if (!otherWaiters) { 237cf1b26a9SAugustin Cavalier user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 2389dd4d2ddSJérôme Duval } 239813d4cbeSIngo Weinhold } 240813d4cbeSIngo Weinhold } 241813d4cbeSIngo Weinhold 242813d4cbeSIngo Weinhold 243813d4cbeSIngo Weinhold static status_t 244402b4156SAugustin Cavalier user_mutex_sem_acquire_locked(int32* sem, phys_addr_t physicalAddress, 245d6d439f3SHamish Morrison const char* name, uint32 flags, bigtime_t timeout, MutexLocker& locker) 246d6d439f3SHamish Morrison { 247d6d439f3SHamish Morrison // The semaphore may have been released in the meantime, and we also 248d6d439f3SHamish Morrison // need to mark it as contended if it isn't already. 249cf1b26a9SAugustin Cavalier int32 oldValue = user_atomic_get(sem); 250d6d439f3SHamish Morrison while (oldValue > -1) { 251cf1b26a9SAugustin Cavalier int32 value = user_atomic_test_and_set(sem, oldValue - 1, oldValue); 252d6d439f3SHamish Morrison if (value == oldValue && value > 0) 253d6d439f3SHamish Morrison return B_OK; 254d6d439f3SHamish Morrison oldValue = value; 255d6d439f3SHamish Morrison } 256d6d439f3SHamish Morrison 257d6d439f3SHamish Morrison bool lastWaiter; 258d6d439f3SHamish Morrison status_t error = user_mutex_wait_locked(sem, physicalAddress, name, flags, 259d6d439f3SHamish Morrison timeout, locker, lastWaiter); 260d6d439f3SHamish Morrison 261cf1b26a9SAugustin Cavalier if (lastWaiter) 262cf1b26a9SAugustin Cavalier user_atomic_test_and_set(sem, 0, -1); 263d6d439f3SHamish Morrison 264d6d439f3SHamish Morrison return error; 265d6d439f3SHamish Morrison } 266d6d439f3SHamish Morrison 267d6d439f3SHamish Morrison 268d6d439f3SHamish Morrison static void 269402b4156SAugustin Cavalier user_mutex_sem_release_locked(int32* sem, phys_addr_t physicalAddress) 270d6d439f3SHamish Morrison { 271d6d439f3SHamish Morrison UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress); 272d6d439f3SHamish Morrison if (!entry) { 273d6d439f3SHamish Morrison // no waiters - mark as uncontended and release 274cf1b26a9SAugustin Cavalier int32 oldValue = user_atomic_get(sem); 275d6d439f3SHamish Morrison while (true) { 276d6d439f3SHamish Morrison int32 inc = oldValue < 0 ? 2 : 1; 277cf1b26a9SAugustin Cavalier int32 value = user_atomic_test_and_set(sem, oldValue + inc, oldValue); 278d6d439f3SHamish Morrison if (value == oldValue) 279d6d439f3SHamish Morrison return; 280d6d439f3SHamish Morrison oldValue = value; 281d6d439f3SHamish Morrison } 282d6d439f3SHamish Morrison } 283d6d439f3SHamish Morrison 284d6d439f3SHamish Morrison bool otherWaiters = remove_user_mutex_entry(entry); 285d6d439f3SHamish Morrison 286d6d439f3SHamish Morrison entry->locked = true; 287d6d439f3SHamish Morrison entry->condition.NotifyOne(); 288d6d439f3SHamish Morrison 289d6d439f3SHamish Morrison if (!otherWaiters) { 290d6d439f3SHamish Morrison // mark the semaphore uncontended 291cf1b26a9SAugustin Cavalier user_atomic_test_and_set(sem, 0, -1); 292d6d439f3SHamish Morrison } 293d6d439f3SHamish Morrison } 294d6d439f3SHamish Morrison 295d6d439f3SHamish Morrison 296d6d439f3SHamish Morrison static status_t 297813d4cbeSIngo Weinhold user_mutex_lock(int32* mutex, const char* name, uint32 flags, bigtime_t timeout) 298813d4cbeSIngo Weinhold { 299813d4cbeSIngo Weinhold // wire the page and get the physical address 300813d4cbeSIngo Weinhold VMPageWiringInfo wiringInfo; 301813d4cbeSIngo Weinhold status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)mutex, true, 302813d4cbeSIngo Weinhold &wiringInfo); 303813d4cbeSIngo Weinhold if (error != B_OK) 304813d4cbeSIngo Weinhold return error; 305813d4cbeSIngo Weinhold 306813d4cbeSIngo Weinhold // get the lock 307813d4cbeSIngo Weinhold { 308813d4cbeSIngo Weinhold MutexLocker locker(sUserMutexTableLock); 309813d4cbeSIngo Weinhold error = user_mutex_lock_locked(mutex, wiringInfo.physicalAddress, name, 310813d4cbeSIngo Weinhold flags, timeout, locker); 311813d4cbeSIngo Weinhold } 312813d4cbeSIngo Weinhold 313813d4cbeSIngo Weinhold // unwire the page 314813d4cbeSIngo Weinhold vm_unwire_page(&wiringInfo); 315813d4cbeSIngo Weinhold 316813d4cbeSIngo Weinhold return error; 317813d4cbeSIngo Weinhold } 318813d4cbeSIngo Weinhold 319813d4cbeSIngo Weinhold 320813d4cbeSIngo Weinhold static status_t 321813d4cbeSIngo Weinhold user_mutex_switch_lock(int32* fromMutex, int32* toMutex, const char* name, 322813d4cbeSIngo Weinhold uint32 flags, bigtime_t timeout) 323813d4cbeSIngo Weinhold { 324813d4cbeSIngo Weinhold // wire the pages and get the physical addresses 325813d4cbeSIngo Weinhold VMPageWiringInfo fromWiringInfo; 326813d4cbeSIngo Weinhold status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)fromMutex, true, 327813d4cbeSIngo Weinhold &fromWiringInfo); 328813d4cbeSIngo Weinhold if (error != B_OK) 329813d4cbeSIngo Weinhold return error; 330813d4cbeSIngo Weinhold 331813d4cbeSIngo Weinhold VMPageWiringInfo toWiringInfo; 332813d4cbeSIngo Weinhold error = vm_wire_page(B_CURRENT_TEAM, (addr_t)toMutex, true, &toWiringInfo); 333813d4cbeSIngo Weinhold if (error != B_OK) { 334813d4cbeSIngo Weinhold vm_unwire_page(&fromWiringInfo); 335813d4cbeSIngo Weinhold return error; 336813d4cbeSIngo Weinhold } 337813d4cbeSIngo Weinhold 338813d4cbeSIngo Weinhold // unlock the first mutex and lock the second one 339813d4cbeSIngo Weinhold { 340813d4cbeSIngo Weinhold MutexLocker locker(sUserMutexTableLock); 341*6f3f29c7SAugustin Cavalier user_atomic_and(fromMutex, ~(int32)B_USER_MUTEX_LOCKED); 342*6f3f29c7SAugustin Cavalier user_mutex_unblock_locked(fromMutex, fromWiringInfo.physicalAddress, 343813d4cbeSIngo Weinhold flags); 344813d4cbeSIngo Weinhold 345813d4cbeSIngo Weinhold error = user_mutex_lock_locked(toMutex, toWiringInfo.physicalAddress, 346813d4cbeSIngo Weinhold name, flags, timeout, locker); 347813d4cbeSIngo Weinhold } 348813d4cbeSIngo Weinhold 349813d4cbeSIngo Weinhold // unwire the pages 350813d4cbeSIngo Weinhold vm_unwire_page(&toWiringInfo); 351813d4cbeSIngo Weinhold vm_unwire_page(&fromWiringInfo); 352813d4cbeSIngo Weinhold 353813d4cbeSIngo Weinhold return error; 354813d4cbeSIngo Weinhold } 355813d4cbeSIngo Weinhold 356813d4cbeSIngo Weinhold 357813d4cbeSIngo Weinhold // #pragma mark - kernel private 358813d4cbeSIngo Weinhold 359813d4cbeSIngo Weinhold 360813d4cbeSIngo Weinhold void 361813d4cbeSIngo Weinhold user_mutex_init() 362813d4cbeSIngo Weinhold { 363813d4cbeSIngo Weinhold if (sUserMutexTable.Init() != B_OK) 364813d4cbeSIngo Weinhold panic("user_mutex_init(): Failed to init table!"); 365813d4cbeSIngo Weinhold } 366813d4cbeSIngo Weinhold 367813d4cbeSIngo Weinhold 368813d4cbeSIngo Weinhold // #pragma mark - syscalls 369813d4cbeSIngo Weinhold 370813d4cbeSIngo Weinhold 371813d4cbeSIngo Weinhold status_t 372813d4cbeSIngo Weinhold _user_mutex_lock(int32* mutex, const char* name, uint32 flags, 373813d4cbeSIngo Weinhold bigtime_t timeout) 374813d4cbeSIngo Weinhold { 375813d4cbeSIngo Weinhold if (mutex == NULL || !IS_USER_ADDRESS(mutex) || (addr_t)mutex % 4 != 0) 376813d4cbeSIngo Weinhold return B_BAD_ADDRESS; 377813d4cbeSIngo Weinhold 378813d4cbeSIngo Weinhold syscall_restart_handle_timeout_pre(flags, timeout); 379813d4cbeSIngo Weinhold 380813d4cbeSIngo Weinhold status_t error = user_mutex_lock(mutex, name, flags | B_CAN_INTERRUPT, 381813d4cbeSIngo Weinhold timeout); 382813d4cbeSIngo Weinhold 383813d4cbeSIngo Weinhold return syscall_restart_handle_timeout_post(error, timeout); 384813d4cbeSIngo Weinhold } 385813d4cbeSIngo Weinhold 386813d4cbeSIngo Weinhold 387813d4cbeSIngo Weinhold status_t 388*6f3f29c7SAugustin Cavalier _user_mutex_unblock(int32* mutex, uint32 flags) 389813d4cbeSIngo Weinhold { 390813d4cbeSIngo Weinhold if (mutex == NULL || !IS_USER_ADDRESS(mutex) || (addr_t)mutex % 4 != 0) 391813d4cbeSIngo Weinhold return B_BAD_ADDRESS; 392813d4cbeSIngo Weinhold 393813d4cbeSIngo Weinhold // wire the page and get the physical address 394813d4cbeSIngo Weinhold VMPageWiringInfo wiringInfo; 395813d4cbeSIngo Weinhold status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)mutex, true, 396813d4cbeSIngo Weinhold &wiringInfo); 397813d4cbeSIngo Weinhold if (error != B_OK) 398813d4cbeSIngo Weinhold return error; 399813d4cbeSIngo Weinhold 400813d4cbeSIngo Weinhold { 401813d4cbeSIngo Weinhold MutexLocker locker(sUserMutexTableLock); 402*6f3f29c7SAugustin Cavalier user_mutex_unblock_locked(mutex, wiringInfo.physicalAddress, flags); 403813d4cbeSIngo Weinhold } 404813d4cbeSIngo Weinhold 405813d4cbeSIngo Weinhold vm_unwire_page(&wiringInfo); 406813d4cbeSIngo Weinhold 407813d4cbeSIngo Weinhold return B_OK; 408813d4cbeSIngo Weinhold } 409813d4cbeSIngo Weinhold 410813d4cbeSIngo Weinhold 411813d4cbeSIngo Weinhold status_t 412813d4cbeSIngo Weinhold _user_mutex_switch_lock(int32* fromMutex, int32* toMutex, const char* name, 413813d4cbeSIngo Weinhold uint32 flags, bigtime_t timeout) 414813d4cbeSIngo Weinhold { 415813d4cbeSIngo Weinhold if (fromMutex == NULL || !IS_USER_ADDRESS(fromMutex) 416813d4cbeSIngo Weinhold || (addr_t)fromMutex % 4 != 0 || toMutex == NULL 417813d4cbeSIngo Weinhold || !IS_USER_ADDRESS(toMutex) || (addr_t)toMutex % 4 != 0) { 418813d4cbeSIngo Weinhold return B_BAD_ADDRESS; 419813d4cbeSIngo Weinhold } 420813d4cbeSIngo Weinhold 4210dffa8d4SIngo Weinhold return user_mutex_switch_lock(fromMutex, toMutex, name, 422813d4cbeSIngo Weinhold flags | B_CAN_INTERRUPT, timeout); 423813d4cbeSIngo Weinhold } 424d6d439f3SHamish Morrison 425d6d439f3SHamish Morrison 426d6d439f3SHamish Morrison status_t 427d6d439f3SHamish Morrison _user_mutex_sem_acquire(int32* sem, const char* name, uint32 flags, 428d6d439f3SHamish Morrison bigtime_t timeout) 429d6d439f3SHamish Morrison { 430d6d439f3SHamish Morrison if (sem == NULL || !IS_USER_ADDRESS(sem) || (addr_t)sem % 4 != 0) 431d6d439f3SHamish Morrison return B_BAD_ADDRESS; 432d6d439f3SHamish Morrison 433d6d439f3SHamish Morrison syscall_restart_handle_timeout_pre(flags, timeout); 434d6d439f3SHamish Morrison 435d6d439f3SHamish Morrison // wire the page and get the physical address 436d6d439f3SHamish Morrison VMPageWiringInfo wiringInfo; 437d6d439f3SHamish Morrison status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)sem, true, 438d6d439f3SHamish Morrison &wiringInfo); 439d6d439f3SHamish Morrison if (error != B_OK) 440d6d439f3SHamish Morrison return error; 441d6d439f3SHamish Morrison 442d6d439f3SHamish Morrison { 443d6d439f3SHamish Morrison MutexLocker locker(sUserMutexTableLock); 444d6d439f3SHamish Morrison error = user_mutex_sem_acquire_locked(sem, wiringInfo.physicalAddress, 445d6d439f3SHamish Morrison name, flags | B_CAN_INTERRUPT, timeout, locker); 446d6d439f3SHamish Morrison } 447d6d439f3SHamish Morrison 448d6d439f3SHamish Morrison vm_unwire_page(&wiringInfo); 449d6d439f3SHamish Morrison return syscall_restart_handle_timeout_post(error, timeout); 450d6d439f3SHamish Morrison } 451d6d439f3SHamish Morrison 452d6d439f3SHamish Morrison 453d6d439f3SHamish Morrison status_t 454d6d439f3SHamish Morrison _user_mutex_sem_release(int32* sem) 455d6d439f3SHamish Morrison { 456d6d439f3SHamish Morrison if (sem == NULL || !IS_USER_ADDRESS(sem) || (addr_t)sem % 4 != 0) 457d6d439f3SHamish Morrison return B_BAD_ADDRESS; 458d6d439f3SHamish Morrison 459d6d439f3SHamish Morrison // wire the page and get the physical address 460d6d439f3SHamish Morrison VMPageWiringInfo wiringInfo; 461d6d439f3SHamish Morrison status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)sem, true, 462d6d439f3SHamish Morrison &wiringInfo); 463d6d439f3SHamish Morrison if (error != B_OK) 464d6d439f3SHamish Morrison return error; 465d6d439f3SHamish Morrison 466d6d439f3SHamish Morrison { 467d6d439f3SHamish Morrison MutexLocker locker(sUserMutexTableLock); 468d6d439f3SHamish Morrison user_mutex_sem_release_locked(sem, wiringInfo.physicalAddress); 469d6d439f3SHamish Morrison } 470d6d439f3SHamish Morrison 471d6d439f3SHamish Morrison vm_unwire_page(&wiringInfo); 472d6d439f3SHamish Morrison return B_OK; 473d6d439f3SHamish Morrison } 474