summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/event.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/event.cpp')
-rw-r--r--src/core/hle/kernel/event.cpp159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
new file mode 100644
index 000000000..127c0cfc6
--- /dev/null
+++ b/src/core/hle/kernel/event.cpp
@@ -0,0 +1,159 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <map>
6#include <algorithm>
7#include <vector>
8
9#include "common/common.h"
10
11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/thread.h"
14
15namespace Kernel {
16
17class Event : public Object {
18public:
19 const char* GetTypeName() const { return "Event"; }
20 const char* GetName() const { return name.c_str(); }
21
22 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; }
23 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; }
24
25 ResetType intitial_reset_type; ///< ResetType specified at Event initialization
26 ResetType reset_type; ///< Current ResetType
27
28 bool locked; ///< Event signal wait
29 bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough)
30 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event
31 std::string name; ///< Name of event (optional)
32
33 /**
34 * Wait for kernel object to synchronize
35 * @param wait Boolean wait set if current thread should wait as a result of sync operation
36 * @return Result of operation, 0 on success, otherwise error code
37 */
38 Result WaitSynchronization(bool* wait) {
39 *wait = locked;
40 if (locked) {
41 Handle thread = GetCurrentThreadHandle();
42 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
43 waiting_threads.push_back(thread);
44 }
45 Kernel::WaitCurrentThread(WAITTYPE_EVENT);
46 }
47 if (reset_type != RESETTYPE_STICKY && !permanent_locked) {
48 locked = true;
49 }
50 return 0;
51 }
52};
53
54/**
55 * Hackish function to set an events permanent lock state, used to pass through synch blocks
56 * @param handle Handle to event to change
57 * @param permanent_locked Boolean permanent locked value to set event
58 * @return Result of operation, 0 on success, otherwise error code
59 */
60Result SetPermanentLock(Handle handle, const bool permanent_locked) {
61 Event* evt = g_object_pool.GetFast<Event>(handle);
62 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
63
64 evt->permanent_locked = permanent_locked;
65 return 0;
66}
67
68/**
69 * Changes whether an event is locked or not
70 * @param handle Handle to event to change
71 * @param locked Boolean locked value to set event
72 * @return Result of operation, 0 on success, otherwise error code
73 */
74Result SetEventLocked(const Handle handle, const bool locked) {
75 Event* evt = g_object_pool.GetFast<Event>(handle);
76 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
77
78 if (!evt->permanent_locked) {
79 evt->locked = locked;
80 }
81 return 0;
82}
83
84/**
85 * Signals an event
86 * @param handle Handle to event to signal
87 * @return Result of operation, 0 on success, otherwise error code
88 */
89Result SignalEvent(const Handle handle) {
90 Event* evt = g_object_pool.GetFast<Event>(handle);
91 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
92
93 // Resume threads waiting for event to signal
94 bool event_caught = false;
95 for (size_t i = 0; i < evt->waiting_threads.size(); ++i) {
96 ResumeThreadFromWait( evt->waiting_threads[i]);
97
98 // If any thread is signalled awake by this event, assume the event was "caught" and reset
99 // the event. This will result in the next thread waiting on the event to block. Otherwise,
100 // the event will not be reset, and the next thread to call WaitSynchronization on it will
101 // not block. Not sure if this is correct behavior, but it seems to work.
102 event_caught = true;
103 }
104 evt->waiting_threads.clear();
105
106 if (!evt->permanent_locked) {
107 evt->locked = event_caught;
108 }
109 return 0;
110}
111
112/**
113 * Clears an event
114 * @param handle Handle to event to clear
115 * @return Result of operation, 0 on success, otherwise error code
116 */
117Result ClearEvent(Handle handle) {
118 Event* evt = g_object_pool.GetFast<Event>(handle);
119 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
120
121 if (!evt->permanent_locked) {
122 evt->locked = true;
123 }
124 return 0;
125}
126
127/**
128 * Creates an event
129 * @param handle Reference to handle for the newly created mutex
130 * @param reset_type ResetType describing how to create event
131 * @param name Optional name of event
132 * @return Newly created Event object
133 */
134Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) {
135 Event* evt = new Event;
136
137 handle = Kernel::g_object_pool.Create(evt);
138
139 evt->locked = true;
140 evt->permanent_locked = false;
141 evt->reset_type = evt->intitial_reset_type = reset_type;
142 evt->name = name;
143
144 return evt;
145}
146
147/**
148 * Creates an event
149 * @param reset_type ResetType describing how to create event
150 * @param name Optional name of event
151 * @return Handle to newly created Event object
152 */
153Handle CreateEvent(const ResetType reset_type, const std::string& name) {
154 Handle handle;
155 Event* evt = CreateEvent(handle, reset_type, name);
156 return handle;
157}
158
159} // namespace