aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/hle/kernel/event.cpp
diff options
context:
space:
mode:
authorGravatar bunnei <ericbunnie@gmail.com>2014-06-05 22:35:36 -0400
committerGravatar bunnei <ericbunnie@gmail.com>2014-06-13 09:51:02 -0400
commitf5c7c1543434e25a215286e6db5e71c055ba48cf (patch)
tree488a3fd0c01051453c6f8ccc4867f6b6ea3f2843 /src/core/hle/kernel/event.cpp
parenta002abf1711a53430d3002e81de8221ea24766ee (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.cpp71
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;
}
/**