mirror of
https://github.com/yuzu-mirror/yuzu.git
synced 2024-09-07 10:09:09 +01:00
kernel/thread: Unify wait synchronization types
This is a holdover from Citra, where the 3DS has both WaitSynchronization1 and WaitSynchronizationN. The switch only has one form of wait synchronizing (literally WaitSynchonization). This allows us to throw out code that doesn't apply at all to the Switch kernel. Because of this unnecessary dichotomy within the wait synchronization utilities, we were also neglecting to properly handle waiting on multiple objects. While we're at it, we can also scrub out any lingering references to WaitSynchronization1/WaitSynchronizationN in comments, and change them to WaitSynchronization (or remove them if the mention no longer applies).
This commit is contained in:
parent
433b59c112
commit
c268ffd831
7 changed files with 38 additions and 45 deletions
|
@ -46,8 +46,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
|
|||
|
||||
bool resume = true;
|
||||
|
||||
if (thread->GetStatus() == ThreadStatus::WaitSynchAny ||
|
||||
thread->GetStatus() == ThreadStatus::WaitSynchAll ||
|
||||
if (thread->GetStatus() == ThreadStatus::WaitSynch ||
|
||||
thread->GetStatus() == ThreadStatus::WaitHLEEvent) {
|
||||
// Remove the thread from each of its waiting objects' waitlists
|
||||
for (const auto& object : thread->GetWaitObjects()) {
|
||||
|
|
|
@ -150,8 +150,7 @@ void Process::PrepareForTermination() {
|
|||
continue;
|
||||
|
||||
// TODO(Subv): When are the other running/ready threads terminated?
|
||||
ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynchAny ||
|
||||
thread->GetStatus() == ThreadStatus::WaitSynchAll,
|
||||
ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynch,
|
||||
"Exiting processes with non-waiting threads is currently unimplemented");
|
||||
|
||||
thread->Stop();
|
||||
|
|
|
@ -424,7 +424,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han
|
|||
/// Default thread wakeup callback for WaitSynchronization
|
||||
static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread,
|
||||
SharedPtr<WaitObject> object, std::size_t index) {
|
||||
ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny);
|
||||
ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
|
||||
|
||||
if (reason == ThreadWakeupReason::Timeout) {
|
||||
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
||||
|
@ -502,7 +502,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
|
|||
}
|
||||
|
||||
thread->SetWaitObjects(std::move(objects));
|
||||
thread->SetStatus(ThreadStatus::WaitSynchAny);
|
||||
thread->SetStatus(ThreadStatus::WaitSynch);
|
||||
|
||||
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
||||
thread->WakeAfterDelay(nano_seconds);
|
||||
|
|
|
@ -101,8 +101,7 @@ void Thread::ResumeFromWait() {
|
|||
ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects");
|
||||
|
||||
switch (status) {
|
||||
case ThreadStatus::WaitSynchAll:
|
||||
case ThreadStatus::WaitSynchAny:
|
||||
case ThreadStatus::WaitSynch:
|
||||
case ThreadStatus::WaitHLEEvent:
|
||||
case ThreadStatus::WaitSleep:
|
||||
case ThreadStatus::WaitIPC:
|
||||
|
@ -143,7 +142,7 @@ void Thread::ResumeFromWait() {
|
|||
}
|
||||
|
||||
void Thread::CancelWait() {
|
||||
ASSERT(GetStatus() == ThreadStatus::WaitSynchAny);
|
||||
ASSERT(GetStatus() == ThreadStatus::WaitSynch);
|
||||
SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED);
|
||||
ResumeFromWait();
|
||||
}
|
||||
|
|
|
@ -49,8 +49,7 @@ enum class ThreadStatus {
|
|||
WaitHLEEvent, ///< Waiting for hle event to finish
|
||||
WaitSleep, ///< Waiting due to a SleepThread SVC
|
||||
WaitIPC, ///< Waiting for the reply from an IPC request
|
||||
WaitSynchAny, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
|
||||
WaitSynchAll, ///< Waiting due to WaitSynchronizationN with wait_all = true
|
||||
WaitSynch, ///< Waiting due to WaitSynchronization
|
||||
WaitMutex, ///< Waiting due to an ArbitrateLock svc
|
||||
WaitCondVar, ///< Waiting due to an WaitProcessWideKey svc
|
||||
WaitArb, ///< Waiting due to a SignalToAddress/WaitForAddress svc
|
||||
|
@ -185,24 +184,27 @@ public:
|
|||
void CancelWakeupTimer();
|
||||
|
||||
/**
|
||||
* Sets the result after the thread awakens (from either WaitSynchronization SVC)
|
||||
* Sets the result after the thread awakens (from svcWaitSynchronization)
|
||||
* @param result Value to set to the returned result
|
||||
*/
|
||||
void SetWaitSynchronizationResult(ResultCode result);
|
||||
|
||||
/**
|
||||
* Sets the output parameter value after the thread awakens (from WaitSynchronizationN SVC only)
|
||||
* Sets the output parameter value after the thread awakens (from svcWaitSynchronization)
|
||||
* @param output Value to set to the output parameter
|
||||
*/
|
||||
void SetWaitSynchronizationOutput(s32 output);
|
||||
|
||||
/**
|
||||
* Retrieves the index that this particular object occupies in the list of objects
|
||||
* that the thread passed to WaitSynchronizationN, starting the search from the last element.
|
||||
* It is used to set the output value of WaitSynchronizationN when the thread is awakened.
|
||||
* that the thread passed to WaitSynchronization, starting the search from the last element.
|
||||
*
|
||||
* It is used to set the output index of WaitSynchronization when the thread is awakened.
|
||||
*
|
||||
* When a thread wakes up due to an object signal, the kernel will use the index of the last
|
||||
* matching object in the wait objects list in case of having multiple instances of the same
|
||||
* object in the list.
|
||||
*
|
||||
* @param object Object to query the index of.
|
||||
*/
|
||||
s32 GetWaitObjectIndex(const WaitObject* object) const;
|
||||
|
@ -239,13 +241,9 @@ public:
|
|||
*/
|
||||
VAddr GetCommandBufferAddress() const;
|
||||
|
||||
/**
|
||||
* Returns whether this thread is waiting for all the objects in
|
||||
* its wait list to become ready, as a result of a WaitSynchronizationN call
|
||||
* with wait_all = true.
|
||||
*/
|
||||
bool IsSleepingOnWaitAll() const {
|
||||
return status == ThreadStatus::WaitSynchAll;
|
||||
/// Returns whether this thread is waiting on objects from a WaitSynchronization call.
|
||||
bool IsSleepingOnWait() const {
|
||||
return status == ThreadStatus::WaitSynch;
|
||||
}
|
||||
|
||||
ThreadContext& GetContext() {
|
||||
|
@ -423,7 +421,7 @@ private:
|
|||
Process* owner_process;
|
||||
|
||||
/// Objects that the thread is waiting on, in the same order as they were
|
||||
/// passed to WaitSynchronization1/N.
|
||||
/// passed to WaitSynchronization.
|
||||
ThreadWaitObjects wait_objects;
|
||||
|
||||
/// List of threads that are waiting for a mutex that is held by this thread.
|
||||
|
@ -449,7 +447,7 @@ private:
|
|||
Handle callback_handle = 0;
|
||||
|
||||
/// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
|
||||
/// was waiting via WaitSynchronizationN then the object will be the last object that became
|
||||
/// was waiting via WaitSynchronization then the object will be the last object that became
|
||||
/// available. In case of a timeout, the object will be nullptr.
|
||||
WakeupCallback wakeup_callback;
|
||||
|
||||
|
|
|
@ -38,8 +38,7 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
|
|||
const ThreadStatus thread_status = thread->GetStatus();
|
||||
|
||||
// The list of waiting threads must not contain threads that are not waiting to be awakened.
|
||||
ASSERT_MSG(thread_status == ThreadStatus::WaitSynchAny ||
|
||||
thread_status == ThreadStatus::WaitSynchAll ||
|
||||
ASSERT_MSG(thread_status == ThreadStatus::WaitSynch ||
|
||||
thread_status == ThreadStatus::WaitHLEEvent,
|
||||
"Inconsistent thread statuses in waiting_threads");
|
||||
|
||||
|
@ -49,10 +48,10 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
|
|||
if (ShouldWait(thread.get()))
|
||||
continue;
|
||||
|
||||
// A thread is ready to run if it's either in ThreadStatus::WaitSynchAny or
|
||||
// in ThreadStatus::WaitSynchAll and the rest of the objects it is waiting on are ready.
|
||||
// A thread is ready to run if it's either in ThreadStatus::WaitSynch
|
||||
// and the rest of the objects it is waiting on are ready.
|
||||
bool ready_to_run = true;
|
||||
if (thread_status == ThreadStatus::WaitSynchAll) {
|
||||
if (thread_status == ThreadStatus::WaitSynch) {
|
||||
ready_to_run = thread->AllWaitObjectsReady();
|
||||
}
|
||||
|
||||
|
@ -68,34 +67,36 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
|
|||
void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) {
|
||||
ASSERT(!ShouldWait(thread.get()));
|
||||
|
||||
if (!thread)
|
||||
if (!thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!thread->IsSleepingOnWaitAll()) {
|
||||
Acquire(thread.get());
|
||||
} else {
|
||||
if (thread->IsSleepingOnWait()) {
|
||||
for (const auto& object : thread->GetWaitObjects()) {
|
||||
ASSERT(!object->ShouldWait(thread.get()));
|
||||
object->Acquire(thread.get());
|
||||
}
|
||||
} else {
|
||||
Acquire(thread.get());
|
||||
}
|
||||
|
||||
const std::size_t index = thread->GetWaitObjectIndex(this);
|
||||
|
||||
for (const auto& object : thread->GetWaitObjects())
|
||||
for (const auto& object : thread->GetWaitObjects()) {
|
||||
object->RemoveWaitingThread(thread.get());
|
||||
}
|
||||
thread->ClearWaitObjects();
|
||||
|
||||
thread->CancelWakeupTimer();
|
||||
|
||||
bool resume = true;
|
||||
|
||||
if (thread->HasWakeupCallback())
|
||||
if (thread->HasWakeupCallback()) {
|
||||
resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, this, index);
|
||||
|
||||
if (resume)
|
||||
}
|
||||
if (resume) {
|
||||
thread->ResumeFromWait();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitObject::WakeupAllWaitingThreads() {
|
||||
while (auto thread = GetHighestPriorityReadyThread()) {
|
||||
|
|
|
@ -227,8 +227,7 @@ QString WaitTreeThread::GetText() const {
|
|||
case Kernel::ThreadStatus::WaitIPC:
|
||||
status = tr("waiting for IPC reply");
|
||||
break;
|
||||
case Kernel::ThreadStatus::WaitSynchAll:
|
||||
case Kernel::ThreadStatus::WaitSynchAny:
|
||||
case Kernel::ThreadStatus::WaitSynch:
|
||||
status = tr("waiting for objects");
|
||||
break;
|
||||
case Kernel::ThreadStatus::WaitMutex:
|
||||
|
@ -269,8 +268,7 @@ QColor WaitTreeThread::GetColor() const {
|
|||
return QColor(Qt::GlobalColor::darkRed);
|
||||
case Kernel::ThreadStatus::WaitSleep:
|
||||
return QColor(Qt::GlobalColor::darkYellow);
|
||||
case Kernel::ThreadStatus::WaitSynchAll:
|
||||
case Kernel::ThreadStatus::WaitSynchAny:
|
||||
case Kernel::ThreadStatus::WaitSynch:
|
||||
case Kernel::ThreadStatus::WaitMutex:
|
||||
case Kernel::ThreadStatus::WaitCondVar:
|
||||
case Kernel::ThreadStatus::WaitArb:
|
||||
|
@ -325,10 +323,9 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
|
|||
list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex")));
|
||||
}
|
||||
|
||||
if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynchAny ||
|
||||
thread.GetStatus() == Kernel::ThreadStatus::WaitSynchAll) {
|
||||
if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) {
|
||||
list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjects(),
|
||||
thread.IsSleepingOnWaitAll()));
|
||||
thread.IsSleepingOnWait()));
|
||||
}
|
||||
|
||||
list.push_back(std::make_unique<WaitTreeCallstack>(thread));
|
||||
|
|
Loading…
Reference in a new issue