1
0
Fork 0
forked from suyu/suyu

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:
Lioncash 2019-04-17 07:21:19 -04:00
parent 433b59c112
commit c268ffd831
7 changed files with 38 additions and 45 deletions

View file

@ -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()) {

View file

@ -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();

View file

@ -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);

View file

@ -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();
} }

View file

@ -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;

View file

@ -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() {

View file

@ -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));