/** * Sleep the current thread until the condition variable has been signalled. * * The mutex must be locked when entering this function. * Will unlock the mutex and then sleep, reacquiring the mutex when woken. * * Similar to <a href="http://en.cppreference.com/w/cpp/thread/condition_variable/wait">std::condition_variable::wait</a>. */ void OSWaitCond(OSCondition *condition, OSMutex *mutex) { auto thread = OSGetCurrentThread(); internal::lockScheduler(); decaf_check(mutex && mutex->tag == OSMutex::Tag); decaf_check(condition && condition->tag == OSCondition::Tag); decaf_check(mutex->owner == thread); // Force an unlock auto mutexCount = mutex->count; mutex->count = 1; unlockMutexNoLock(mutex); internal::rescheduleOtherCoreNoLock(); // Sleep on the condition internal::sleepThreadNoLock(&condition->queue); internal::rescheduleSelfNoLock(); // Restore lock lockMutexNoLock(mutex); mutex->count = mutexCount; internal::unlockScheduler(); }
/** * Lock the mutex. * * If no one owns the mutex, set current thread as owner. * If the lock is owned by the current thread, increase the recursion count. * If the lock is owned by another thread, the current thread will sleep until * the owner has unlocked this mutex. * * Similar to <a href="http://en.cppreference.com/w/cpp/thread/recursive_mutex/lock">std::recursive_mutex::lock</a>. */ void OSLockMutex(virt_ptr<OSMutex> mutex) { internal::lockScheduler(); internal::testThreadCancelNoLock(); lockMutexNoLock(mutex); internal::unlockScheduler(); }
/** * Sleep the current thread until the condition variable has been signalled. * * The mutex must be locked when entering this function. * Will unlock the mutex and then sleep, reacquiring the mutex when woken. * * Similar to <a href="http://en.cppreference.com/w/cpp/thread/condition_variable/wait">std::condition_variable::wait</a>. */ void OSWaitCond(virt_ptr<OSCondition> condition, virt_ptr<OSMutex> mutex) { internal::lockScheduler(); auto thread = OSGetCurrentThread(); decaf_check(thread->state == OSThreadState::Running); decaf_check(mutex->owner == thread); // Save the count and then unlock the mutex auto mutexCount = mutex->count; mutex->count = 0; mutex->owner = nullptr; // Remove mutex from thread's mutex queue MutexQueue::erase(virt_addrof(thread->mutexQueue), mutex); // If we have a promoted priority, reset it. if (thread->priority < thread->basePriority) { thread->priority = internal::calculateThreadPriorityNoLock(thread); } // Wake anyone waiting on the mutex internal::disableScheduler(); internal::wakeupThreadNoLock(virt_addrof(mutex->queue)); internal::rescheduleAllCoreNoLock(); internal::enableScheduler(); // Sleep on the condition internal::sleepThreadNoLock(virt_addrof(condition->queue)); internal::rescheduleSelfNoLock(); // Relock the mutex lockMutexNoLock(mutex); mutex->count = mutexCount; internal::unlockScheduler(); }