diff options
| author | 2014-06-14 12:13:16 -0400 | |
|---|---|---|
| committer | 2014-06-14 12:13:16 -0400 | |
| commit | 004df767953a949817da89bddcd5d1379240f769 (patch) | |
| tree | b2d54928dcbf3cb4dde0cd5d3277afe7999b7bd9 /src/core/hle/kernel/event.cpp | |
| parent | GPU debugger: Const correctness and build fix. (diff) | |
| parent | Kernel: Removed unnecessary "#pragma once". (diff) | |
| download | yuzu-004df767953a949817da89bddcd5d1379240f769.tar.gz yuzu-004df767953a949817da89bddcd5d1379240f769.tar.xz yuzu-004df767953a949817da89bddcd5d1379240f769.zip | |
Merge branch 'threading' of https://github.com/bunnei/citra
Conflicts:
src/core/hle/function_wrappers.h
src/core/hle/service/gsp.cpp
Diffstat (limited to 'src/core/hle/kernel/event.cpp')
| -rw-r--r-- | src/core/hle/kernel/event.cpp | 159 |
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 | |||
| 15 | namespace Kernel { | ||
| 16 | |||
| 17 | class Event : public Object { | ||
| 18 | public: | ||
| 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 | */ | ||
| 60 | Result 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 | */ | ||
| 74 | Result 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 | */ | ||
| 89 | Result 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 | */ | ||
| 117 | Result 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 | */ | ||
| 134 | Event* 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 | */ | ||
| 153 | Handle 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 | ||