From c22bac6398ff1705992fc44b2c29775c84cff662 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 14 Jan 2015 19:22:50 -0500 Subject: Kernel: Added WaitObject and changed "waitable" objects inherit from it. --- src/core/hle/kernel/event.cpp | 26 +++++++------------------- src/core/hle/kernel/kernel.cpp | 26 ++++++++++++++++++++++++++ src/core/hle/kernel/kernel.h | 25 +++++++++++++++++++++++++ src/core/hle/kernel/mutex.cpp | 29 ++++++----------------------- src/core/hle/kernel/semaphore.cpp | 11 +++-------- src/core/hle/kernel/thread.cpp | 11 ++--------- src/core/hle/kernel/thread.h | 4 +--- src/core/hle/kernel/timer.cpp | 12 +++--------- 8 files changed, 73 insertions(+), 71 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 271190dbe..bf71e9edb 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -14,7 +14,7 @@ namespace Kernel { -class Event : public Object { +class Event : public WaitObject { public: std::string GetTypeName() const override { return "Event"; } std::string GetName() const override { return name; } @@ -27,16 +27,12 @@ public: bool locked; ///< Event signal wait bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough) - std::vector waiting_threads; ///< Threads that are waiting for the event std::string name; ///< Name of event (optional) ResultVal WaitSynchronization() override { bool wait = locked; if (locked) { - Handle thread = GetCurrentThread()->GetHandle(); - if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { - waiting_threads.push_back(thread); - } + AddWaitingThread(GetCurrentThread()); Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); } if (reset_type != RESETTYPE_STICKY && !permanent_locked) { @@ -86,20 +82,12 @@ ResultCode SignalEvent(const Handle handle) { if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); // Resume threads waiting for event to signal - bool event_caught = false; - for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { - Thread* thread = Kernel::g_handle_table.Get(evt->waiting_threads[i]).get(); - if (thread != nullptr) - thread->ResumeFromWait(); - - // If any thread is signalled awake by this event, assume the event was "caught" and reset - // the event. This will result in the next thread waiting on the event to block. Otherwise, - // the event will not be reset, and the next thread to call WaitSynchronization on it will - // not block. Not sure if this is correct behavior, but it seems to work. - event_caught = true; - } - evt->waiting_threads.clear(); + bool event_caught = evt->ResumeAllWaitingThreads(); + // If any thread is signalled awake by this event, assume the event was "caught" and reset + // the event. This will result in the next thread waiting on the event to block. Otherwise, + // the event will not be reset, and the next thread to call WaitSynchronization on it will + // not block. Not sure if this is correct behavior, but it seems to work. if (!evt->permanent_locked) { evt->locked = event_caught; } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index d3684896f..07e96e633 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -18,6 +18,32 @@ SharedPtr g_main_thread = nullptr; HandleTable g_handle_table; u64 g_program_id = 0; +void WaitObject::AddWaitingThread(Thread* thread) { + if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { + waiting_threads.push_back(thread); + } +} + +Thread* WaitObject::ResumeNextThread() { + if (waiting_threads.empty()) return nullptr; + + auto next_thread = waiting_threads.front(); + + next_thread->ResumeFromWait(); + waiting_threads.erase(waiting_threads.begin()); + + return next_thread.get(); +} + +void WaitObject::ReleaseAllWaitingThreads() { + auto waiting_threads_copy = waiting_threads; + + for (auto thread : waiting_threads_copy) + thread->ReleaseWaitObject(this); + + waiting_threads.clear(); +} + HandleTable::HandleTable() { next_generation = 1; Clear(); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 5e5217b78..a9af9de88 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -8,6 +8,8 @@ #include #include +#include + #include "common/common.h" #include "core/hle/result.h" @@ -92,6 +94,29 @@ inline void intrusive_ptr_release(Object* object) { template using SharedPtr = boost::intrusive_ptr; +/// Class that represents a Kernel object that a thread can be waiting on +class WaitObject : public Object { +public: + + /** + * Add a thread to wait on this object + * @param thread Pointer to thread to add + */ + void AddWaitingThread(Thread* thread); + + /** + * Resumes the next thread waiting on this object + * @return Pointer to the thread that was resumed, nullptr if no threads are waiting + */ + Thread* ResumeNextThread(); + + /// Releases all threads waiting on this object + void ReleaseAllWaitingThreads(); + +private: + std::vector waiting_threads; ///< Threads waiting for this object to become available +}; + /** * This class allows the creation of Handles, which are references to objects that can be tested * for validity and looked up. Here they are used to pass references to kernel objects to/from the diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 853a5dd74..35d829606 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -13,7 +13,7 @@ namespace Kernel { -class Mutex : public Object { +class Mutex : public WaitObject { public: std::string GetTypeName() const override { return "Mutex"; } std::string GetName() const override { return name; } @@ -24,7 +24,6 @@ public: bool initial_locked; ///< Initial lock state when mutex was created bool locked; ///< Current locked state Handle lock_thread; ///< Handle to thread that currently has mutex - std::vector waiting_threads; ///< Threads that are waiting for the mutex std::string name; ///< Name of mutex (optional) ResultVal WaitSynchronization() override; @@ -45,36 +44,20 @@ void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandl mutex->lock_thread = thread; } -bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) { - MutexAcquireLock(mutex, thread_handle); - - Thread* thread = Kernel::g_handle_table.Get(thread_handle).get(); - if (thread == nullptr) { - LOG_ERROR(Kernel, "Called with invalid handle: %08X", thread_handle); - return false; - } - - thread->ResumeFromWait(); - return true; -} - /** * Resumes a thread waiting for the specified mutex * @param mutex The mutex that some thread is waiting on */ void ResumeWaitingThread(Mutex* mutex) { // Find the next waiting thread for the mutex... - if (mutex->waiting_threads.empty()) { + auto next_thread = mutex->ResumeNextThread(); + if (next_thread != nullptr) { + MutexAcquireLock(mutex, next_thread->GetHandle()); + } else { // Reset mutex lock thread handle, nothing is waiting mutex->locked = false; mutex->lock_thread = -1; } - else { - // Resume the next waiting thread and re-lock the mutex - std::vector::iterator iter = mutex->waiting_threads.begin(); - ReleaseMutexForThread(mutex, *iter); - mutex->waiting_threads.erase(iter); - } } void MutexEraseLock(Mutex* mutex) { @@ -175,7 +158,7 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { ResultVal Mutex::WaitSynchronization() { bool wait = locked; if (locked) { - waiting_threads.push_back(GetCurrentThread()->GetHandle()); + AddWaitingThread(GetCurrentThread()); Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); } else { // Lock the mutex when the first thread accesses it diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 88ec9a104..af2c465e4 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -12,7 +12,7 @@ namespace Kernel { -class Semaphore : public Object { +class Semaphore : public WaitObject { public: std::string GetTypeName() const override { return "Semaphore"; } std::string GetName() const override { return name; } @@ -22,7 +22,6 @@ public: s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have s32 available_count; ///< Number of free slots left in the semaphore - std::queue waiting_threads; ///< Threads that are waiting for the semaphore std::string name; ///< Name of semaphore (optional) /** @@ -38,7 +37,7 @@ public: if (wait) { Kernel::WaitCurrentThread(WAITTYPE_SEMA, this); - waiting_threads.push(GetCurrentThread()->GetHandle()); + AddWaitingThread(GetCurrentThread()); } else { --available_count; } @@ -83,11 +82,7 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { // Notify some of the threads that the semaphore has been released // stop once the semaphore is full again or there are no more waiting threads - while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) { - Thread* thread = Kernel::g_handle_table.Get(semaphore->waiting_threads.front()).get(); - if (thread != nullptr) - thread->ResumeFromWait(); - semaphore->waiting_threads.pop(); + while (semaphore->IsAvailable() && semaphore->ResumeNextThread() != nullptr) { --semaphore->available_count; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index bc86a7c59..845672702 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -25,10 +25,7 @@ namespace Kernel { ResultVal Thread::WaitSynchronization() { const bool wait = status != THREADSTATUS_DORMANT; if (wait) { - Thread* thread = GetCurrentThread(); - if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { - waiting_threads.push_back(thread); - } + AddWaitingThread(GetCurrentThread()); WaitCurrentThread(WAITTYPE_THREADEND, this); } @@ -110,11 +107,7 @@ void Thread::Stop(const char* reason) { ChangeReadyState(this, false); status = THREADSTATUS_DORMANT; - for (auto& waiting_thread : waiting_threads) { - if (CheckWaitType(waiting_thread.get(), WAITTYPE_THREADEND, this)) - waiting_thread->ResumeFromWait(); - } - waiting_threads.clear(); + ResumeAllWaitingThreads(); // Stopped threads are never waiting. wait_type = WAITTYPE_NONE; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 8c9f63aa5..daaeb26a4 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -52,7 +52,7 @@ enum WaitType { namespace Kernel { -class Thread : public Kernel::Object { +class Thread : public WaitObject { public: static ResultVal> Create(std::string name, VAddr entry_point, s32 priority, u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); @@ -99,8 +99,6 @@ public: Object* wait_object; VAddr wait_address; - std::vector> waiting_threads; - std::string name; /// Whether this thread is intended to never actually be executed, i.e. always idle diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 3b0452d4d..2d4fa4c01 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -13,7 +13,7 @@ namespace Kernel { -class Timer : public Object { +class Timer : public WaitObject { public: std::string GetTypeName() const override { return "Timer"; } std::string GetName() const override { return name; } @@ -24,7 +24,6 @@ public: ResetType reset_type; ///< The ResetType of this timer bool signaled; ///< Whether the timer has been signaled or not - std::set waiting_threads; ///< Threads that are waiting for the timer std::string name; ///< Name of timer (optional) u64 initial_delay; ///< The delay until the timer fires for the first time @@ -33,7 +32,7 @@ public: ResultVal WaitSynchronization() override { bool wait = !signaled; if (wait) { - waiting_threads.insert(GetCurrentThread()->GetHandle()); + AddWaitingThread(GetCurrentThread()); Kernel::WaitCurrentThread(WAITTYPE_TIMER, this); } return MakeResult(wait); @@ -92,12 +91,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { timer->signaled = true; // Resume all waiting threads - for (Handle thread_handle : timer->waiting_threads) { - if (SharedPtr thread = Kernel::g_handle_table.Get(thread_handle)) - thread->ResumeFromWait(); - } - - timer->waiting_threads.clear(); + timer->ResumeAllWaitingThreads(); if (timer->reset_type == RESETTYPE_ONESHOT) timer->signaled = false; -- cgit v1.2.3 From 5e77e2e1de73ce7786f52f2a74c28182fa4aa845 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 14 Jan 2015 23:19:22 -0500 Subject: WaitObject: Added RemoveWaitingThread, fixed a bug, and cleanup. --- src/core/hle/kernel/kernel.cpp | 13 ++++++++++--- src/core/hle/kernel/kernel.h | 8 +++++++- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 07e96e633..1dba85939 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -19,13 +19,20 @@ HandleTable g_handle_table; u64 g_program_id = 0; void WaitObject::AddWaitingThread(Thread* thread) { - if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { + auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); + if (itr == waiting_threads.end()) waiting_threads.push_back(thread); - } +} + +void WaitObject::RemoveWaitingThread(Thread* thread) { + auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); + if (itr != waiting_threads.end()) + waiting_threads.erase(itr); } Thread* WaitObject::ResumeNextThread() { - if (waiting_threads.empty()) return nullptr; + if (waiting_threads.empty()) + return nullptr; auto next_thread = waiting_threads.front(); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index a9af9de88..53b3f9143 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -105,7 +105,13 @@ public: void AddWaitingThread(Thread* thread); /** - * Resumes the next thread waiting on this object + * Removes a thread from waiting on this object (e.g. if it was resumed already) + * @param thread Pointer to thread to remove + */ + void RemoveWaitingThread(Thread* thead); + + /** + * Resumes (and removes) the next thread waiting on this object * @return Pointer to the thread that was resumed, nullptr if no threads are waiting */ Thread* ResumeNextThread(); -- cgit v1.2.3 From 14cbbf4d9b8e07f9f2d679bcf66c2180463ae57c Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 14 Jan 2015 23:33:37 -0500 Subject: Event: Get rid of permanent_lock hack. --- src/core/hle/kernel/event.cpp | 37 ++++++++----------------------------- src/core/hle/kernel/event.h | 7 ------- 2 files changed, 8 insertions(+), 36 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index bf71e9edb..9dd3d0f5d 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -26,7 +26,6 @@ public: ResetType reset_type; ///< Current ResetType bool locked; ///< Event signal wait - bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough) std::string name; ///< Name of event (optional) ResultVal WaitSynchronization() override { @@ -35,27 +34,13 @@ public: AddWaitingThread(GetCurrentThread()); Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); } - if (reset_type != RESETTYPE_STICKY && !permanent_locked) { + if (reset_type != RESETTYPE_STICKY) { locked = true; } return MakeResult(wait); } }; -/** - * Hackish function to set an events permanent lock state, used to pass through synch blocks - * @param handle Handle to event to change - * @param permanent_locked Boolean permanent locked value to set event - * @return Result of operation, 0 on success, otherwise error code - */ -ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) { - Event* evt = g_handle_table.Get(handle).get(); - if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); - - evt->permanent_locked = permanent_locked; - return RESULT_SUCCESS; -} - /** * Changes whether an event is locked or not * @param handle Handle to event to change @@ -66,9 +51,8 @@ ResultCode SetEventLocked(const Handle handle, const bool locked) { Event* evt = g_handle_table.Get(handle).get(); if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); - if (!evt->permanent_locked) { - evt->locked = locked; - } + evt->locked = locked; + return RESULT_SUCCESS; } @@ -81,16 +65,13 @@ ResultCode SignalEvent(const Handle handle) { Event* evt = g_handle_table.Get(handle).get(); if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); - // Resume threads waiting for event to signal - bool event_caught = evt->ResumeAllWaitingThreads(); - // If any thread is signalled awake by this event, assume the event was "caught" and reset // the event. This will result in the next thread waiting on the event to block. Otherwise, // the event will not be reset, and the next thread to call WaitSynchronization on it will // not block. Not sure if this is correct behavior, but it seems to work. - if (!evt->permanent_locked) { - evt->locked = event_caught; - } + // TODO(bunnei): Test how this works on hardware + evt->locked = evt->ResumeAllWaitingThreads(); + return RESULT_SUCCESS; } @@ -103,9 +84,8 @@ ResultCode ClearEvent(Handle handle) { Event* evt = g_handle_table.Get(handle).get(); if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); - if (!evt->permanent_locked) { - evt->locked = true; - } + evt->locked = true; + return RESULT_SUCCESS; } @@ -123,7 +103,6 @@ Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string handle = Kernel::g_handle_table.Create(evt).ValueOr(INVALID_HANDLE); evt->locked = true; - evt->permanent_locked = false; evt->reset_type = evt->intitial_reset_type = reset_type; evt->name = name; diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index da793df1a..b1b9d4b7b 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h @@ -18,13 +18,6 @@ namespace Kernel { */ ResultCode SetEventLocked(const Handle handle, const bool locked); -/** - * Hackish function to set an events permanent lock state, used to pass through synch blocks - * @param handle Handle to event to change - * @param permanent_locked Boolean permanent locked value to set event - */ -ResultCode SetPermanentLock(Handle handle, const bool permanent_locked); - /** * Signals an event * @param handle Handle to event to signal -- cgit v1.2.3 From 1f7a04f05a488b7d457d356f9bf2dda296cd6b92 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 14 Jan 2015 23:41:33 -0500 Subject: Thread: Keep track of multiple wait objects. --- src/core/hle/kernel/address_arbiter.cpp | 5 +++-- src/core/hle/kernel/thread.cpp | 35 ++++++++++++++++++++++----------- src/core/hle/kernel/thread.h | 6 +++--- 3 files changed, 30 insertions(+), 16 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index b7434aaf2..ff1472066 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -15,7 +15,7 @@ namespace Kernel { -class AddressArbiter : public Object { +class AddressArbiter : public WaitObject { public: std::string GetTypeName() const override { return "Arbiter"; } std::string GetName() const override { return name; } @@ -30,7 +30,8 @@ public: /// Arbitrate an address ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds) { - Object* object = Kernel::g_handle_table.GetGeneric(handle).get(); + WaitObject* object = static_cast(Kernel::g_handle_table.GetGeneric(handle).get()); + if (object == nullptr) return InvalidHandle(ErrorModule::Kernel); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 845672702..00b72477e 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -65,7 +65,7 @@ static void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { t->current_priority = t->initial_priority; } t->wait_type = WAITTYPE_NONE; - t->wait_object = nullptr; + t->wait_objects.clear(); t->wait_address = 0; } @@ -92,7 +92,11 @@ static bool CheckWaitType(const Thread* thread, WaitType type) { /// Check if a thread is blocking on a specified wait type with a specified handle static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { - return CheckWaitType(thread, type) && wait_object == thread->wait_object; + auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); + if (itr == thread->wait_objects.end()) { + return false; + } + return CheckWaitType(thread, type); } /// Check if a thread is blocking on a specified wait type with a specified handle and address @@ -111,7 +115,7 @@ void Thread::Stop(const char* reason) { // Stopped threads are never waiting. wait_type = WAITTYPE_NONE; - wait_object = nullptr; + wait_objects.clear(); wait_address = 0; } @@ -216,14 +220,18 @@ static Thread* NextThread() { return next; } -void WaitCurrentThread(WaitType wait_type, Object* wait_object) { +void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object) { Thread* thread = GetCurrentThread(); thread->wait_type = wait_type; - thread->wait_object = wait_object; + + auto res = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); + if (res == thread->wait_objects.end()) { + thread->wait_objects.push_back(wait_object); + } ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } -void WaitCurrentThread(WaitType wait_type, Object* wait_object, VAddr wait_address) { +void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address) { WaitCurrentThread(wait_type, wait_object); GetCurrentThread()->wait_address = wait_address; } @@ -260,7 +268,13 @@ void Thread::ResumeFromWait() { CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle()); status &= ~THREADSTATUS_WAIT; - wait_object = nullptr; + + // Remove this thread from all other WaitObjects + for (auto wait_object : wait_objects) + wait_object->RemoveWaitingThread(this); + + wait_objects.clear(); + wait_type = WAITTYPE_NONE; if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { ChangeReadyState(this, true); @@ -328,7 +342,7 @@ ResultVal> Thread::Create(std::string name, VAddr entry_point, thread->initial_priority = thread->current_priority = priority; thread->processor_id = processor_id; thread->wait_type = WAITTYPE_NONE; - thread->wait_object = nullptr; + thread->wait_objects.clear(); thread->wait_address = 0; thread->name = std::move(name); @@ -412,9 +426,8 @@ void Reschedule() { LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); for (auto& thread : thread_list) { - LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X", - thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, - (thread->wait_object ? thread->wait_object->GetHandle() : INVALID_HANDLE)); + LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X", + thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type); } } } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index daaeb26a4..9ec96c18c 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -96,7 +96,7 @@ public: s32 processor_id; WaitType wait_type; - Object* wait_object; + std::vector> wait_objects; VAddr wait_address; std::string name; @@ -128,7 +128,7 @@ Thread* GetCurrentThread(); * @param wait_type Type of wait * @param wait_object Kernel object that we are waiting on, defaults to current thread */ -void WaitCurrentThread(WaitType wait_type, Object* wait_object = GetCurrentThread()); +void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object = GetCurrentThread()); /** * Schedules an event to wake up the specified thread after the specified delay. @@ -143,7 +143,7 @@ void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); * @param wait_object Kernel object that we are waiting on * @param wait_address Arbitration address used to resume from wait */ -void WaitCurrentThread(WaitType wait_type, Object* wait_object, VAddr wait_address); +void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address); -- cgit v1.2.3 From e4a5d8ad4f708c9674c9865eb872e3c081d9a8c8 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 15 Jan 2015 19:29:46 -0500 Subject: Event: Fixed some bugs and cleanup (Subv) --- src/core/hle/kernel/event.cpp | 58 ++++++++----------------------------------- src/core/hle/kernel/event.h | 9 ++----- 2 files changed, 13 insertions(+), 54 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 9dd3d0f5d..540199e03 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -25,66 +25,36 @@ public: ResetType intitial_reset_type; ///< ResetType specified at Event initialization ResetType reset_type; ///< Current ResetType - bool locked; ///< Event signal wait + bool signaled; ///< Whether the event has already been signaled std::string name; ///< Name of event (optional) ResultVal WaitSynchronization() override { - bool wait = locked; - if (locked) { + bool wait = !signaled; + if (wait) { AddWaitingThread(GetCurrentThread()); Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); } - if (reset_type != RESETTYPE_STICKY) { - locked = true; - } return MakeResult(wait); } }; -/** - * Changes whether an event is locked or not - * @param handle Handle to event to change - * @param locked Boolean locked value to set event - * @return Result of operation, 0 on success, otherwise error code - */ -ResultCode SetEventLocked(const Handle handle, const bool locked) { - Event* evt = g_handle_table.Get(handle).get(); - if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); - - evt->locked = locked; - - return RESULT_SUCCESS; -} - -/** - * Signals an event - * @param handle Handle to event to signal - * @return Result of operation, 0 on success, otherwise error code - */ ResultCode SignalEvent(const Handle handle) { Event* evt = g_handle_table.Get(handle).get(); - if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); + if (evt == nullptr) + return InvalidHandle(ErrorModule::Kernel); - // If any thread is signalled awake by this event, assume the event was "caught" and reset - // the event. This will result in the next thread waiting on the event to block. Otherwise, - // the event will not be reset, and the next thread to call WaitSynchronization on it will - // not block. Not sure if this is correct behavior, but it seems to work. - // TODO(bunnei): Test how this works on hardware - evt->locked = evt->ResumeAllWaitingThreads(); + evt->signaled = true; + evt->ReleaseAllWaitingThreads(); return RESULT_SUCCESS; } -/** - * Clears an event - * @param handle Handle to event to clear - * @return Result of operation, 0 on success, otherwise error code - */ ResultCode ClearEvent(Handle handle) { Event* evt = g_handle_table.Get(handle).get(); - if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); + if (evt == nullptr) + return InvalidHandle(ErrorModule::Kernel); - evt->locked = true; + evt->signaled = false; return RESULT_SUCCESS; } @@ -102,19 +72,13 @@ Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string // TOOD(yuriks): Fix error reporting handle = Kernel::g_handle_table.Create(evt).ValueOr(INVALID_HANDLE); - evt->locked = true; + evt->signaled = false; evt->reset_type = evt->intitial_reset_type = reset_type; evt->name = name; return evt; } -/** - * Creates an event - * @param reset_type ResetType describing how to create event - * @param name Optional name of event - * @return Handle to newly created Event object - */ Handle CreateEvent(const ResetType reset_type, const std::string& name) { Handle handle; Event* evt = CreateEvent(handle, reset_type, name); diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index b1b9d4b7b..c08b12ee1 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h @@ -11,22 +11,17 @@ namespace Kernel { -/** - * Changes whether an event is locked or not - * @param handle Handle to event to change - * @param locked Boolean locked value to set event - */ -ResultCode SetEventLocked(const Handle handle, const bool locked); - /** * Signals an event * @param handle Handle to event to signal + * @return Result of operation, 0 on success, otherwise error code */ ResultCode SignalEvent(const Handle handle); /** * Clears an event * @param handle Handle to event to clear + * @return Result of operation, 0 on success, otherwise error code */ ResultCode ClearEvent(Handle handle); -- cgit v1.2.3 From 7faf2d8e06e705d1866fa0d7848ff43541a4b172 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Jan 2015 02:03:44 -0500 Subject: WaitSynchronizationN: Implement return values --- src/core/hle/kernel/address_arbiter.cpp | 8 +-- src/core/hle/kernel/event.cpp | 4 +- src/core/hle/kernel/kernel.cpp | 4 +- src/core/hle/kernel/kernel.h | 7 +-- src/core/hle/kernel/mutex.cpp | 8 +-- src/core/hle/kernel/semaphore.cpp | 6 +-- src/core/hle/kernel/thread.cpp | 94 ++++++++++++++++++++++++++------- src/core/hle/kernel/thread.h | 58 ++++++++++++++------ src/core/hle/kernel/timer.cpp | 6 +-- 9 files changed, 139 insertions(+), 56 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index ff1472066..520601455 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -52,13 +52,13 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 // Wait current thread (acquire the arbiter)... case ArbitrationType::WaitIfLessThan: if ((s32)Memory::Read32(address) <= value) { - Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); + Kernel::WaitCurrentThread_ArbitrateAddress(object, address); HLE::Reschedule(__func__); } break; case ArbitrationType::WaitIfLessThanWithTimeout: if ((s32)Memory::Read32(address) <= value) { - Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); + Kernel::WaitCurrentThread_ArbitrateAddress(object, address); Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); HLE::Reschedule(__func__); } @@ -68,7 +68,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 s32 memory_value = Memory::Read32(address) - 1; Memory::Write32(address, memory_value); if (memory_value <= value) { - Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); + Kernel::WaitCurrentThread_ArbitrateAddress(object, address); HLE::Reschedule(__func__); } break; @@ -78,7 +78,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 s32 memory_value = Memory::Read32(address) - 1; Memory::Write32(address, memory_value); if (memory_value <= value) { - Kernel::WaitCurrentThread(WAITTYPE_ARB, object, address); + Kernel::WaitCurrentThread_ArbitrateAddress(object, address); Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); HLE::Reschedule(__func__); } diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 540199e03..4173a980b 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -28,11 +28,11 @@ public: bool signaled; ///< Whether the event has already been signaled std::string name; ///< Name of event (optional) - ResultVal WaitSynchronization() override { + ResultVal WaitSynchronization(unsigned index) override { bool wait = !signaled; if (wait) { AddWaitingThread(GetCurrentThread()); - Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); + Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_EVENT, this, index); } return MakeResult(wait); } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1dba85939..be3495412 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -30,13 +30,13 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { waiting_threads.erase(itr); } -Thread* WaitObject::ResumeNextThread() { +Thread* WaitObject::ReleaseNextThread() { if (waiting_threads.empty()) return nullptr; auto next_thread = waiting_threads.front(); - next_thread->ResumeFromWait(); + next_thread->ReleaseFromWait(this); waiting_threads.erase(waiting_threads.begin()); return next_thread.get(); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 53b3f9143..af4e2f443 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -66,9 +66,10 @@ public: /** * Wait for kernel object to synchronize. + * @param index Index of wait object (only applies to WaitSynchronizationN) * @return True if the current thread should wait as a result of the wait */ - virtual ResultVal WaitSynchronization() { + virtual ResultVal WaitSynchronization(unsigned index=0) { LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); return UnimplementedFunction(ErrorModule::Kernel); } @@ -111,10 +112,10 @@ public: void RemoveWaitingThread(Thread* thead); /** - * Resumes (and removes) the next thread waiting on this object + * Releases (and removes) the next thread waiting on this object * @return Pointer to the thread that was resumed, nullptr if no threads are waiting */ - Thread* ResumeNextThread(); + Thread* ReleaseNextThread(); /// Releases all threads waiting on this object void ReleaseAllWaitingThreads(); diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 35d829606..78063b8f1 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -26,7 +26,7 @@ public: Handle lock_thread; ///< Handle to thread that currently has mutex std::string name; ///< Name of mutex (optional) - ResultVal WaitSynchronization() override; + ResultVal WaitSynchronization(unsigned index) override; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -50,7 +50,7 @@ void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandl */ void ResumeWaitingThread(Mutex* mutex) { // Find the next waiting thread for the mutex... - auto next_thread = mutex->ResumeNextThread(); + auto next_thread = mutex->ReleaseNextThread(); if (next_thread != nullptr) { MutexAcquireLock(mutex, next_thread->GetHandle()); } else { @@ -155,11 +155,11 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { return handle; } -ResultVal Mutex::WaitSynchronization() { +ResultVal Mutex::WaitSynchronization(unsigned index) { bool wait = locked; if (locked) { AddWaitingThread(GetCurrentThread()); - Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); + Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_MUTEX, this, index); } else { // Lock the mutex when the first thread accesses it locked = true; diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index af2c465e4..288928441 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -32,11 +32,11 @@ public: return available_count > 0; } - ResultVal WaitSynchronization() override { + ResultVal WaitSynchronization(unsigned index) override { bool wait = !IsAvailable(); if (wait) { - Kernel::WaitCurrentThread(WAITTYPE_SEMA, this); + Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_SEMA, this, index); AddWaitingThread(GetCurrentThread()); } else { --available_count; @@ -82,7 +82,7 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { // Notify some of the threads that the semaphore has been released // stop once the semaphore is full again or there are no more waiting threads - while (semaphore->IsAvailable() && semaphore->ResumeNextThread() != nullptr) { + while (semaphore->IsAvailable() && semaphore->ReleaseNextThread() != nullptr) { --semaphore->available_count; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 00b72477e..0c9ecc091 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,11 +22,11 @@ namespace Kernel { -ResultVal Thread::WaitSynchronization() { +ResultVal Thread::WaitSynchronization(unsigned index) { const bool wait = status != THREADSTATUS_DORMANT; if (wait) { AddWaitingThread(GetCurrentThread()); - WaitCurrentThread(WAITTYPE_THREADEND, this); + WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this, index); } return MakeResult(wait); @@ -92,11 +92,11 @@ static bool CheckWaitType(const Thread* thread, WaitType type) { /// Check if a thread is blocking on a specified wait type with a specified handle static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { - auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); - if (itr == thread->wait_objects.end()) { - return false; + for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { + if (itr->first == wait_object) + return CheckWaitType(thread, type); } - return CheckWaitType(thread, type); + return false; } /// Check if a thread is blocking on a specified wait type with a specified handle and address @@ -111,7 +111,7 @@ void Thread::Stop(const char* reason) { ChangeReadyState(this, false); status = THREADSTATUS_DORMANT; - ResumeAllWaitingThreads(); + ReleaseAllWaitingThreads(); // Stopped threads are never waiting. wait_type = WAITTYPE_NONE; @@ -135,7 +135,7 @@ static void ChangeThreadState(Thread* t, ThreadStatus new_status) { } /// Arbitrate the highest priority thread that is waiting -Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) { +Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address) { Thread* highest_priority_thread = nullptr; s32 priority = THREADPRIO_LOWEST; @@ -155,19 +155,19 @@ Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) { // If a thread was arbitrated, resume it if (nullptr != highest_priority_thread) { - highest_priority_thread->ResumeFromWait(); + highest_priority_thread->ReleaseFromWait(arbiter); } return highest_priority_thread; } /// Arbitrate all threads currently waiting -void ArbitrateAllThreads(Object* arbiter, u32 address) { +void ArbitrateAllThreads(WaitObject* arbiter, u32 address) { // Iterate through threads, find highest priority thread that is waiting to be arbitrated... for (auto& thread : thread_list) { if (CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address)) - thread->ResumeFromWait(); + thread->ReleaseFromWait(arbiter); } } @@ -220,19 +220,32 @@ static Thread* NextThread() { return next; } -void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object) { +void WaitCurrentThread(WaitType wait_type) { + Thread* thread = GetCurrentThread(); + thread->wait_type = wait_type; + ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); +} + +void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_object, unsigned index) { Thread* thread = GetCurrentThread(); thread->wait_type = wait_type; - auto res = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); - if (res == thread->wait_objects.end()) { - thread->wait_objects.push_back(wait_object); + bool insert_wait_object = true; + for (auto itr = thread->wait_objects.begin(); itr < thread->wait_objects.end(); ++itr) { + if (itr->first == wait_object) { + insert_wait_object = false; + break; + } } + + if (insert_wait_object) + thread->wait_objects.push_back(std::pair, unsigned>(wait_object, index)); + ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } -void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address) { - WaitCurrentThread(wait_type, wait_object); +void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address) { + WaitCurrentThread_WaitSynchronization(WaitType::WAITTYPE_ARB, wait_object, 0); GetCurrentThread()->wait_address = wait_address; } @@ -248,6 +261,9 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) { return; } + thread->SetReturnValue(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, + ErrorSummary::StatusChanged, ErrorLevel::Info), -1); + thread->ResumeFromWait(); } @@ -262,7 +278,40 @@ void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) { CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); } -/// Resumes a thread from waiting by marking it as "ready" +void Thread::ReleaseFromWait(WaitObject* wait_object) { + if (wait_objects.empty()) { + LOG_CRITICAL(Kernel, "thread is not waiting on any objects!"); + return; + } + + // Remove this thread from the wait_object + wait_object->RemoveWaitingThread(this); + + // Find the waiting object + auto itr = wait_objects.begin(); + for (; itr != wait_objects.end(); ++itr) { + if (wait_object == itr->first) + break; + } + unsigned index = itr->second; + + // Remove the wait_object from this thread + if (itr != wait_objects.end()) + wait_objects.erase(itr); + + // If wait_all=false, resume the thread on a release wait_object from wait + if (!wait_all) { + SetReturnValue(RESULT_SUCCESS, index); + ResumeFromWait(); + } else { + // Otherwise, wait_all=true, only resume the thread if all wait_object's have been released + if (wait_objects.empty()) { + SetReturnValue(RESULT_SUCCESS, -1); + ResumeFromWait(); + } + } +} + void Thread::ResumeFromWait() { // Cancel any outstanding wakeup events CoreTiming::UnscheduleEvent(ThreadWakeupEventType, GetHandle()); @@ -271,11 +320,12 @@ void Thread::ResumeFromWait() { // Remove this thread from all other WaitObjects for (auto wait_object : wait_objects) - wait_object->RemoveWaitingThread(this); + wait_object.first->RemoveWaitingThread(this); wait_objects.clear(); wait_type = WAITTYPE_NONE; + wait_all = false; if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { ChangeReadyState(this, true); } @@ -342,6 +392,7 @@ ResultVal> Thread::Create(std::string name, VAddr entry_point, thread->initial_priority = thread->current_priority = priority; thread->processor_id = processor_id; thread->wait_type = WAITTYPE_NONE; + thread->wait_all = false; thread->wait_objects.clear(); thread->wait_address = 0; thread->name = std::move(name); @@ -432,6 +483,11 @@ void Reschedule() { } } +void Thread::SetReturnValue(ResultCode return_val, s32 out_val) { + context.cpu_registers[0] = return_val.raw; + context.cpu_registers[1] = out_val; +} + //////////////////////////////////////////////////////////////////////////////////////////////////// void ThreadingInit() { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9ec96c18c..f3dc4eec0 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -70,7 +70,7 @@ public: inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } inline bool IsIdle() const { return idle; } - ResultVal WaitSynchronization() override; + ResultVal WaitSynchronization(unsigned index) override; s32 GetPriority() const { return current_priority; } void SetPriority(s32 priority); @@ -78,9 +78,29 @@ public: u32 GetThreadId() const { return thread_id; } void Stop(const char* reason); - /// Resumes a thread from waiting by marking it as "ready". + + /** + * Release an object from the thread's wait list + * @param wait_object WaitObject to release from the thread's wait list + */ + void ReleaseFromWait(WaitObject* wait_object); + + /// Resumes a thread from waiting by marking it as "ready" void ResumeFromWait(); + /** + * Sets the waiting mode of the thread + * @param wait_all If true, wait for all objects, otherwise just wait for the first one + */ + void SetWaitAll(bool wait_all) { this->wait_all = wait_all; } + + /** + * Sets the output values after the thread awakens from WaitSynchronization + * @param return_val Value returned + * @param out_val Value to set to the output parameter + */ + void SetReturnValue(ResultCode return_val, s32 out_val); + Core::ThreadContext context; u32 thread_id; @@ -96,7 +116,7 @@ public: s32 processor_id; WaitType wait_type; - std::vector> wait_objects; + std::vector, unsigned>> wait_objects; VAddr wait_address; std::string name; @@ -105,6 +125,8 @@ public: bool idle = false; private: + bool wait_all = false; + Thread() = default; }; @@ -115,37 +137,41 @@ SharedPtr SetupMainThread(s32 priority, u32 stack_size); void Reschedule(); /// Arbitrate the highest priority thread that is waiting -Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address); +Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address); /// Arbitrate all threads currently waiting... -void ArbitrateAllThreads(Object* arbiter, u32 address); +void ArbitrateAllThreads(WaitObject* arbiter, u32 address); /// Gets the current thread Thread* GetCurrentThread(); /** - * Puts the current thread in the wait state for the given type + * Waits the current thread for the given type * @param wait_type Type of wait - * @param wait_object Kernel object that we are waiting on, defaults to current thread */ -void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object = GetCurrentThread()); +void WaitCurrentThread(WaitType wait_type); /** - * Schedules an event to wake up the specified thread after the specified delay. - * @param thread The thread to wake after the delay. - * @param nanoseconds The time this thread will be allowed to sleep for. + * Waits the current thread from a WaitSynchronization call + * @param wait_type Type of wait + * @param wait_object Kernel object that we are waiting on + * @param index Index of calling object (for WaitSynchronizationN only) */ -void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); +void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_object, unsigned index=0); /** - * Puts the current thread in the wait state for the given type - * @param wait_type Type of wait + * Waits the current thread from an ArbitrateAddress call * @param wait_object Kernel object that we are waiting on * @param wait_address Arbitration address used to resume from wait */ -void WaitCurrentThread(WaitType wait_type, WaitObject* wait_object, VAddr wait_address); - +void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address); +/** + * Schedules an event to wake up the specified thread after the specified delay. + * @param handle The thread handle. + * @param nanoseconds The time this thread will be allowed to sleep for. + */ +void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); /** * Sets up the idle thread, this is a thread that is intended to never execute instructions, diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 2d4fa4c01..c97ae6c5c 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -29,11 +29,11 @@ public: u64 initial_delay; ///< The delay until the timer fires for the first time u64 interval_delay; ///< The delay until the timer fires after the first time - ResultVal WaitSynchronization() override { + ResultVal WaitSynchronization(unsigned index) override { bool wait = !signaled; if (wait) { AddWaitingThread(GetCurrentThread()); - Kernel::WaitCurrentThread(WAITTYPE_TIMER, this); + Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_TIMER, this, index); } return MakeResult(wait); } @@ -91,7 +91,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { timer->signaled = true; // Resume all waiting threads - timer->ResumeAllWaitingThreads(); + timer->ReleaseAllWaitingThreads(); if (timer->reset_type == RESETTYPE_ONESHOT) timer->signaled = false; -- cgit v1.2.3 From aa01c57ae9d73e41b65d37860ca6fbb91caba33a Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 17 Jan 2015 22:23:49 -0500 Subject: Kernel: Separate WaitSynchronization into Wait and Acquire methods. --- src/core/hle/kernel/event.cpp | 6 +++++- src/core/hle/kernel/kernel.h | 13 +++++++++++-- src/core/hle/kernel/mutex.cpp | 19 ++++++++++++++----- src/core/hle/kernel/semaphore.cpp | 15 ++++++++++++--- src/core/hle/kernel/thread.cpp | 6 +++++- src/core/hle/kernel/thread.h | 3 ++- src/core/hle/kernel/timer.cpp | 6 +++++- 7 files changed, 54 insertions(+), 14 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 4173a980b..41e1bd6c5 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -28,7 +28,7 @@ public: bool signaled; ///< Whether the event has already been signaled std::string name; ///< Name of event (optional) - ResultVal WaitSynchronization(unsigned index) override { + ResultVal Wait(unsigned index) override { bool wait = !signaled; if (wait) { AddWaitingThread(GetCurrentThread()); @@ -36,6 +36,10 @@ public: } return MakeResult(wait); } + + ResultVal Acquire() override { + return MakeResult(true); + } }; ResultCode SignalEvent(const Handle handle) { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index af4e2f443..d98fd0389 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -65,11 +65,20 @@ public: virtual Kernel::HandleType GetHandleType() const = 0; /** - * Wait for kernel object to synchronize. + * Wait the current thread for kernel object to synchronize. * @param index Index of wait object (only applies to WaitSynchronizationN) * @return True if the current thread should wait as a result of the wait */ - virtual ResultVal WaitSynchronization(unsigned index=0) { + virtual ResultVal Wait(unsigned index = 0) { + LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); + return UnimplementedFunction(ErrorModule::Kernel); + } + + /** + * Acquire/lock the kernel object if it is available + * @return True if we were able to acquire the kernel object, otherwise false + */ + virtual ResultVal Acquire() { LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); return UnimplementedFunction(ErrorModule::Kernel); } diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 78063b8f1..37e7be4e7 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -26,7 +26,8 @@ public: Handle lock_thread; ///< Handle to thread that currently has mutex std::string name; ///< Name of mutex (optional) - ResultVal WaitSynchronization(unsigned index) override; + ResultVal Wait(unsigned index) override; + ResultVal Acquire() override; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -155,17 +156,25 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { return handle; } -ResultVal Mutex::WaitSynchronization(unsigned index) { - bool wait = locked; +ResultVal Mutex::Wait(unsigned index) { if (locked) { AddWaitingThread(GetCurrentThread()); Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_MUTEX, this, index); - } else { + } + + return MakeResult(locked); +} + +ResultVal Mutex::Acquire() { + bool res = false; + + if (!locked) { // Lock the mutex when the first thread accesses it locked = true; + res = true; MutexAcquireLock(this); } - return MakeResult(wait); + return MakeResult(res); } } // namespace diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 288928441..6464b2580 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -32,18 +32,27 @@ public: return available_count > 0; } - ResultVal WaitSynchronization(unsigned index) override { + ResultVal Wait(unsigned index) override { bool wait = !IsAvailable(); if (wait) { Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_SEMA, this, index); AddWaitingThread(GetCurrentThread()); - } else { - --available_count; } return MakeResult(wait); } + + ResultVal Acquire() override { + bool res = false; + + if (IsAvailable()) { + --available_count; + res = true; + } + + return MakeResult(res); + } }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 0c9ecc091..6b0bdebb5 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,7 +22,7 @@ namespace Kernel { -ResultVal Thread::WaitSynchronization(unsigned index) { +ResultVal Thread::Wait(unsigned index) { const bool wait = status != THREADSTATUS_DORMANT; if (wait) { AddWaitingThread(GetCurrentThread()); @@ -32,6 +32,10 @@ ResultVal Thread::WaitSynchronization(unsigned index) { return MakeResult(wait); } +ResultVal Thread::Acquire() { + return MakeResult(true); +} + // Lists all thread ids that aren't deleted/etc. static std::vector> thread_list; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index f3dc4eec0..9faf89c15 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -70,7 +70,8 @@ public: inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } inline bool IsIdle() const { return idle; } - ResultVal WaitSynchronization(unsigned index) override; + ResultVal Wait(unsigned index) override; + ResultVal Acquire() override; s32 GetPriority() const { return current_priority; } void SetPriority(s32 priority); diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index c97ae6c5c..6497bb349 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -29,7 +29,7 @@ public: u64 initial_delay; ///< The delay until the timer fires for the first time u64 interval_delay; ///< The delay until the timer fires after the first time - ResultVal WaitSynchronization(unsigned index) override { + ResultVal Wait(unsigned index) override { bool wait = !signaled; if (wait) { AddWaitingThread(GetCurrentThread()); @@ -37,6 +37,10 @@ public: } return MakeResult(wait); } + + ResultVal Acquire() override { + return MakeResult(true); + } }; /** -- cgit v1.2.3 From 6643673f28b9273149fc945849a13ed832e9ef33 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 01:27:46 -0500 Subject: WaitSynchronizationN: Refactor to fix several bugs - Separate wait checking from waiting the current thread - Resume thread when wait_all=true only if all objects are available at once - Set output to correct wait object index when there are duplicate handles --- src/core/hle/kernel/event.cpp | 6 ++-- src/core/hle/kernel/kernel.h | 12 ++++---- src/core/hle/kernel/mutex.cpp | 8 ++--- src/core/hle/kernel/semaphore.cpp | 6 ++-- src/core/hle/kernel/thread.cpp | 61 ++++++++++++++++++--------------------- src/core/hle/kernel/thread.h | 4 +-- src/core/hle/kernel/timer.cpp | 6 ++-- 7 files changed, 49 insertions(+), 54 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 41e1bd6c5..ae9b06b84 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -28,11 +28,11 @@ public: bool signaled; ///< Whether the event has already been signaled std::string name; ///< Name of event (optional) - ResultVal Wait(unsigned index) override { + ResultVal Wait(bool wait_thread) override { bool wait = !signaled; - if (wait) { + if (wait && wait_thread) { AddWaitingThread(GetCurrentThread()); - Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_EVENT, this, index); + Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_EVENT, this); } return MakeResult(wait); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index d98fd0389..cfaf0c901 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -65,18 +65,18 @@ public: virtual Kernel::HandleType GetHandleType() const = 0; /** - * Wait the current thread for kernel object to synchronize. - * @param index Index of wait object (only applies to WaitSynchronizationN) - * @return True if the current thread should wait as a result of the wait + * Check if this object is available, (optionally) wait the current thread if not + * @param wait_thread If true, wait the current thread if this object is unavailable + * @return True if the current thread should wait due to this object being unavailable */ - virtual ResultVal Wait(unsigned index = 0) { + virtual ResultVal Wait(bool wait_thread) { LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); return UnimplementedFunction(ErrorModule::Kernel); } /** - * Acquire/lock the kernel object if it is available - * @return True if we were able to acquire the kernel object, otherwise false + * Acquire/lock the this object if it is available + * @return True if we were able to acquire this object, otherwise false */ virtual ResultVal Acquire() { LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 37e7be4e7..f97c69a78 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -26,7 +26,7 @@ public: Handle lock_thread; ///< Handle to thread that currently has mutex std::string name; ///< Name of mutex (optional) - ResultVal Wait(unsigned index) override; + ResultVal Wait(bool wait_thread) override; ResultVal Acquire() override; }; @@ -156,10 +156,10 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { return handle; } -ResultVal Mutex::Wait(unsigned index) { - if (locked) { +ResultVal Mutex::Wait(bool wait_thread) { + if (locked && wait_thread) { AddWaitingThread(GetCurrentThread()); - Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_MUTEX, this, index); + Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_MUTEX, this); } return MakeResult(locked); diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 6464b2580..42b5cf704 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -32,11 +32,11 @@ public: return available_count > 0; } - ResultVal Wait(unsigned index) override { + ResultVal Wait(bool wait_thread) override { bool wait = !IsAvailable(); - if (wait) { - Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_SEMA, this, index); + if (wait && wait_thread) { + Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_SEMA, this); AddWaitingThread(GetCurrentThread()); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 6b0bdebb5..62b85f56a 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,11 +22,11 @@ namespace Kernel { -ResultVal Thread::Wait(unsigned index) { +ResultVal Thread::Wait(bool wait_thread) { const bool wait = status != THREADSTATUS_DORMANT; - if (wait) { + if (wait && wait_thread) { AddWaitingThread(GetCurrentThread()); - WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this, index); + WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this); } return MakeResult(wait); @@ -97,7 +97,7 @@ static bool CheckWaitType(const Thread* thread, WaitType type) { /// Check if a thread is blocking on a specified wait type with a specified handle static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { - if (itr->first == wait_object) + if (*itr == wait_object) return CheckWaitType(thread, type); } return false; @@ -234,16 +234,7 @@ void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_ Thread* thread = GetCurrentThread(); thread->wait_type = wait_type; - bool insert_wait_object = true; - for (auto itr = thread->wait_objects.begin(); itr < thread->wait_objects.end(); ++itr) { - if (itr->first == wait_object) { - insert_wait_object = false; - break; - } - } - - if (insert_wait_object) - thread->wait_objects.push_back(std::pair, unsigned>(wait_object, index)); + thread->wait_objects.push_back(wait_object); ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } @@ -288,31 +279,35 @@ void Thread::ReleaseFromWait(WaitObject* wait_object) { return; } - // Remove this thread from the wait_object + // Remove this thread from the waiting object's thread list wait_object->RemoveWaitingThread(this); - // Find the waiting object - auto itr = wait_objects.begin(); - for (; itr != wait_objects.end(); ++itr) { - if (wait_object == itr->first) - break; - } - unsigned index = itr->second; + unsigned index = 0; + bool wait_all_failed = false; // Will be set to true if any object is unavailable - // Remove the wait_object from this thread - if (itr != wait_objects.end()) - wait_objects.erase(itr); + // Iterate through all waiting objects to check availability... + for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { + auto res = (*itr)->Wait(false); - // If wait_all=false, resume the thread on a release wait_object from wait - if (!wait_all) { - SetReturnValue(RESULT_SUCCESS, index); - ResumeFromWait(); - } else { - // Otherwise, wait_all=true, only resume the thread if all wait_object's have been released - if (wait_objects.empty()) { + if (*res && res.Succeeded()) + wait_all_failed = true; + + // The output should be the last index of wait_object + if (*itr == wait_object) + index = itr - wait_objects.begin(); + } + + // If we are waiting on all objects... + if (wait_all) { + // Resume the thread only if all are available... + if (!wait_all_failed) { SetReturnValue(RESULT_SUCCESS, -1); ResumeFromWait(); } + } else { + // Otherwise, resume + SetReturnValue(RESULT_SUCCESS, index); + ResumeFromWait(); } } @@ -324,7 +319,7 @@ void Thread::ResumeFromWait() { // Remove this thread from all other WaitObjects for (auto wait_object : wait_objects) - wait_object.first->RemoveWaitingThread(this); + wait_object->RemoveWaitingThread(this); wait_objects.clear(); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9faf89c15..dff6bbaec 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -70,7 +70,7 @@ public: inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } inline bool IsIdle() const { return idle; } - ResultVal Wait(unsigned index) override; + ResultVal Wait(bool wait_thread) override; ResultVal Acquire() override; s32 GetPriority() const { return current_priority; } @@ -117,7 +117,7 @@ public: s32 processor_id; WaitType wait_type; - std::vector, unsigned>> wait_objects; + std::vector> wait_objects; VAddr wait_address; std::string name; diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 6497bb349..9f0fbafe2 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -29,11 +29,11 @@ public: u64 initial_delay; ///< The delay until the timer fires for the first time u64 interval_delay; ///< The delay until the timer fires after the first time - ResultVal Wait(unsigned index) override { + ResultVal Wait(bool wait_thread) override { bool wait = !signaled; - if (wait) { + if (wait && wait_thread) { AddWaitingThread(GetCurrentThread()); - Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_TIMER, this, index); + Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_TIMER, this); } return MakeResult(wait); } -- cgit v1.2.3 From e5a9f1c64483e01b7856c581ae5685d0c5ad88dc Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 13:25:51 -0500 Subject: Kernel: Get rid of WaitTypes and simplify lots of code, removing hacks. --- src/core/hle/kernel/event.cpp | 9 ++---- src/core/hle/kernel/kernel.cpp | 6 ++-- src/core/hle/kernel/kernel.h | 5 ++- src/core/hle/kernel/mutex.cpp | 9 ++---- src/core/hle/kernel/semaphore.cpp | 11 ++----- src/core/hle/kernel/thread.cpp | 65 ++++++++++++--------------------------- src/core/hle/kernel/thread.h | 41 ++++++------------------ src/core/hle/kernel/timer.cpp | 9 ++---- 8 files changed, 43 insertions(+), 112 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index ae9b06b84..399730cb1 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -28,13 +28,8 @@ public: bool signaled; ///< Whether the event has already been signaled std::string name; ///< Name of event (optional) - ResultVal Wait(bool wait_thread) override { - bool wait = !signaled; - if (wait && wait_thread) { - AddWaitingThread(GetCurrentThread()); - Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_EVENT, this); - } - return MakeResult(wait); + ResultVal Wait() override { + return MakeResult(!signaled); } ResultVal Acquire() override { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index be3495412..57e0e8df7 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -42,13 +42,15 @@ Thread* WaitObject::ReleaseNextThread() { return next_thread.get(); } -void WaitObject::ReleaseAllWaitingThreads() { +void WaitObject::WakeupAllWaitingThreads() { auto waiting_threads_copy = waiting_threads; + // We use a copy because ReleaseWaitObject will remove the thread from this object's + // waiting_threads list for (auto thread : waiting_threads_copy) thread->ReleaseWaitObject(this); - waiting_threads.clear(); + _assert_msg_(Kernel, waiting_threads.empty(), "failed to awaken all waiting threads!"); } HandleTable::HandleTable() { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index cfaf0c901..5bf9a2bfc 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -65,11 +65,10 @@ public: virtual Kernel::HandleType GetHandleType() const = 0; /** - * Check if this object is available, (optionally) wait the current thread if not - * @param wait_thread If true, wait the current thread if this object is unavailable + * Check if this object is available * @return True if the current thread should wait due to this object being unavailable */ - virtual ResultVal Wait(bool wait_thread) { + virtual ResultVal Wait() { LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); return UnimplementedFunction(ErrorModule::Kernel); } diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index f97c69a78..4a1eaca37 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -26,7 +26,7 @@ public: Handle lock_thread; ///< Handle to thread that currently has mutex std::string name; ///< Name of mutex (optional) - ResultVal Wait(bool wait_thread) override; + ResultVal Wait() override; ResultVal Acquire() override; }; @@ -156,12 +156,7 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { return handle; } -ResultVal Mutex::Wait(bool wait_thread) { - if (locked && wait_thread) { - AddWaitingThread(GetCurrentThread()); - Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_MUTEX, this); - } - +ResultVal Mutex::Wait() { return MakeResult(locked); } diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 42b5cf704..6ccdb2a8f 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -32,15 +32,8 @@ public: return available_count > 0; } - ResultVal Wait(bool wait_thread) override { - bool wait = !IsAvailable(); - - if (wait && wait_thread) { - Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_SEMA, this); - AddWaitingThread(GetCurrentThread()); - } - - return MakeResult(wait); + ResultVal Wait() override { + return MakeResult(!IsAvailable()); } ResultVal Acquire() override { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 62b85f56a..601e0eb20 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,14 +22,8 @@ namespace Kernel { -ResultVal Thread::Wait(bool wait_thread) { - const bool wait = status != THREADSTATUS_DORMANT; - if (wait && wait_thread) { - AddWaitingThread(GetCurrentThread()); - WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this); - } - - return MakeResult(wait); +ResultVal Thread::Wait() { + return MakeResult(status != THREADSTATUS_DORMANT); } ResultVal Thread::Acquire() { @@ -68,7 +62,7 @@ static void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { if (t->current_priority < lowest_priority) { t->current_priority = t->initial_priority; } - t->wait_type = WAITTYPE_NONE; + t->wait_objects.clear(); t->wait_address = 0; } @@ -89,23 +83,18 @@ static void ChangeReadyState(Thread* t, bool ready) { } } -/// Check if a thread is blocking on a specified wait type -static bool CheckWaitType(const Thread* thread, WaitType type) { - return (type == thread->wait_type) && (thread->IsWaiting()); -} - -/// Check if a thread is blocking on a specified wait type with a specified handle -static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { +/// Check if a thread is blocking on a the specified object +static bool CheckWaitType(const Thread* thread, Object* wait_object) { for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { if (*itr == wait_object) - return CheckWaitType(thread, type); + return (thread->IsWaiting()); } return false; } -/// Check if a thread is blocking on a specified wait type with a specified handle and address -static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object, VAddr wait_address) { - return CheckWaitType(thread, type, wait_object) && (wait_address == thread->wait_address); +/// Check if a thread is blocking on a the specified object and an address +static bool CheckWaitType(const Thread* thread, Object* wait_object, VAddr wait_address) { + return CheckWaitType(thread, wait_object) && (wait_address == thread->wait_address); } /// Stops the current thread @@ -118,7 +107,6 @@ void Thread::Stop(const char* reason) { ReleaseAllWaitingThreads(); // Stopped threads are never waiting. - wait_type = WAITTYPE_NONE; wait_objects.clear(); wait_address = 0; } @@ -130,12 +118,6 @@ static void ChangeThreadState(Thread* t, ThreadStatus new_status) { } ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0); t->status = new_status; - - if (new_status == THREADSTATUS_WAIT) { - if (t->wait_type == WAITTYPE_NONE) { - LOG_ERROR(Kernel, "Waittype none not allowed"); - } - } } /// Arbitrate the highest priority thread that is waiting @@ -145,7 +127,7 @@ Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address) { // Iterate through threads, find highest priority thread that is waiting to be arbitrated... for (auto& thread : thread_list) { - if (!CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address)) + if (!CheckWaitType(thread.get(), arbiter, address)) continue; if (thread == nullptr) @@ -170,7 +152,7 @@ void ArbitrateAllThreads(WaitObject* arbiter, u32 address) { // Iterate through threads, find highest priority thread that is waiting to be arbitrated... for (auto& thread : thread_list) { - if (CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address)) + if (CheckWaitType(thread.get(), arbiter, address)) thread->ReleaseFromWait(arbiter); } } @@ -178,9 +160,6 @@ void ArbitrateAllThreads(WaitObject* arbiter, u32 address) { /// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields) static void CallThread(Thread* t) { // Stop waiting - if (t->wait_type != WAITTYPE_NONE) { - t->wait_type = WAITTYPE_NONE; - } ChangeThreadState(t, THREADSTATUS_READY); } @@ -201,7 +180,6 @@ static void SwitchContext(Thread* t) { current_thread = t; ChangeReadyState(t, false); t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY; - t->wait_type = WAITTYPE_NONE; Core::g_app_core->LoadContext(t->context); } else { current_thread = nullptr; @@ -224,23 +202,20 @@ static Thread* NextThread() { return next; } -void WaitCurrentThread(WaitType wait_type) { +void WaitCurrentThread() { Thread* thread = GetCurrentThread(); - thread->wait_type = wait_type; ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } -void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_object, unsigned index) { +void WaitCurrentThread_WaitSynchronization(WaitObject* wait_object, bool wait_all) { Thread* thread = GetCurrentThread(); - thread->wait_type = wait_type; - + thread->wait_all = wait_all; thread->wait_objects.push_back(wait_object); - ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address) { - WaitCurrentThread_WaitSynchronization(WaitType::WAITTYPE_ARB, wait_object, 0); + WaitCurrentThread_WaitSynchronization(wait_object); GetCurrentThread()->wait_address = wait_address; } @@ -287,7 +262,7 @@ void Thread::ReleaseFromWait(WaitObject* wait_object) { // Iterate through all waiting objects to check availability... for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { - auto res = (*itr)->Wait(false); + auto res = (*itr)->Wait(); if (*res && res.Succeeded()) wait_all_failed = true; @@ -322,9 +297,8 @@ void Thread::ResumeFromWait() { wait_object->RemoveWaitingThread(this); wait_objects.clear(); - - wait_type = WAITTYPE_NONE; wait_all = false; + if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { ChangeReadyState(this, true); } @@ -390,7 +364,6 @@ ResultVal> Thread::Create(std::string name, VAddr entry_point, thread->stack_size = stack_size; thread->initial_priority = thread->current_priority = priority; thread->processor_id = processor_id; - thread->wait_type = WAITTYPE_NONE; thread->wait_all = false; thread->wait_objects.clear(); thread->wait_address = 0; @@ -476,8 +449,8 @@ void Reschedule() { LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); for (auto& thread : thread_list) { - LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X", - thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type); + LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X", thread->GetHandle(), + thread->current_priority, thread->status); } } } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index dff6bbaec..cb48fcadc 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -38,18 +38,6 @@ enum ThreadStatus { THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND }; -enum WaitType { - WAITTYPE_NONE, - WAITTYPE_SLEEP, - WAITTYPE_SEMA, - WAITTYPE_EVENT, - WAITTYPE_THREADEND, - WAITTYPE_MUTEX, - WAITTYPE_SYNCH, - WAITTYPE_ARB, - WAITTYPE_TIMER, -}; - namespace Kernel { class Thread : public WaitObject { @@ -70,7 +58,7 @@ public: inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } inline bool IsIdle() const { return idle; } - ResultVal Wait(bool wait_thread) override; + ResultVal Wait() override; ResultVal Acquire() override; s32 GetPriority() const { return current_priority; } @@ -89,12 +77,6 @@ public: /// Resumes a thread from waiting by marking it as "ready" void ResumeFromWait(); - /** - * Sets the waiting mode of the thread - * @param wait_all If true, wait for all objects, otherwise just wait for the first one - */ - void SetWaitAll(bool wait_all) { this->wait_all = wait_all; } - /** * Sets the output values after the thread awakens from WaitSynchronization * @param return_val Value returned @@ -116,9 +98,10 @@ public: s32 processor_id; - WaitType wait_type; - std::vector> wait_objects; - VAddr wait_address; + std::vector> wait_objects; ///< Objects that the thread is waiting on + + VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address + bool wait_all; ///< True if the thread is waiting on all objects before resuming std::string name; @@ -126,7 +109,6 @@ public: bool idle = false; private: - bool wait_all = false; Thread() = default; }; @@ -146,19 +128,15 @@ void ArbitrateAllThreads(WaitObject* arbiter, u32 address); /// Gets the current thread Thread* GetCurrentThread(); -/** - * Waits the current thread for the given type - * @param wait_type Type of wait - */ -void WaitCurrentThread(WaitType wait_type); +/// Waits the current thread +void WaitCurrentThread(); /** * Waits the current thread from a WaitSynchronization call - * @param wait_type Type of wait * @param wait_object Kernel object that we are waiting on - * @param index Index of calling object (for WaitSynchronizationN only) + * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only) */ -void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_object, unsigned index=0); +void WaitCurrentThread_WaitSynchronization(WaitObject* wait_object, bool wait_all=false); /** * Waits the current thread from an ArbitrateAddress call @@ -181,6 +159,7 @@ void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds); * @returns The handle of the idle thread */ Handle SetupIdleThread(); + /// Initialize threading void ThreadingInit(); diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 9f0fbafe2..62bdf07c7 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -29,13 +29,8 @@ public: u64 initial_delay; ///< The delay until the timer fires for the first time u64 interval_delay; ///< The delay until the timer fires after the first time - ResultVal Wait(bool wait_thread) override { - bool wait = !signaled; - if (wait && wait_thread) { - AddWaitingThread(GetCurrentThread()); - Kernel::WaitCurrentThread_WaitSynchronization(WAITTYPE_TIMER, this); - } - return MakeResult(wait); + ResultVal Wait() override { + return MakeResult(!signaled); } ResultVal Acquire() override { -- cgit v1.2.3 From 254e4ebd58a31e8462b70799f95f096d0d0038f2 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 13:56:40 -0500 Subject: AddressArbiter: Changed to Kernel::Object, big cleanup, removed code that made no sense. --- src/core/hle/kernel/address_arbiter.cpp | 16 ++++++------- src/core/hle/kernel/kernel.cpp | 2 +- src/core/hle/kernel/thread.cpp | 42 ++++++++++++++++++++------------- src/core/hle/kernel/thread.h | 17 +++++++------ 4 files changed, 42 insertions(+), 35 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 520601455..9e855b0bf 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -15,7 +15,7 @@ namespace Kernel { -class AddressArbiter : public WaitObject { +class AddressArbiter : public Object { public: std::string GetTypeName() const override { return "Arbiter"; } std::string GetName() const override { return name; } @@ -30,7 +30,7 @@ public: /// Arbitrate an address ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value, u64 nanoseconds) { - WaitObject* object = static_cast(Kernel::g_handle_table.GetGeneric(handle).get()); + AddressArbiter* object = Kernel::g_handle_table.Get(handle).get(); if (object == nullptr) return InvalidHandle(ErrorModule::Kernel); @@ -41,24 +41,24 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 case ArbitrationType::Signal: // Negative value means resume all threads if (value < 0) { - ArbitrateAllThreads(object, address); + ArbitrateAllThreads(address); } else { // Resume first N threads for(int i = 0; i < value; i++) - ArbitrateHighestPriorityThread(object, address); + ArbitrateHighestPriorityThread(address); } break; // Wait current thread (acquire the arbiter)... case ArbitrationType::WaitIfLessThan: if ((s32)Memory::Read32(address) <= value) { - Kernel::WaitCurrentThread_ArbitrateAddress(object, address); + Kernel::WaitCurrentThread_ArbitrateAddress(address); HLE::Reschedule(__func__); } break; case ArbitrationType::WaitIfLessThanWithTimeout: if ((s32)Memory::Read32(address) <= value) { - Kernel::WaitCurrentThread_ArbitrateAddress(object, address); + Kernel::WaitCurrentThread_ArbitrateAddress(address); Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); HLE::Reschedule(__func__); } @@ -68,7 +68,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 s32 memory_value = Memory::Read32(address) - 1; Memory::Write32(address, memory_value); if (memory_value <= value) { - Kernel::WaitCurrentThread_ArbitrateAddress(object, address); + Kernel::WaitCurrentThread_ArbitrateAddress(address); HLE::Reschedule(__func__); } break; @@ -78,7 +78,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 s32 memory_value = Memory::Read32(address) - 1; Memory::Write32(address, memory_value); if (memory_value <= value) { - Kernel::WaitCurrentThread_ArbitrateAddress(object, address); + Kernel::WaitCurrentThread_ArbitrateAddress(address); Kernel::WakeThreadAfterDelay(GetCurrentThread(), nanoseconds); HLE::Reschedule(__func__); } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 57e0e8df7..b3ca78ed6 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -36,7 +36,7 @@ Thread* WaitObject::ReleaseNextThread() { auto next_thread = waiting_threads.front(); - next_thread->ReleaseFromWait(this); + next_thread->ReleaseWaitObject(this); waiting_threads.erase(waiting_threads.begin()); return next_thread.get(); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 601e0eb20..16865ccc4 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -83,8 +83,8 @@ static void ChangeReadyState(Thread* t, bool ready) { } } -/// Check if a thread is blocking on a the specified object -static bool CheckWaitType(const Thread* thread, Object* wait_object) { +/// Check if a thread is waiting on a the specified wait object +static bool CheckWait_WaitObject(const Thread* thread, WaitObject* wait_object) { for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { if (*itr == wait_object) return (thread->IsWaiting()); @@ -92,9 +92,9 @@ static bool CheckWaitType(const Thread* thread, Object* wait_object) { return false; } -/// Check if a thread is blocking on a the specified object and an address -static bool CheckWaitType(const Thread* thread, Object* wait_object, VAddr wait_address) { - return CheckWaitType(thread, wait_object) && (wait_address == thread->wait_address); +/// Check if the specified thread is waiting on the specified address to be arbitrated +static bool CheckWait_AddressArbiter(const Thread* thread, VAddr wait_address) { + return thread->IsWaiting() && thread->wait_objects.empty() && wait_address == thread->wait_address; } /// Stops the current thread @@ -121,17 +121,17 @@ static void ChangeThreadState(Thread* t, ThreadStatus new_status) { } /// Arbitrate the highest priority thread that is waiting -Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address) { +Thread* ArbitrateHighestPriorityThread(u32 address) { Thread* highest_priority_thread = nullptr; s32 priority = THREADPRIO_LOWEST; // Iterate through threads, find highest priority thread that is waiting to be arbitrated... for (auto& thread : thread_list) { - if (!CheckWaitType(thread.get(), arbiter, address)) + if (!CheckWait_AddressArbiter(thread.get(), address)) continue; if (thread == nullptr) - continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. + continue; if(thread->current_priority <= priority) { highest_priority_thread = thread.get(); @@ -141,19 +141,19 @@ Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address) { // If a thread was arbitrated, resume it if (nullptr != highest_priority_thread) { - highest_priority_thread->ReleaseFromWait(arbiter); + highest_priority_thread->ResumeFromWait(); } return highest_priority_thread; } /// Arbitrate all threads currently waiting -void ArbitrateAllThreads(WaitObject* arbiter, u32 address) { +void ArbitrateAllThreads(u32 address) { // Iterate through threads, find highest priority thread that is waiting to be arbitrated... for (auto& thread : thread_list) { - if (CheckWaitType(thread.get(), arbiter, address)) - thread->ReleaseFromWait(arbiter); + if (CheckWait_AddressArbiter(thread.get(), address)) + thread->ResumeFromWait(); } } @@ -202,21 +202,28 @@ static Thread* NextThread() { return next; } -void WaitCurrentThread() { +void WaitCurrentThread_Sleep() { Thread* thread = GetCurrentThread(); + thread->wait_all = false; + thread->wait_address = 0; + thread->wait_objects.clear(); ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } void WaitCurrentThread_WaitSynchronization(WaitObject* wait_object, bool wait_all) { Thread* thread = GetCurrentThread(); thread->wait_all = wait_all; + thread->wait_address = 0; thread->wait_objects.push_back(wait_object); ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } -void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address) { - WaitCurrentThread_WaitSynchronization(wait_object); - GetCurrentThread()->wait_address = wait_address; +void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { + Thread* thread = GetCurrentThread(); + thread->wait_all = false; + thread->wait_address = wait_address; + thread->wait_objects.clear(); + ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } /// Event type for the thread wake up event @@ -248,7 +255,7 @@ void WakeThreadAfterDelay(Thread* thread, s64 nanoseconds) { CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, thread->GetHandle()); } -void Thread::ReleaseFromWait(WaitObject* wait_object) { +void Thread::ReleaseWaitObject(WaitObject* wait_object) { if (wait_objects.empty()) { LOG_CRITICAL(Kernel, "thread is not waiting on any objects!"); return; @@ -298,6 +305,7 @@ void Thread::ResumeFromWait() { wait_objects.clear(); wait_all = false; + wait_address = 0; if (!(status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { ChangeReadyState(this, true); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index cb48fcadc..9907aa6e1 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -69,10 +69,10 @@ public: void Stop(const char* reason); /** - * Release an object from the thread's wait list - * @param wait_object WaitObject to release from the thread's wait list + * Release an acquired wait object + * @param wait_object WaitObject to release */ - void ReleaseFromWait(WaitObject* wait_object); + void ReleaseWaitObject(WaitObject* wait_object); /// Resumes a thread from waiting by marking it as "ready" void ResumeFromWait(); @@ -120,16 +120,16 @@ SharedPtr SetupMainThread(s32 priority, u32 stack_size); void Reschedule(); /// Arbitrate the highest priority thread that is waiting -Thread* ArbitrateHighestPriorityThread(WaitObject* arbiter, u32 address); +Thread* ArbitrateHighestPriorityThread(u32 address); /// Arbitrate all threads currently waiting... -void ArbitrateAllThreads(WaitObject* arbiter, u32 address); +void ArbitrateAllThreads(u32 address); /// Gets the current thread Thread* GetCurrentThread(); -/// Waits the current thread -void WaitCurrentThread(); +/// Waits the current thread on a sleep +void WaitCurrentThread_Sleep(); /** * Waits the current thread from a WaitSynchronization call @@ -140,10 +140,9 @@ void WaitCurrentThread_WaitSynchronization(WaitObject* wait_object, bool wait_al /** * Waits the current thread from an ArbitrateAddress call - * @param wait_object Kernel object that we are waiting on * @param wait_address Arbitration address used to resume from wait */ -void WaitCurrentThread_ArbitrateAddress(WaitObject* wait_object, VAddr wait_address); +void WaitCurrentThread_ArbitrateAddress(VAddr wait_address); /** * Schedules an event to wake up the specified thread after the specified delay. -- cgit v1.2.3 From 9412996c8f86f5da5a9052f7533b05e9780c4eb0 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 14:33:11 -0500 Subject: Kernel: Moved Wait and Acquire to WaitObject, added way to retrieve a WaitObject safely. --- src/core/hle/kernel/kernel.h | 71 ++++++++++++++++++++++++++++++++---------- src/core/hle/kernel/thread.cpp | 2 +- src/core/hle/kernel/thread.h | 2 +- 3 files changed, 57 insertions(+), 18 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 5bf9a2bfc..a9a893f41 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -60,26 +60,34 @@ class Object : NonCopyable { public: virtual ~Object() {} Handle GetHandle() const { return handle; } + virtual std::string GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; } virtual std::string GetName() const { return "[UNKNOWN KERNEL OBJECT]"; } virtual Kernel::HandleType GetHandleType() const = 0; /** - * Check if this object is available - * @return True if the current thread should wait due to this object being unavailable + * Check if a thread can wait on the object + * @return True if a thread can wait on the object, otherwise false */ - virtual ResultVal Wait() { - LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); - return UnimplementedFunction(ErrorModule::Kernel); - } + bool IsWaitable() const { + switch (GetHandleType()) { + case HandleType::Event: + case HandleType::Mutex: + case HandleType::Thread: + case HandleType::Semaphore: + case HandleType::Timer: + return true; + + case HandleType::Unknown: + case HandleType::Port: + case HandleType::SharedMemory: + case HandleType::Redirection: + case HandleType::Process: + case HandleType::AddressArbiter: + return false; + } - /** - * Acquire/lock the this object if it is available - * @return True if we were able to acquire this object, otherwise false - */ - virtual ResultVal Acquire() { - LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); - return UnimplementedFunction(ErrorModule::Kernel); + return false; } private: @@ -107,6 +115,24 @@ using SharedPtr = boost::intrusive_ptr; class WaitObject : public Object { public: + /** + * Check if this object is available + * @return True if the current thread should wait due to this object being unavailable + */ + virtual ResultVal Wait() { + LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); + return UnimplementedFunction(ErrorModule::Kernel); + } + + /** + * Acquire/lock the this object if it is available + * @return True if we were able to acquire this object, otherwise false + */ + virtual ResultVal Acquire() { + LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); + return UnimplementedFunction(ErrorModule::Kernel); + } + /** * Add a thread to wait on this object * @param thread Pointer to thread to add @@ -186,14 +212,14 @@ public: /** * Looks up a handle. - * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid. + * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid. */ SharedPtr GetGeneric(Handle handle) const; /** * Looks up a handle while verifying its type. - * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid or its - * type differs from the handle type `T::HANDLE_TYPE`. + * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its + * type differs from the handle type `T::HANDLE_TYPE`. */ template SharedPtr Get(Handle handle) const { @@ -204,6 +230,19 @@ public: return nullptr; } + /** + * Looks up a handle while verifying that it is an object that a thread can wait on + * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or it is + * not a waitable object. + */ + SharedPtr GetWaitObject(Handle handle) const { + SharedPtr object = GetGeneric(handle); + if (object != nullptr && object->IsWaitable()) { + return boost::static_pointer_cast(std::move(object)); + } + return nullptr; + } + /// Closes all handles held in this table. void Clear(); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 16865ccc4..271828ea7 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -210,7 +210,7 @@ void WaitCurrentThread_Sleep() { ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } -void WaitCurrentThread_WaitSynchronization(WaitObject* wait_object, bool wait_all) { +void WaitCurrentThread_WaitSynchronization(SharedPtr wait_object, bool wait_all) { Thread* thread = GetCurrentThread(); thread->wait_all = wait_all; thread->wait_address = 0; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9907aa6e1..a3a17e6c0 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -136,7 +136,7 @@ void WaitCurrentThread_Sleep(); * @param wait_object Kernel object that we are waiting on * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only) */ -void WaitCurrentThread_WaitSynchronization(WaitObject* wait_object, bool wait_all=false); +void WaitCurrentThread_WaitSynchronization(SharedPtr wait_object, bool wait_all = false); /** * Waits the current thread from an ArbitrateAddress call -- cgit v1.2.3 From dde02f79af45fc01d747254eefbe680e580c3d45 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 15:45:01 -0500 Subject: Mutex: Fix a bug where the thread should not wait if it already has the mutex. --- src/core/hle/kernel/mutex.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 4a1eaca37..6cd140376 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -25,6 +25,7 @@ public: bool locked; ///< Current locked state Handle lock_thread; ///< Handle to thread that currently has mutex std::string name; ///< Name of mutex (optional) + SharedPtr current_thread; ///< Thread that has acquired the mutex ResultVal Wait() override; ResultVal Acquire() override; @@ -43,6 +44,7 @@ static MutexMap g_mutex_held_locks; void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandle()) { g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); mutex->lock_thread = thread; + mutex->current_thread = Kernel::g_handle_table.Get(thread); } /** @@ -132,6 +134,7 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) mutex->locked = mutex->initial_locked = initial_locked; mutex->name = name; + mutex->current_thread = nullptr; // Acquire mutex with current thread if initialized as locked... if (mutex->locked) { @@ -157,7 +160,7 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { } ResultVal Mutex::Wait() { - return MakeResult(locked); + return MakeResult(locked && (current_thread != GetCurrentThread())); } ResultVal Mutex::Acquire() { -- cgit v1.2.3 From d2759c578e8cf24277767f701d5682f7b1792a9f Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 18:01:58 -0500 Subject: Kernel: Reschedule on SignalEvent and SendSyncRequest, fix some bugs. --- src/core/hle/kernel/kernel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b3ca78ed6..6f1dced70 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -35,9 +35,9 @@ Thread* WaitObject::ReleaseNextThread() { return nullptr; auto next_thread = waiting_threads.front(); + waiting_threads.erase(waiting_threads.begin()); next_thread->ReleaseWaitObject(this); - waiting_threads.erase(waiting_threads.begin()); return next_thread.get(); } -- cgit v1.2.3 From 9e6ec3b6cd23a7cef80a1d62fda515018f080083 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 20:40:53 -0500 Subject: Session: Change to a WaitObject. --- src/core/hle/kernel/kernel.cpp | 2 +- src/core/hle/kernel/kernel.h | 1 + src/core/hle/kernel/session.h | 8 +++++++- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 6f1dced70..692349857 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -39,7 +39,7 @@ Thread* WaitObject::ReleaseNextThread() { next_thread->ReleaseWaitObject(this); - return next_thread.get(); + return next_thread; } void WaitObject::WakeupAllWaitingThreads() { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index a9a893f41..ca9ccf4bf 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -71,6 +71,7 @@ public: */ bool IsWaitable() const { switch (GetHandleType()) { + case HandleType::Session: case HandleType::Event: case HandleType::Mutex: case HandleType::Thread: diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 91f3ffc2c..e11f727a5 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -41,7 +41,7 @@ inline static u32* GetCommandBuffer(const int offset=0) { * CTR-OS so that IPC calls can be optionally handled by the real implementations of processes, as * opposed to HLE simulations. */ -class Session : public Object { +class Session : public WaitObject { public: std::string GetTypeName() const override { return "Session"; } @@ -53,6 +53,12 @@ public: * aren't supported yet. */ virtual ResultVal SyncRequest() = 0; + + ResultVal Wait() override { + // TODO(bunnei): This function exists to satisfy a hardware test with a Session object + // passed into WaitSynchronization. Not sure if it's possible for this to ever be false? + return MakeResult(true); + } }; } -- cgit v1.2.3 From 69c5830ef2a0190803e176615d5cb16d5462b971 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 19 Jan 2015 03:30:55 -0500 Subject: Event: Fix implementation of "non-sticky" events. --- src/core/hle/kernel/event.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 399730cb1..37f01652e 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -33,6 +33,10 @@ public: } ResultVal Acquire() override { + // Release the event if it's not sticky... + if (reset_type != RESETTYPE_STICKY) + signaled = false; + return MakeResult(true); } }; -- cgit v1.2.3 From c68eb1569549ae49ae25c6c29cec2e10d8329f2d Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 17:41:12 -0500 Subject: WaitObject: Renamed "Wait" to "ShouldWait", made "ShouldWait" and "Acquire" pure virtual. --- src/core/hle/kernel/event.cpp | 2 +- src/core/hle/kernel/kernel.h | 14 ++++---------- src/core/hle/kernel/mutex.cpp | 4 ++-- src/core/hle/kernel/semaphore.cpp | 2 +- src/core/hle/kernel/session.h | 11 ++++++++--- src/core/hle/kernel/thread.cpp | 4 ++-- src/core/hle/kernel/thread.h | 2 +- src/core/hle/kernel/timer.cpp | 2 +- 8 files changed, 20 insertions(+), 21 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 37f01652e..bed856020 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -28,7 +28,7 @@ public: bool signaled; ///< Whether the event has already been signaled std::string name; ///< Name of event (optional) - ResultVal Wait() override { + ResultVal ShouldWait() override { return MakeResult(!signaled); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index ca9ccf4bf..1bb0b55bd 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -117,22 +117,16 @@ class WaitObject : public Object { public: /** - * Check if this object is available + * Check if the current thread should wait until the object is available * @return True if the current thread should wait due to this object being unavailable */ - virtual ResultVal Wait() { - LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); - return UnimplementedFunction(ErrorModule::Kernel); - } + virtual ResultVal ShouldWait() = 0; /** - * Acquire/lock the this object if it is available + * Acquire/lock the object if it is available * @return True if we were able to acquire this object, otherwise false */ - virtual ResultVal Acquire() { - LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); - return UnimplementedFunction(ErrorModule::Kernel); - } + virtual ResultVal Acquire() = 0; /** * Add a thread to wait on this object diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 6cd140376..01d2263ff 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -27,7 +27,7 @@ public: std::string name; ///< Name of mutex (optional) SharedPtr current_thread; ///< Thread that has acquired the mutex - ResultVal Wait() override; + ResultVal ShouldWait() override; ResultVal Acquire() override; }; @@ -159,7 +159,7 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { return handle; } -ResultVal Mutex::Wait() { +ResultVal Mutex::ShouldWait() { return MakeResult(locked && (current_thread != GetCurrentThread())); } diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 6ccdb2a8f..24d41c0b3 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -32,7 +32,7 @@ public: return available_count > 0; } - ResultVal Wait() override { + ResultVal ShouldWait() override { return MakeResult(!IsAvailable()); } diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index e11f727a5..f0343d9b2 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -54,11 +54,16 @@ public: */ virtual ResultVal SyncRequest() = 0; - ResultVal Wait() override { - // TODO(bunnei): This function exists to satisfy a hardware test with a Session object - // passed into WaitSynchronization. Not sure if it's possible for this to ever be false? + // TODO(bunnei): These functions exist to satisfy a hardware test with a Session object + // passed into WaitSynchronization. Figure out the meaning of them. + + ResultVal ShouldWait() override { return MakeResult(true); } + + ResultVal Acquire() override { + return MakeResult(false); + } }; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 271828ea7..8a2cf8bf4 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,7 +22,7 @@ namespace Kernel { -ResultVal Thread::Wait() { +ResultVal Thread::ShouldWait() { return MakeResult(status != THREADSTATUS_DORMANT); } @@ -269,7 +269,7 @@ void Thread::ReleaseWaitObject(WaitObject* wait_object) { // Iterate through all waiting objects to check availability... for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { - auto res = (*itr)->Wait(); + auto res = (*itr)->ShouldWait(); if (*res && res.Succeeded()) wait_all_failed = true; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index a3a17e6c0..b23638bd1 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -58,7 +58,7 @@ public: inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } inline bool IsIdle() const { return idle; } - ResultVal Wait() override; + ResultVal ShouldWait() override; ResultVal Acquire() override; s32 GetPriority() const { return current_priority; } diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 62bdf07c7..1729cca0f 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -29,7 +29,7 @@ public: u64 initial_delay; ///< The delay until the timer fires for the first time u64 interval_delay; ///< The delay until the timer fires after the first time - ResultVal Wait() override { + ResultVal ShouldWait() override { return MakeResult(!signaled); } -- cgit v1.2.3 From 15b6a4d9add6b260a2a1a84ab6228addced4f851 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 18:16:45 -0500 Subject: Kernel: Changed "ShouldWait" to return bool and "Acquire" to return void. --- src/core/hle/kernel/event.cpp | 10 +++++----- src/core/hle/kernel/kernel.h | 9 +++------ src/core/hle/kernel/mutex.cpp | 24 +++++++++--------------- src/core/hle/kernel/semaphore.cpp | 28 +++++++--------------------- src/core/hle/kernel/session.h | 8 ++++---- src/core/hle/kernel/thread.cpp | 12 +++++------- src/core/hle/kernel/thread.h | 4 ++-- src/core/hle/kernel/timer.cpp | 8 ++++---- 8 files changed, 39 insertions(+), 64 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index bed856020..cdacba1d9 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -28,16 +28,16 @@ public: bool signaled; ///< Whether the event has already been signaled std::string name; ///< Name of event (optional) - ResultVal ShouldWait() override { - return MakeResult(!signaled); + bool ShouldWait() override { + return !signaled; } - ResultVal Acquire() override { + void Acquire() override { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); + // Release the event if it's not sticky... if (reset_type != RESETTYPE_STICKY) signaled = false; - - return MakeResult(true); } }; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 1bb0b55bd..c26726223 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -120,13 +120,10 @@ public: * Check if the current thread should wait until the object is available * @return True if the current thread should wait due to this object being unavailable */ - virtual ResultVal ShouldWait() = 0; + virtual bool ShouldWait() = 0; - /** - * Acquire/lock the object if it is available - * @return True if we were able to acquire this object, otherwise false - */ - virtual ResultVal Acquire() = 0; + /// Acquire/lock the object if it is available + virtual void Acquire() = 0; /** * Add a thread to wait on this object diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 01d2263ff..355824e60 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -27,8 +27,8 @@ public: std::string name; ///< Name of mutex (optional) SharedPtr current_thread; ///< Thread that has acquired the mutex - ResultVal ShouldWait() override; - ResultVal Acquire() override; + bool ShouldWait() override; + void Acquire() override; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -159,20 +159,14 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { return handle; } -ResultVal Mutex::ShouldWait() { - return MakeResult(locked && (current_thread != GetCurrentThread())); +bool Mutex::ShouldWait() { + return locked && current_thread != GetCurrentThread(); } -ResultVal Mutex::Acquire() { - bool res = false; - - if (!locked) { - // Lock the mutex when the first thread accesses it - locked = true; - res = true; - MutexAcquireLock(this); - } - - return MakeResult(res); +void Mutex::Acquire() { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); + locked = true; + MutexAcquireLock(this); } + } // namespace diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 24d41c0b3..274680568 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -24,27 +24,13 @@ public: s32 available_count; ///< Number of free slots left in the semaphore std::string name; ///< Name of semaphore (optional) - /** - * Tests whether a semaphore still has free slots - * @return Whether the semaphore is available - */ - bool IsAvailable() const { - return available_count > 0; + bool ShouldWait() override { + return available_count <= 0; } - ResultVal ShouldWait() override { - return MakeResult(!IsAvailable()); - } - - ResultVal Acquire() override { - bool res = false; - - if (IsAvailable()) { - --available_count; - res = true; - } - - return MakeResult(res); + void Acquire() override { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); + --available_count; } }; @@ -84,8 +70,8 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { // Notify some of the threads that the semaphore has been released // stop once the semaphore is full again or there are no more waiting threads - while (semaphore->IsAvailable() && semaphore->ReleaseNextThread() != nullptr) { - --semaphore->available_count; + while (!semaphore->ShouldWait() && semaphore->ReleaseNextThread() != nullptr) { + semaphore->Acquire(); } return RESULT_SUCCESS; diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index f0343d9b2..1788e4375 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -57,12 +57,12 @@ public: // TODO(bunnei): These functions exist to satisfy a hardware test with a Session object // passed into WaitSynchronization. Figure out the meaning of them. - ResultVal ShouldWait() override { - return MakeResult(true); + bool ShouldWait() override { + return true; } - ResultVal Acquire() override { - return MakeResult(false); + void Acquire() override { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); } }; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 8a2cf8bf4..7a7f430cf 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,12 +22,12 @@ namespace Kernel { -ResultVal Thread::ShouldWait() { - return MakeResult(status != THREADSTATUS_DORMANT); +bool Thread::ShouldWait() { + return status != THREADSTATUS_DORMANT; } -ResultVal Thread::Acquire() { - return MakeResult(true); +void Thread::Acquire() { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); } // Lists all thread ids that aren't deleted/etc. @@ -269,9 +269,7 @@ void Thread::ReleaseWaitObject(WaitObject* wait_object) { // Iterate through all waiting objects to check availability... for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { - auto res = (*itr)->ShouldWait(); - - if (*res && res.Succeeded()) + if ((*itr)->ShouldWait()) wait_all_failed = true; // The output should be the last index of wait_object diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index b23638bd1..bed9f714a 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -58,8 +58,8 @@ public: inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } inline bool IsIdle() const { return idle; } - ResultVal ShouldWait() override; - ResultVal Acquire() override; + bool ShouldWait() override; + void Acquire() override; s32 GetPriority() const { return current_priority; } void SetPriority(s32 priority); diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 1729cca0f..8d9db92a4 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -29,12 +29,12 @@ public: u64 initial_delay; ///< The delay until the timer fires for the first time u64 interval_delay; ///< The delay until the timer fires after the first time - ResultVal ShouldWait() override { - return MakeResult(!signaled); + bool ShouldWait() override { + return !signaled; } - ResultVal Acquire() override { - return MakeResult(true); + void Acquire() override { + _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); } }; -- cgit v1.2.3 From f09806aed24b2f7de7d969cbfdb3b9d18ab90c61 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 18:20:47 -0500 Subject: Kernel: Renamed some functions for clarity. - ReleaseNextThread->WakeupNextThread - ReleaseAllWaitingThreads->WakeupAllWaitingThreads. --- src/core/hle/kernel/event.cpp | 2 +- src/core/hle/kernel/kernel.cpp | 2 +- src/core/hle/kernel/kernel.h | 8 ++++---- src/core/hle/kernel/mutex.cpp | 2 +- src/core/hle/kernel/semaphore.cpp | 2 +- src/core/hle/kernel/thread.cpp | 2 +- src/core/hle/kernel/timer.cpp | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index cdacba1d9..a48125965 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -47,7 +47,7 @@ ResultCode SignalEvent(const Handle handle) { return InvalidHandle(ErrorModule::Kernel); evt->signaled = true; - evt->ReleaseAllWaitingThreads(); + evt->WakeupAllWaitingThreads(); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 692349857..d7fa4dcea 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -30,7 +30,7 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { waiting_threads.erase(itr); } -Thread* WaitObject::ReleaseNextThread() { +Thread* WaitObject::WakeupNextThread() { if (waiting_threads.empty()) return nullptr; diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index c26726223..3828efbea 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -138,13 +138,13 @@ public: void RemoveWaitingThread(Thread* thead); /** - * Releases (and removes) the next thread waiting on this object + * Wake up the next thread waiting on this object * @return Pointer to the thread that was resumed, nullptr if no threads are waiting */ - Thread* ReleaseNextThread(); + Thread* WakeupNextThread(); - /// Releases all threads waiting on this object - void ReleaseAllWaitingThreads(); + /// Wake up all threads waiting on this object + void WakeupAllWaitingThreads(); private: std::vector waiting_threads; ///< Threads waiting for this object to become available diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 355824e60..c170e55ff 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -53,7 +53,7 @@ void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandl */ void ResumeWaitingThread(Mutex* mutex) { // Find the next waiting thread for the mutex... - auto next_thread = mutex->ReleaseNextThread(); + auto next_thread = mutex->WakeupNextThread(); if (next_thread != nullptr) { MutexAcquireLock(mutex, next_thread->GetHandle()); } else { diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 274680568..135d8fb2a 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -70,7 +70,7 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { // Notify some of the threads that the semaphore has been released // stop once the semaphore is full again or there are no more waiting threads - while (!semaphore->ShouldWait() && semaphore->ReleaseNextThread() != nullptr) { + while (!semaphore->ShouldWait() && semaphore->WakeupNextThread() != nullptr) { semaphore->Acquire(); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 7a7f430cf..ab1126a36 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -104,7 +104,7 @@ void Thread::Stop(const char* reason) { ChangeReadyState(this, false); status = THREADSTATUS_DORMANT; - ReleaseAllWaitingThreads(); + WakeupAllWaitingThreads(); // Stopped threads are never waiting. wait_objects.clear(); diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 8d9db92a4..ec0b2c323 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -90,7 +90,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { timer->signaled = true; // Resume all waiting threads - timer->ReleaseAllWaitingThreads(); + timer->WakeupAllWaitingThreads(); if (timer->reset_type == RESETTYPE_ONESHOT) timer->signaled = false; -- cgit v1.2.3 From 2f3020a10247a0cb47848a6f8c19fbde50a7e0a6 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 18:33:23 -0500 Subject: Mutex: Cleanup and remove redundant code. --- src/core/hle/kernel/mutex.cpp | 72 ++++++++++++++++-------------------------- src/core/hle/kernel/mutex.h | 2 +- src/core/hle/kernel/thread.cpp | 2 +- 3 files changed, 29 insertions(+), 47 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index c170e55ff..cd05a1397 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -23,9 +23,8 @@ public: bool initial_locked; ///< Initial lock state when mutex was created bool locked; ///< Current locked state - Handle lock_thread; ///< Handle to thread that currently has mutex std::string name; ///< Name of mutex (optional) - SharedPtr current_thread; ///< Thread that has acquired the mutex + SharedPtr holding_thread; ///< Thread that has acquired the mutex bool ShouldWait() override; void Acquire() override; @@ -33,18 +32,17 @@ public: //////////////////////////////////////////////////////////////////////////////////////////////////// -typedef std::multimap MutexMap; +typedef std::multimap, SharedPtr> MutexMap; static MutexMap g_mutex_held_locks; /** * Acquires the specified mutex for the specified thread * @param mutex Mutex that is to be acquired - * @param thread Thread that will acquired + * @param thread Thread that will acquire the mutex */ -void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandle()) { - g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); - mutex->lock_thread = thread; - mutex->current_thread = Kernel::g_handle_table.Get(thread); +void MutexAcquireLock(Mutex* mutex, Thread* thread) { + g_mutex_held_locks.insert(std::make_pair(thread, mutex)); + mutex->holding_thread = thread; } /** @@ -55,51 +53,39 @@ void ResumeWaitingThread(Mutex* mutex) { // Find the next waiting thread for the mutex... auto next_thread = mutex->WakeupNextThread(); if (next_thread != nullptr) { - MutexAcquireLock(mutex, next_thread->GetHandle()); + MutexAcquireLock(mutex, next_thread); } else { // Reset mutex lock thread handle, nothing is waiting mutex->locked = false; - mutex->lock_thread = -1; + mutex->holding_thread = nullptr; } } -void MutexEraseLock(Mutex* mutex) { - Handle handle = mutex->GetHandle(); - auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread); - for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { - if (iter->second == handle) { - g_mutex_held_locks.erase(iter); - break; - } - } - mutex->lock_thread = -1; -} - -void ReleaseThreadMutexes(Handle thread) { +void ReleaseThreadMutexes(Thread* thread) { auto locked = g_mutex_held_locks.equal_range(thread); // Release every mutex that the thread holds, and resume execution on the waiting threads - for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { - Mutex* mutex = g_handle_table.Get(iter->second).get(); - ResumeWaitingThread(mutex); + for (auto iter = locked.first; iter != locked.second; ++iter) { + ResumeWaitingThread(iter->second.get()); } // Erase all the locks that this thread holds g_mutex_held_locks.erase(thread); } -bool LockMutex(Mutex* mutex) { - // Mutex alread locked? +bool ReleaseMutex(Mutex* mutex) { if (mutex->locked) { - return false; - } - MutexAcquireLock(mutex); - return true; -} + auto locked = g_mutex_held_locks.equal_range(mutex->holding_thread); -bool ReleaseMutex(Mutex* mutex) { - MutexEraseLock(mutex); - ResumeWaitingThread(mutex); + for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { + if (iter->second == mutex) { + g_mutex_held_locks.erase(iter); + break; + } + } + + ResumeWaitingThread(mutex); + } return true; } @@ -134,16 +120,12 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) mutex->locked = mutex->initial_locked = initial_locked; mutex->name = name; - mutex->current_thread = nullptr; + mutex->holding_thread = nullptr; // Acquire mutex with current thread if initialized as locked... - if (mutex->locked) { - MutexAcquireLock(mutex); + if (mutex->locked) + MutexAcquireLock(mutex, GetCurrentThread()); - // Otherwise, reset lock thread handle - } else { - mutex->lock_thread = -1; - } return mutex; } @@ -160,13 +142,13 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { } bool Mutex::ShouldWait() { - return locked && current_thread != GetCurrentThread(); + return locked && holding_thread != GetCurrentThread(); } void Mutex::Acquire() { _assert_msg_(Kernel, !ShouldWait(), "object unavailable!"); locked = true; - MutexAcquireLock(this); + MutexAcquireLock(this, GetCurrentThread()); } } // namespace diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index a8ca97014..bb8778c98 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -28,6 +28,6 @@ Handle CreateMutex(bool initial_locked, const std::string& name="Unknown"); * Releases all the mutexes held by the specified thread * @param thread Thread that is holding the mutexes */ -void ReleaseThreadMutexes(Handle thread); +void ReleaseThreadMutexes(Thread* thread); } // namespace diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ab1126a36..3ca9603c2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -100,7 +100,7 @@ static bool CheckWait_AddressArbiter(const Thread* thread, VAddr wait_address) { /// Stops the current thread void Thread::Stop(const char* reason) { // Release all the mutexes that this thread holds - ReleaseThreadMutexes(GetHandle()); + ReleaseThreadMutexes(this); ChangeReadyState(this, false); status = THREADSTATUS_DORMANT; -- cgit v1.2.3 From 4255f25647dee3ae6098d14adbb3db0749935120 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 18:40:01 -0500 Subject: Thread: Use std::find in CheckWait_WaitObject. --- src/core/hle/kernel/thread.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 3ca9603c2..58523e145 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -85,10 +85,11 @@ static void ChangeReadyState(Thread* t, bool ready) { /// Check if a thread is waiting on a the specified wait object static bool CheckWait_WaitObject(const Thread* thread, WaitObject* wait_object) { - for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { - if (*itr == wait_object) - return (thread->IsWaiting()); - } + auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); + + if (itr != thread->wait_objects.end()) + return thread->IsWaiting(); + return false; } -- cgit v1.2.3 From 68ddaaa2f5726e3619accee77b488ec285f3a2d7 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jan 2015 20:53:52 -0500 Subject: Thread: Fix WaitSynchronization1 to not set register 1 on thread wakeup. --- src/core/hle/kernel/thread.cpp | 43 +++++++++++++++++++++++++++--------------- src/core/hle/kernel/thread.h | 21 ++++++++++++++------- 2 files changed, 42 insertions(+), 22 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 58523e145..03b492c75 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -205,25 +205,24 @@ static Thread* NextThread() { void WaitCurrentThread_Sleep() { Thread* thread = GetCurrentThread(); - thread->wait_all = false; - thread->wait_address = 0; - thread->wait_objects.clear(); ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } -void WaitCurrentThread_WaitSynchronization(SharedPtr wait_object, bool wait_all) { +void WaitCurrentThread_WaitSynchronization(SharedPtr wait_object, bool wait_set_output, bool wait_all) { Thread* thread = GetCurrentThread(); + thread->wait_set_output = wait_set_output; thread->wait_all = wait_all; - thread->wait_address = 0; - thread->wait_objects.push_back(wait_object); + + // It's possible to call WaitSynchronizationN without any objects passed in... + if (wait_object != nullptr) + thread->wait_objects.push_back(wait_object); + ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { Thread* thread = GetCurrentThread(); - thread->wait_all = false; thread->wait_address = wait_address; - thread->wait_objects.clear(); ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } @@ -239,8 +238,11 @@ static void ThreadWakeupCallback(u64 parameter, int cycles_late) { return; } - thread->SetReturnValue(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, - ErrorSummary::StatusChanged, ErrorLevel::Info), -1); + thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, + ErrorSummary::StatusChanged, ErrorLevel::Info)); + + if (thread->wait_set_output) + thread->SetWaitSynchronizationOutput(-1); thread->ResumeFromWait(); } @@ -282,12 +284,18 @@ void Thread::ReleaseWaitObject(WaitObject* wait_object) { if (wait_all) { // Resume the thread only if all are available... if (!wait_all_failed) { - SetReturnValue(RESULT_SUCCESS, -1); + SetWaitSynchronizationResult(RESULT_SUCCESS); + SetWaitSynchronizationOutput(-1); + ResumeFromWait(); } } else { // Otherwise, resume - SetReturnValue(RESULT_SUCCESS, index); + SetWaitSynchronizationResult(RESULT_SUCCESS); + + if (wait_set_output) + SetWaitSynchronizationOutput(index); + ResumeFromWait(); } } @@ -303,6 +311,7 @@ void Thread::ResumeFromWait() { wait_object->RemoveWaitingThread(this); wait_objects.clear(); + wait_set_output = false; wait_all = false; wait_address = 0; @@ -371,6 +380,7 @@ ResultVal> Thread::Create(std::string name, VAddr entry_point, thread->stack_size = stack_size; thread->initial_priority = thread->current_priority = priority; thread->processor_id = processor_id; + thread->wait_set_output = false; thread->wait_all = false; thread->wait_objects.clear(); thread->wait_address = 0; @@ -462,9 +472,12 @@ void Reschedule() { } } -void Thread::SetReturnValue(ResultCode return_val, s32 out_val) { - context.cpu_registers[0] = return_val.raw; - context.cpu_registers[1] = out_val; +void Thread::SetWaitSynchronizationResult(ResultCode result) { + context.cpu_registers[0] = result.raw; +} + +void Thread::SetWaitSynchronizationOutput(s32 output) { + context.cpu_registers[1] = output; } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index bed9f714a..5fab1ab58 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -78,11 +78,16 @@ public: void ResumeFromWait(); /** - * Sets the output values after the thread awakens from WaitSynchronization - * @param return_val Value returned - * @param out_val Value to set to the output parameter + * Sets the result after the thread awakens (from either WaitSynchronization SVC) + * @param result Value to set to the returned result */ - void SetReturnValue(ResultCode return_val, s32 out_val); + void SetWaitSynchronizationResult(ResultCode result); + + /** + * Sets the output parameter value after the thread awakens (from WaitSynchronizationN SVC only) + * @param output Value to set to the output parameter + */ + void SetWaitSynchronizationOutput(s32 output); Core::ThreadContext context; @@ -100,8 +105,9 @@ public: std::vector> wait_objects; ///< Objects that the thread is waiting on - VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address - bool wait_all; ///< True if the thread is waiting on all objects before resuming + VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address + bool wait_all; ///< True if the thread is waiting on all objects before resuming + bool wait_set_output; ///< True if the output parameter should be set on thread wakeup std::string name; @@ -134,9 +140,10 @@ void WaitCurrentThread_Sleep(); /** * Waits the current thread from a WaitSynchronization call * @param wait_object Kernel object that we are waiting on + * @param wait_set_output If true, set the output parameter on thread wakeup (for WaitSynchronizationN only) * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only) */ -void WaitCurrentThread_WaitSynchronization(SharedPtr wait_object, bool wait_all = false); +void WaitCurrentThread_WaitSynchronization(SharedPtr wait_object, bool wait_set_output, bool wait_all); /** * Waits the current thread from an ArbitrateAddress call -- cgit v1.2.3