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 179901b48c2SAugustin Cavalier static bool 180901b48c2SAugustin Cavalier user_mutex_prepare_to_lock(int32* mutex) 181d6d439f3SHamish Morrison { 182cf1b26a9SAugustin Cavalier int32 oldValue = user_atomic_or(mutex, 183d6d439f3SHamish Morrison B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING); 1846f3f29c7SAugustin Cavalier if ((oldValue & B_USER_MUTEX_LOCKED) == 0 185d6d439f3SHamish Morrison || (oldValue & B_USER_MUTEX_DISABLED) != 0) { 186d6d439f3SHamish Morrison // clear the waiting flag and be done 1876f3f29c7SAugustin Cavalier if ((oldValue & B_USER_MUTEX_WAITING) == 0) 188cf1b26a9SAugustin Cavalier user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 189901b48c2SAugustin Cavalier return true; 190d6d439f3SHamish Morrison } 191d6d439f3SHamish Morrison 192901b48c2SAugustin Cavalier return false; 193901b48c2SAugustin Cavalier } 194901b48c2SAugustin Cavalier 195901b48c2SAugustin Cavalier 196901b48c2SAugustin Cavalier static status_t 197901b48c2SAugustin Cavalier user_mutex_lock_locked(int32* mutex, phys_addr_t physicalAddress, 198901b48c2SAugustin Cavalier const char* name, uint32 flags, bigtime_t timeout, MutexLocker& locker) 199901b48c2SAugustin Cavalier { 200901b48c2SAugustin Cavalier if (user_mutex_prepare_to_lock(mutex)) 201901b48c2SAugustin Cavalier return B_OK; 202901b48c2SAugustin Cavalier 203d6d439f3SHamish Morrison bool lastWaiter; 204d6d439f3SHamish Morrison status_t error = user_mutex_wait_locked(mutex, physicalAddress, name, 205d6d439f3SHamish Morrison flags, timeout, locker, lastWaiter); 206d6d439f3SHamish Morrison 2076f3f29c7SAugustin Cavalier if (lastWaiter) 208cf1b26a9SAugustin Cavalier user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 209d6d439f3SHamish Morrison 210813d4cbeSIngo Weinhold return error; 211813d4cbeSIngo Weinhold } 212813d4cbeSIngo Weinhold 213813d4cbeSIngo Weinhold 214813d4cbeSIngo Weinhold static void 2156f3f29c7SAugustin Cavalier user_mutex_unblock_locked(int32* mutex, phys_addr_t physicalAddress, uint32 flags) 216813d4cbeSIngo Weinhold { 217fb67dbf0SHamish Morrison UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress); 218fb67dbf0SHamish Morrison if (entry == NULL) { 2196f3f29c7SAugustin Cavalier // no one is waiting 2206f3f29c7SAugustin Cavalier user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 221fb67dbf0SHamish Morrison return; 222fb67dbf0SHamish Morrison } 223fb67dbf0SHamish Morrison 2246f3f29c7SAugustin Cavalier // Someone is waiting: try to hand off the lock to them, if possible. 225*ca458a2bSAugustin Cavalier int32 oldValue = 0; 226*ca458a2bSAugustin Cavalier if ((flags & B_USER_MUTEX_UNBLOCK_ALL) == 0) { 227*ca458a2bSAugustin Cavalier oldValue = user_atomic_or(mutex, B_USER_MUTEX_LOCKED); 2286f3f29c7SAugustin Cavalier if ((oldValue & B_USER_MUTEX_LOCKED) != 0) 2296f3f29c7SAugustin Cavalier return; 230*ca458a2bSAugustin Cavalier } else { 231*ca458a2bSAugustin Cavalier oldValue = user_atomic_get(mutex); 232*ca458a2bSAugustin Cavalier } 2330dffa8d4SIngo Weinhold 234813d4cbeSIngo Weinhold // unblock the first thread 235813d4cbeSIngo Weinhold entry->locked = true; 236813d4cbeSIngo Weinhold entry->condition.NotifyOne(); 237813d4cbeSIngo Weinhold 238813d4cbeSIngo Weinhold if ((flags & B_USER_MUTEX_UNBLOCK_ALL) != 0 2390dffa8d4SIngo Weinhold || (oldValue & B_USER_MUTEX_DISABLED) != 0) { 240fb67dbf0SHamish Morrison // unblock and dequeue all the other waiting threads as well 241fb67dbf0SHamish Morrison while (UserMutexEntry* otherEntry = entry->otherEntries.RemoveHead()) { 242813d4cbeSIngo Weinhold otherEntry->locked = true; 243813d4cbeSIngo Weinhold otherEntry->condition.NotifyOne(); 244813d4cbeSIngo Weinhold } 245fb67dbf0SHamish Morrison 246fb67dbf0SHamish Morrison // dequeue the first thread and mark the mutex uncontended 247fb67dbf0SHamish Morrison sUserMutexTable.Remove(entry); 248cf1b26a9SAugustin Cavalier user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 2490dffa8d4SIngo Weinhold } else { 250fb67dbf0SHamish Morrison bool otherWaiters = remove_user_mutex_entry(entry); 2519dd4d2ddSJérôme Duval if (!otherWaiters) { 252cf1b26a9SAugustin Cavalier user_atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING); 2539dd4d2ddSJérôme Duval } 254813d4cbeSIngo Weinhold } 255813d4cbeSIngo Weinhold } 256813d4cbeSIngo Weinhold 257813d4cbeSIngo Weinhold 258813d4cbeSIngo Weinhold static status_t 259402b4156SAugustin Cavalier user_mutex_sem_acquire_locked(int32* sem, phys_addr_t physicalAddress, 260d6d439f3SHamish Morrison const char* name, uint32 flags, bigtime_t timeout, MutexLocker& locker) 261d6d439f3SHamish Morrison { 262d6d439f3SHamish Morrison // The semaphore may have been released in the meantime, and we also 263d6d439f3SHamish Morrison // need to mark it as contended if it isn't already. 264cf1b26a9SAugustin Cavalier int32 oldValue = user_atomic_get(sem); 265d6d439f3SHamish Morrison while (oldValue > -1) { 266cf1b26a9SAugustin Cavalier int32 value = user_atomic_test_and_set(sem, oldValue - 1, oldValue); 267d6d439f3SHamish Morrison if (value == oldValue && value > 0) 268d6d439f3SHamish Morrison return B_OK; 269d6d439f3SHamish Morrison oldValue = value; 270d6d439f3SHamish Morrison } 271d6d439f3SHamish Morrison 272d6d439f3SHamish Morrison bool lastWaiter; 273d6d439f3SHamish Morrison status_t error = user_mutex_wait_locked(sem, physicalAddress, name, flags, 274d6d439f3SHamish Morrison timeout, locker, lastWaiter); 275d6d439f3SHamish Morrison 276cf1b26a9SAugustin Cavalier if (lastWaiter) 277cf1b26a9SAugustin Cavalier user_atomic_test_and_set(sem, 0, -1); 278d6d439f3SHamish Morrison 279d6d439f3SHamish Morrison return error; 280d6d439f3SHamish Morrison } 281d6d439f3SHamish Morrison 282d6d439f3SHamish Morrison 283d6d439f3SHamish Morrison static void 284402b4156SAugustin Cavalier user_mutex_sem_release_locked(int32* sem, phys_addr_t physicalAddress) 285d6d439f3SHamish Morrison { 286d6d439f3SHamish Morrison UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress); 287d6d439f3SHamish Morrison if (!entry) { 288d6d439f3SHamish Morrison // no waiters - mark as uncontended and release 289cf1b26a9SAugustin Cavalier int32 oldValue = user_atomic_get(sem); 290d6d439f3SHamish Morrison while (true) { 291d6d439f3SHamish Morrison int32 inc = oldValue < 0 ? 2 : 1; 292cf1b26a9SAugustin Cavalier int32 value = user_atomic_test_and_set(sem, oldValue + inc, oldValue); 293d6d439f3SHamish Morrison if (value == oldValue) 294d6d439f3SHamish Morrison return; 295d6d439f3SHamish Morrison oldValue = value; 296d6d439f3SHamish Morrison } 297d6d439f3SHamish Morrison } 298d6d439f3SHamish Morrison 299d6d439f3SHamish Morrison bool otherWaiters = remove_user_mutex_entry(entry); 300d6d439f3SHamish Morrison 301d6d439f3SHamish Morrison entry->locked = true; 302d6d439f3SHamish Morrison entry->condition.NotifyOne(); 303d6d439f3SHamish Morrison 304d6d439f3SHamish Morrison if (!otherWaiters) { 305d6d439f3SHamish Morrison // mark the semaphore uncontended 306cf1b26a9SAugustin Cavalier user_atomic_test_and_set(sem, 0, -1); 307d6d439f3SHamish Morrison } 308d6d439f3SHamish Morrison } 309d6d439f3SHamish Morrison 310d6d439f3SHamish Morrison 311d6d439f3SHamish Morrison static status_t 312813d4cbeSIngo Weinhold user_mutex_lock(int32* mutex, const char* name, uint32 flags, bigtime_t timeout) 313813d4cbeSIngo Weinhold { 314813d4cbeSIngo Weinhold // wire the page and get the physical address 315813d4cbeSIngo Weinhold VMPageWiringInfo wiringInfo; 316813d4cbeSIngo Weinhold status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)mutex, true, 317813d4cbeSIngo Weinhold &wiringInfo); 318813d4cbeSIngo Weinhold if (error != B_OK) 319813d4cbeSIngo Weinhold return error; 320813d4cbeSIngo Weinhold 321813d4cbeSIngo Weinhold // get the lock 322813d4cbeSIngo Weinhold { 323813d4cbeSIngo Weinhold MutexLocker locker(sUserMutexTableLock); 324813d4cbeSIngo Weinhold error = user_mutex_lock_locked(mutex, wiringInfo.physicalAddress, name, 325813d4cbeSIngo Weinhold flags, timeout, locker); 326813d4cbeSIngo Weinhold } 327813d4cbeSIngo Weinhold 328813d4cbeSIngo Weinhold // unwire the page 329813d4cbeSIngo Weinhold vm_unwire_page(&wiringInfo); 330813d4cbeSIngo Weinhold 331813d4cbeSIngo Weinhold return error; 332813d4cbeSIngo Weinhold } 333813d4cbeSIngo Weinhold 334813d4cbeSIngo Weinhold 335813d4cbeSIngo Weinhold static status_t 336813d4cbeSIngo Weinhold user_mutex_switch_lock(int32* fromMutex, int32* toMutex, const char* name, 337813d4cbeSIngo Weinhold uint32 flags, bigtime_t timeout) 338813d4cbeSIngo Weinhold { 339813d4cbeSIngo Weinhold // wire the pages and get the physical addresses 340813d4cbeSIngo Weinhold VMPageWiringInfo fromWiringInfo; 341813d4cbeSIngo Weinhold status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)fromMutex, true, 342813d4cbeSIngo Weinhold &fromWiringInfo); 343813d4cbeSIngo Weinhold if (error != B_OK) 344813d4cbeSIngo Weinhold return error; 345813d4cbeSIngo Weinhold 346813d4cbeSIngo Weinhold VMPageWiringInfo toWiringInfo; 347813d4cbeSIngo Weinhold error = vm_wire_page(B_CURRENT_TEAM, (addr_t)toMutex, true, &toWiringInfo); 348813d4cbeSIngo Weinhold if (error != B_OK) { 349813d4cbeSIngo Weinhold vm_unwire_page(&fromWiringInfo); 350813d4cbeSIngo Weinhold return error; 351813d4cbeSIngo Weinhold } 352813d4cbeSIngo Weinhold 353813d4cbeSIngo Weinhold // unlock the first mutex and lock the second one 354813d4cbeSIngo Weinhold { 355813d4cbeSIngo Weinhold MutexLocker locker(sUserMutexTableLock); 356901b48c2SAugustin Cavalier 357901b48c2SAugustin Cavalier const bool alreadyLocked = user_mutex_prepare_to_lock(toMutex); 3586f3f29c7SAugustin Cavalier user_atomic_and(fromMutex, ~(int32)B_USER_MUTEX_LOCKED); 3596f3f29c7SAugustin Cavalier user_mutex_unblock_locked(fromMutex, fromWiringInfo.physicalAddress, 360813d4cbeSIngo Weinhold flags); 361813d4cbeSIngo Weinhold 362901b48c2SAugustin Cavalier if (!alreadyLocked) { 363813d4cbeSIngo Weinhold error = user_mutex_lock_locked(toMutex, toWiringInfo.physicalAddress, 364813d4cbeSIngo Weinhold name, flags, timeout, locker); 365813d4cbeSIngo Weinhold } 366901b48c2SAugustin Cavalier } 367813d4cbeSIngo Weinhold 368813d4cbeSIngo Weinhold // unwire the pages 369813d4cbeSIngo Weinhold vm_unwire_page(&toWiringInfo); 370813d4cbeSIngo Weinhold vm_unwire_page(&fromWiringInfo); 371813d4cbeSIngo Weinhold 372813d4cbeSIngo Weinhold return error; 373813d4cbeSIngo Weinhold } 374813d4cbeSIngo Weinhold 375813d4cbeSIngo Weinhold 376813d4cbeSIngo Weinhold // #pragma mark - kernel private 377813d4cbeSIngo Weinhold 378813d4cbeSIngo Weinhold 379813d4cbeSIngo Weinhold void 380813d4cbeSIngo Weinhold user_mutex_init() 381813d4cbeSIngo Weinhold { 382813d4cbeSIngo Weinhold if (sUserMutexTable.Init() != B_OK) 383813d4cbeSIngo Weinhold panic("user_mutex_init(): Failed to init table!"); 384813d4cbeSIngo Weinhold } 385813d4cbeSIngo Weinhold 386813d4cbeSIngo Weinhold 387813d4cbeSIngo Weinhold // #pragma mark - syscalls 388813d4cbeSIngo Weinhold 389813d4cbeSIngo Weinhold 390813d4cbeSIngo Weinhold status_t 391813d4cbeSIngo Weinhold _user_mutex_lock(int32* mutex, const char* name, uint32 flags, 392813d4cbeSIngo Weinhold bigtime_t timeout) 393813d4cbeSIngo Weinhold { 394813d4cbeSIngo Weinhold if (mutex == NULL || !IS_USER_ADDRESS(mutex) || (addr_t)mutex % 4 != 0) 395813d4cbeSIngo Weinhold return B_BAD_ADDRESS; 396813d4cbeSIngo Weinhold 397813d4cbeSIngo Weinhold syscall_restart_handle_timeout_pre(flags, timeout); 398813d4cbeSIngo Weinhold 399813d4cbeSIngo Weinhold status_t error = user_mutex_lock(mutex, name, flags | B_CAN_INTERRUPT, 400813d4cbeSIngo Weinhold timeout); 401813d4cbeSIngo Weinhold 402813d4cbeSIngo Weinhold return syscall_restart_handle_timeout_post(error, timeout); 403813d4cbeSIngo Weinhold } 404813d4cbeSIngo Weinhold 405813d4cbeSIngo Weinhold 406813d4cbeSIngo Weinhold status_t 4076f3f29c7SAugustin Cavalier _user_mutex_unblock(int32* mutex, uint32 flags) 408813d4cbeSIngo Weinhold { 409813d4cbeSIngo Weinhold if (mutex == NULL || !IS_USER_ADDRESS(mutex) || (addr_t)mutex % 4 != 0) 410813d4cbeSIngo Weinhold return B_BAD_ADDRESS; 411813d4cbeSIngo Weinhold 412813d4cbeSIngo Weinhold // wire the page and get the physical address 413813d4cbeSIngo Weinhold VMPageWiringInfo wiringInfo; 414813d4cbeSIngo Weinhold status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)mutex, true, 415813d4cbeSIngo Weinhold &wiringInfo); 416813d4cbeSIngo Weinhold if (error != B_OK) 417813d4cbeSIngo Weinhold return error; 418813d4cbeSIngo Weinhold 419813d4cbeSIngo Weinhold { 420813d4cbeSIngo Weinhold MutexLocker locker(sUserMutexTableLock); 4216f3f29c7SAugustin Cavalier user_mutex_unblock_locked(mutex, wiringInfo.physicalAddress, flags); 422813d4cbeSIngo Weinhold } 423813d4cbeSIngo Weinhold 424813d4cbeSIngo Weinhold vm_unwire_page(&wiringInfo); 425813d4cbeSIngo Weinhold 426813d4cbeSIngo Weinhold return B_OK; 427813d4cbeSIngo Weinhold } 428813d4cbeSIngo Weinhold 429813d4cbeSIngo Weinhold 430813d4cbeSIngo Weinhold status_t 431813d4cbeSIngo Weinhold _user_mutex_switch_lock(int32* fromMutex, int32* toMutex, const char* name, 432813d4cbeSIngo Weinhold uint32 flags, bigtime_t timeout) 433813d4cbeSIngo Weinhold { 434813d4cbeSIngo Weinhold if (fromMutex == NULL || !IS_USER_ADDRESS(fromMutex) 435813d4cbeSIngo Weinhold || (addr_t)fromMutex % 4 != 0 || toMutex == NULL 436813d4cbeSIngo Weinhold || !IS_USER_ADDRESS(toMutex) || (addr_t)toMutex % 4 != 0) { 437813d4cbeSIngo Weinhold return B_BAD_ADDRESS; 438813d4cbeSIngo Weinhold } 439813d4cbeSIngo Weinhold 4400dffa8d4SIngo Weinhold return user_mutex_switch_lock(fromMutex, toMutex, name, 441813d4cbeSIngo Weinhold flags | B_CAN_INTERRUPT, timeout); 442813d4cbeSIngo Weinhold } 443d6d439f3SHamish Morrison 444d6d439f3SHamish Morrison 445d6d439f3SHamish Morrison status_t 446d6d439f3SHamish Morrison _user_mutex_sem_acquire(int32* sem, const char* name, uint32 flags, 447d6d439f3SHamish Morrison bigtime_t timeout) 448d6d439f3SHamish Morrison { 449d6d439f3SHamish Morrison if (sem == NULL || !IS_USER_ADDRESS(sem) || (addr_t)sem % 4 != 0) 450d6d439f3SHamish Morrison return B_BAD_ADDRESS; 451d6d439f3SHamish Morrison 452d6d439f3SHamish Morrison syscall_restart_handle_timeout_pre(flags, timeout); 453d6d439f3SHamish Morrison 454d6d439f3SHamish Morrison // wire the page and get the physical address 455d6d439f3SHamish Morrison VMPageWiringInfo wiringInfo; 456d6d439f3SHamish Morrison status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)sem, true, 457d6d439f3SHamish Morrison &wiringInfo); 458d6d439f3SHamish Morrison if (error != B_OK) 459d6d439f3SHamish Morrison return error; 460d6d439f3SHamish Morrison 461d6d439f3SHamish Morrison { 462d6d439f3SHamish Morrison MutexLocker locker(sUserMutexTableLock); 463d6d439f3SHamish Morrison error = user_mutex_sem_acquire_locked(sem, wiringInfo.physicalAddress, 464d6d439f3SHamish Morrison name, flags | B_CAN_INTERRUPT, timeout, locker); 465d6d439f3SHamish Morrison } 466d6d439f3SHamish Morrison 467d6d439f3SHamish Morrison vm_unwire_page(&wiringInfo); 468d6d439f3SHamish Morrison return syscall_restart_handle_timeout_post(error, timeout); 469d6d439f3SHamish Morrison } 470d6d439f3SHamish Morrison 471d6d439f3SHamish Morrison 472d6d439f3SHamish Morrison status_t 473d6d439f3SHamish Morrison _user_mutex_sem_release(int32* sem) 474d6d439f3SHamish Morrison { 475d6d439f3SHamish Morrison if (sem == NULL || !IS_USER_ADDRESS(sem) || (addr_t)sem % 4 != 0) 476d6d439f3SHamish Morrison return B_BAD_ADDRESS; 477d6d439f3SHamish Morrison 478d6d439f3SHamish Morrison // wire the page and get the physical address 479d6d439f3SHamish Morrison VMPageWiringInfo wiringInfo; 480d6d439f3SHamish Morrison status_t error = vm_wire_page(B_CURRENT_TEAM, (addr_t)sem, true, 481d6d439f3SHamish Morrison &wiringInfo); 482d6d439f3SHamish Morrison if (error != B_OK) 483d6d439f3SHamish Morrison return error; 484d6d439f3SHamish Morrison 485d6d439f3SHamish Morrison { 486d6d439f3SHamish Morrison MutexLocker locker(sUserMutexTableLock); 487d6d439f3SHamish Morrison user_mutex_sem_release_locked(sem, wiringInfo.physicalAddress); 488d6d439f3SHamish Morrison } 489d6d439f3SHamish Morrison 490d6d439f3SHamish Morrison vm_unwire_page(&wiringInfo); 491d6d439f3SHamish Morrison return B_OK; 492d6d439f3SHamish Morrison } 493