mirror of
https://github.com/yuzu-mirror/yuzu
synced 2024-12-30 08:03:04 +00: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;
|
bool resume = true;
|
||||||
|
|
||||||
if (thread->GetStatus() == ThreadStatus::WaitSynchAny ||
|
if (thread->GetStatus() == ThreadStatus::WaitSynch ||
|
||||||
thread->GetStatus() == ThreadStatus::WaitSynchAll ||
|
|
||||||
thread->GetStatus() == ThreadStatus::WaitHLEEvent) {
|
thread->GetStatus() == ThreadStatus::WaitHLEEvent) {
|
||||||
// Remove the thread from each of its waiting objects' waitlists
|
// Remove the thread from each of its waiting objects' waitlists
|
||||||
for (const auto& object : thread->GetWaitObjects()) {
|
for (const auto& object : thread->GetWaitObjects()) {
|
||||||
|
|
|
@ -150,8 +150,7 @@ void Process::PrepareForTermination() {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// TODO(Subv): When are the other running/ready threads terminated?
|
// TODO(Subv): When are the other running/ready threads terminated?
|
||||||
ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynchAny ||
|
ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynch,
|
||||||
thread->GetStatus() == ThreadStatus::WaitSynchAll,
|
|
||||||
"Exiting processes with non-waiting threads is currently unimplemented");
|
"Exiting processes with non-waiting threads is currently unimplemented");
|
||||||
|
|
||||||
thread->Stop();
|
thread->Stop();
|
||||||
|
|
|
@ -424,7 +424,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han
|
||||||
/// Default thread wakeup callback for WaitSynchronization
|
/// Default thread wakeup callback for WaitSynchronization
|
||||||
static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread,
|
static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> thread,
|
||||||
SharedPtr<WaitObject> object, std::size_t index) {
|
SharedPtr<WaitObject> object, std::size_t index) {
|
||||||
ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny);
|
ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
|
||||||
|
|
||||||
if (reason == ThreadWakeupReason::Timeout) {
|
if (reason == ThreadWakeupReason::Timeout) {
|
||||||
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
||||||
|
@ -502,7 +502,7 @@ static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
thread->SetWaitObjects(std::move(objects));
|
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
|
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
||||||
thread->WakeAfterDelay(nano_seconds);
|
thread->WakeAfterDelay(nano_seconds);
|
||||||
|
|
|
@ -101,8 +101,7 @@ void Thread::ResumeFromWait() {
|
||||||
ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects");
|
ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects");
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case ThreadStatus::WaitSynchAll:
|
case ThreadStatus::WaitSynch:
|
||||||
case ThreadStatus::WaitSynchAny:
|
|
||||||
case ThreadStatus::WaitHLEEvent:
|
case ThreadStatus::WaitHLEEvent:
|
||||||
case ThreadStatus::WaitSleep:
|
case ThreadStatus::WaitSleep:
|
||||||
case ThreadStatus::WaitIPC:
|
case ThreadStatus::WaitIPC:
|
||||||
|
@ -143,7 +142,7 @@ void Thread::ResumeFromWait() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::CancelWait() {
|
void Thread::CancelWait() {
|
||||||
ASSERT(GetStatus() == ThreadStatus::WaitSynchAny);
|
ASSERT(GetStatus() == ThreadStatus::WaitSynch);
|
||||||
SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED);
|
SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED);
|
||||||
ResumeFromWait();
|
ResumeFromWait();
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,7 @@ enum class ThreadStatus {
|
||||||
WaitHLEEvent, ///< Waiting for hle event to finish
|
WaitHLEEvent, ///< Waiting for hle event to finish
|
||||||
WaitSleep, ///< Waiting due to a SleepThread SVC
|
WaitSleep, ///< Waiting due to a SleepThread SVC
|
||||||
WaitIPC, ///< Waiting for the reply from an IPC request
|
WaitIPC, ///< Waiting for the reply from an IPC request
|
||||||
WaitSynchAny, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
|
WaitSynch, ///< Waiting due to WaitSynchronization
|
||||||
WaitSynchAll, ///< Waiting due to WaitSynchronizationN with wait_all = true
|
|
||||||
WaitMutex, ///< Waiting due to an ArbitrateLock svc
|
WaitMutex, ///< Waiting due to an ArbitrateLock svc
|
||||||
WaitCondVar, ///< Waiting due to an WaitProcessWideKey svc
|
WaitCondVar, ///< Waiting due to an WaitProcessWideKey svc
|
||||||
WaitArb, ///< Waiting due to a SignalToAddress/WaitForAddress svc
|
WaitArb, ///< Waiting due to a SignalToAddress/WaitForAddress svc
|
||||||
|
@ -185,24 +184,27 @@ public:
|
||||||
void CancelWakeupTimer();
|
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
|
* @param result Value to set to the returned result
|
||||||
*/
|
*/
|
||||||
void SetWaitSynchronizationResult(ResultCode 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
|
* @param output Value to set to the output parameter
|
||||||
*/
|
*/
|
||||||
void SetWaitSynchronizationOutput(s32 output);
|
void SetWaitSynchronizationOutput(s32 output);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the index that this particular object occupies in the list of objects
|
* 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.
|
* that the thread passed to WaitSynchronization, starting the search from the last element.
|
||||||
* It is used to set the output value of WaitSynchronizationN when the thread is awakened.
|
*
|
||||||
|
* 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
|
* 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
|
* matching object in the wait objects list in case of having multiple instances of the same
|
||||||
* object in the list.
|
* object in the list.
|
||||||
|
*
|
||||||
* @param object Object to query the index of.
|
* @param object Object to query the index of.
|
||||||
*/
|
*/
|
||||||
s32 GetWaitObjectIndex(const WaitObject* object) const;
|
s32 GetWaitObjectIndex(const WaitObject* object) const;
|
||||||
|
@ -239,13 +241,9 @@ public:
|
||||||
*/
|
*/
|
||||||
VAddr GetCommandBufferAddress() const;
|
VAddr GetCommandBufferAddress() const;
|
||||||
|
|
||||||
/**
|
/// Returns whether this thread is waiting on objects from a WaitSynchronization call.
|
||||||
* Returns whether this thread is waiting for all the objects in
|
bool IsSleepingOnWait() const {
|
||||||
* its wait list to become ready, as a result of a WaitSynchronizationN call
|
return status == ThreadStatus::WaitSynch;
|
||||||
* with wait_all = true.
|
|
||||||
*/
|
|
||||||
bool IsSleepingOnWaitAll() const {
|
|
||||||
return status == ThreadStatus::WaitSynchAll;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadContext& GetContext() {
|
ThreadContext& GetContext() {
|
||||||
|
@ -423,7 +421,7 @@ private:
|
||||||
Process* owner_process;
|
Process* owner_process;
|
||||||
|
|
||||||
/// Objects that the thread is waiting on, in the same order as they were
|
/// Objects that the thread is waiting on, in the same order as they were
|
||||||
/// passed to WaitSynchronization1/N.
|
/// passed to WaitSynchronization.
|
||||||
ThreadWaitObjects wait_objects;
|
ThreadWaitObjects wait_objects;
|
||||||
|
|
||||||
/// List of threads that are waiting for a mutex that is held by this thread.
|
/// List of threads that are waiting for a mutex that is held by this thread.
|
||||||
|
@ -449,7 +447,7 @@ private:
|
||||||
Handle callback_handle = 0;
|
Handle callback_handle = 0;
|
||||||
|
|
||||||
/// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
|
/// 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.
|
/// available. In case of a timeout, the object will be nullptr.
|
||||||
WakeupCallback wakeup_callback;
|
WakeupCallback wakeup_callback;
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,7 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
|
||||||
const ThreadStatus thread_status = thread->GetStatus();
|
const ThreadStatus thread_status = thread->GetStatus();
|
||||||
|
|
||||||
// The list of waiting threads must not contain threads that are not waiting to be awakened.
|
// The list of waiting threads must not contain threads that are not waiting to be awakened.
|
||||||
ASSERT_MSG(thread_status == ThreadStatus::WaitSynchAny ||
|
ASSERT_MSG(thread_status == ThreadStatus::WaitSynch ||
|
||||||
thread_status == ThreadStatus::WaitSynchAll ||
|
|
||||||
thread_status == ThreadStatus::WaitHLEEvent,
|
thread_status == ThreadStatus::WaitHLEEvent,
|
||||||
"Inconsistent thread statuses in waiting_threads");
|
"Inconsistent thread statuses in waiting_threads");
|
||||||
|
|
||||||
|
@ -49,10 +48,10 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
|
||||||
if (ShouldWait(thread.get()))
|
if (ShouldWait(thread.get()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// A thread is ready to run if it's either in ThreadStatus::WaitSynchAny or
|
// A thread is ready to run if it's either in ThreadStatus::WaitSynch
|
||||||
// in ThreadStatus::WaitSynchAll and the rest of the objects it is waiting on are ready.
|
// and the rest of the objects it is waiting on are ready.
|
||||||
bool ready_to_run = true;
|
bool ready_to_run = true;
|
||||||
if (thread_status == ThreadStatus::WaitSynchAll) {
|
if (thread_status == ThreadStatus::WaitSynch) {
|
||||||
ready_to_run = thread->AllWaitObjectsReady();
|
ready_to_run = thread->AllWaitObjectsReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,33 +67,35 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
|
||||||
void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) {
|
void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) {
|
||||||
ASSERT(!ShouldWait(thread.get()));
|
ASSERT(!ShouldWait(thread.get()));
|
||||||
|
|
||||||
if (!thread)
|
if (!thread) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!thread->IsSleepingOnWaitAll()) {
|
if (thread->IsSleepingOnWait()) {
|
||||||
Acquire(thread.get());
|
|
||||||
} else {
|
|
||||||
for (const auto& object : thread->GetWaitObjects()) {
|
for (const auto& object : thread->GetWaitObjects()) {
|
||||||
ASSERT(!object->ShouldWait(thread.get()));
|
ASSERT(!object->ShouldWait(thread.get()));
|
||||||
object->Acquire(thread.get());
|
object->Acquire(thread.get());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Acquire(thread.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::size_t index = thread->GetWaitObjectIndex(this);
|
const std::size_t index = thread->GetWaitObjectIndex(this);
|
||||||
|
|
||||||
for (const auto& object : thread->GetWaitObjects())
|
for (const auto& object : thread->GetWaitObjects()) {
|
||||||
object->RemoveWaitingThread(thread.get());
|
object->RemoveWaitingThread(thread.get());
|
||||||
|
}
|
||||||
thread->ClearWaitObjects();
|
thread->ClearWaitObjects();
|
||||||
|
|
||||||
thread->CancelWakeupTimer();
|
thread->CancelWakeupTimer();
|
||||||
|
|
||||||
bool resume = true;
|
bool resume = true;
|
||||||
|
if (thread->HasWakeupCallback()) {
|
||||||
if (thread->HasWakeupCallback())
|
|
||||||
resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, this, index);
|
resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, this, index);
|
||||||
|
}
|
||||||
if (resume)
|
if (resume) {
|
||||||
thread->ResumeFromWait();
|
thread->ResumeFromWait();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitObject::WakeupAllWaitingThreads() {
|
void WaitObject::WakeupAllWaitingThreads() {
|
||||||
|
|
|
@ -227,8 +227,7 @@ QString WaitTreeThread::GetText() const {
|
||||||
case Kernel::ThreadStatus::WaitIPC:
|
case Kernel::ThreadStatus::WaitIPC:
|
||||||
status = tr("waiting for IPC reply");
|
status = tr("waiting for IPC reply");
|
||||||
break;
|
break;
|
||||||
case Kernel::ThreadStatus::WaitSynchAll:
|
case Kernel::ThreadStatus::WaitSynch:
|
||||||
case Kernel::ThreadStatus::WaitSynchAny:
|
|
||||||
status = tr("waiting for objects");
|
status = tr("waiting for objects");
|
||||||
break;
|
break;
|
||||||
case Kernel::ThreadStatus::WaitMutex:
|
case Kernel::ThreadStatus::WaitMutex:
|
||||||
|
@ -269,8 +268,7 @@ QColor WaitTreeThread::GetColor() const {
|
||||||
return QColor(Qt::GlobalColor::darkRed);
|
return QColor(Qt::GlobalColor::darkRed);
|
||||||
case Kernel::ThreadStatus::WaitSleep:
|
case Kernel::ThreadStatus::WaitSleep:
|
||||||
return QColor(Qt::GlobalColor::darkYellow);
|
return QColor(Qt::GlobalColor::darkYellow);
|
||||||
case Kernel::ThreadStatus::WaitSynchAll:
|
case Kernel::ThreadStatus::WaitSynch:
|
||||||
case Kernel::ThreadStatus::WaitSynchAny:
|
|
||||||
case Kernel::ThreadStatus::WaitMutex:
|
case Kernel::ThreadStatus::WaitMutex:
|
||||||
case Kernel::ThreadStatus::WaitCondVar:
|
case Kernel::ThreadStatus::WaitCondVar:
|
||||||
case Kernel::ThreadStatus::WaitArb:
|
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")));
|
list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynchAny ||
|
if (thread.GetStatus() == Kernel::ThreadStatus::WaitSynch) {
|
||||||
thread.GetStatus() == Kernel::ThreadStatus::WaitSynchAll) {
|
|
||||||
list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjects(),
|
list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjects(),
|
||||||
thread.IsSleepingOnWaitAll()));
|
thread.IsSleepingOnWait()));
|
||||||
}
|
}
|
||||||
|
|
||||||
list.push_back(std::make_unique<WaitTreeCallstack>(thread));
|
list.push_back(std::make_unique<WaitTreeCallstack>(thread));
|
||||||
|
|
Loading…
Reference in a new issue