diff options
author | bunnei <ericbunnie@gmail.com> | 2014-06-05 22:35:36 -0400 |
---|---|---|
committer | bunnei <ericbunnie@gmail.com> | 2014-06-13 09:51:02 -0400 |
commit | f5c7c1543434e25a215286e6db5e71c055ba48cf (patch) | |
tree | 488a3fd0c01051453c6f8ccc4867f6b6ea3f2843 /src/core/hle/kernel/event.cpp | |
parent | a002abf1711a53430d3002e81de8221ea24766ee (diff) |
Kernel: Added real support for thread and event blocking
- SVC: Added ExitThread support
- SVC: Added SignalEvent support
- Thread: Added WAITTYPE_EVENT for waiting threads for event signals
- Thread: Added support for blocking on other threads to finish (e.g. Thread::Join)
- Thread: Added debug function for printing current threads ready for execution
- Thread: Removed hack/broken thread ready state code from Kernel::Reschedule
- Mutex: Moved WaitCurrentThread from SVC to Mutex::WaitSynchronization
- Event: Added support for blocking threads on event signalling
Kernel: Added missing algorithm #include for use of std::find on non-Windows platforms.
Diffstat (limited to 'src/core/hle/kernel/event.cpp')
-rw-r--r-- | src/core/hle/kernel/event.cpp | 71 |
1 files changed, 59 insertions, 12 deletions
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 70e50115..787e9f5f 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -3,12 +3,14 @@ // Refer to the license.txt file included. #include <map> +#include <algorithm> #include <vector> #include "common/common.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/event.h" +#include "core/hle/kernel/thread.h" namespace Kernel { @@ -20,12 +22,13 @@ public: static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; } Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; } - ResetType intitial_reset_type; ///< ResetType specified at Event initialization - ResetType reset_type; ///< Current ResetType + ResetType intitial_reset_type; ///< ResetType specified at Event initialization + ResetType reset_type; ///< Current ResetType - bool locked; ///< Current locked state - bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough) - std::string name; ///< Name of event (optional) + bool locked; ///< Event signal wait + bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough) + std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event + std::string name; ///< Name of event (optional) /** * Synchronize kernel object @@ -44,8 +47,14 @@ public: * @return Result of operation, 0 on success, otherwise error code */ Result WaitSynchronization(bool* wait) { - // TODO(bunnei): ImplementMe *wait = locked; + if (locked) { + Handle thread = GetCurrentThreadHandle(); + if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { + waiting_threads.push_back(thread); + } + Kernel::WaitCurrentThread(WAITTYPE_EVENT); + } if (reset_type != RESETTYPE_STICKY && !permanent_locked) { locked = true; } @@ -54,6 +63,22 @@ public: }; /** + * 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 + */ +Result SetPermanentLock(Handle handle, const bool permanent_locked) { + Event* evt = g_object_pool.GetFast<Event>(handle); + if (!evt) { + ERROR_LOG(KERNEL, "called with unknown handle=0x%08X", handle); + return -1; + } + evt->permanent_locked = permanent_locked; + return 0; +} + +/** * Changes whether an event is locked or not * @param handle Handle to event to change * @param locked Boolean locked value to set event @@ -72,18 +97,32 @@ Result 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 + * Signals an event + * @param handle Handle to event to signal * @return Result of operation, 0 on success, otherwise error code */ -Result SetPermanentLock(Handle handle, const bool permanent_locked) { +Result SignalEvent(const Handle handle) { Event* evt = g_object_pool.GetFast<Event>(handle); if (!evt) { ERROR_LOG(KERNEL, "called with unknown handle=0x%08X", handle); return -1; } - evt->permanent_locked = permanent_locked; + // Resume threads waiting for event to signal + bool event_caught = false; + for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { + ResumeThreadFromWait( evt->waiting_threads[i]); + + // 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(); + + if (!evt->permanent_locked) { + evt->locked = event_caught; + } return 0; } @@ -93,7 +132,15 @@ Result SetPermanentLock(Handle handle, const bool permanent_locked) { * @return Result of operation, 0 on success, otherwise error code */ Result ClearEvent(Handle handle) { - return SetEventLocked(handle, true); + Event* evt = g_object_pool.GetFast<Event>(handle); + if (!evt) { + ERROR_LOG(KERNEL, "called with unknown handle=0x%08X", handle); + return -1; + } + if (!evt->permanent_locked) { + evt->locked = true; + } + return 0; } /** |