diff options
| author | 2015-01-14 19:22:50 -0500 | |
|---|---|---|
| committer | 2015-01-21 18:41:00 -0500 | |
| commit | c22bac6398ff1705992fc44b2c29775c84cff662 (patch) | |
| tree | e20da7e6e1824c19b7ced73f43815397749ffae7 /src | |
| parent | Merge pull request #491 from archshift/hidspvr (diff) | |
| download | yuzu-c22bac6398ff1705992fc44b2c29775c84cff662.tar.gz yuzu-c22bac6398ff1705992fc44b2c29775c84cff662.tar.xz yuzu-c22bac6398ff1705992fc44b2c29775c84cff662.zip | |
Kernel: Added WaitObject and changed "waitable" objects inherit from it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/event.cpp | 26 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 26 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 25 | ||||
| -rw-r--r-- | src/core/hle/kernel/mutex.cpp | 29 | ||||
| -rw-r--r-- | src/core/hle/kernel/semaphore.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/timer.cpp | 12 |
8 files changed, 73 insertions, 71 deletions
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 @@ | |||
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| 16 | 16 | ||
| 17 | class Event : public Object { | 17 | class Event : public WaitObject { |
| 18 | public: | 18 | public: |
| 19 | std::string GetTypeName() const override { return "Event"; } | 19 | std::string GetTypeName() const override { return "Event"; } |
| 20 | std::string GetName() const override { return name; } | 20 | std::string GetName() const override { return name; } |
| @@ -27,16 +27,12 @@ public: | |||
| 27 | 27 | ||
| 28 | bool locked; ///< Event signal wait | 28 | bool locked; ///< Event signal wait |
| 29 | bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough) | 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) | 30 | std::string name; ///< Name of event (optional) |
| 32 | 31 | ||
| 33 | ResultVal<bool> WaitSynchronization() override { | 32 | ResultVal<bool> WaitSynchronization() override { |
| 34 | bool wait = locked; | 33 | bool wait = locked; |
| 35 | if (locked) { | 34 | if (locked) { |
| 36 | Handle thread = GetCurrentThread()->GetHandle(); | 35 | AddWaitingThread(GetCurrentThread()); |
| 37 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | ||
| 38 | waiting_threads.push_back(thread); | ||
| 39 | } | ||
| 40 | Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); | 36 | Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); |
| 41 | } | 37 | } |
| 42 | if (reset_type != RESETTYPE_STICKY && !permanent_locked) { | 38 | if (reset_type != RESETTYPE_STICKY && !permanent_locked) { |
| @@ -86,20 +82,12 @@ ResultCode SignalEvent(const Handle handle) { | |||
| 86 | if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); | 82 | if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); |
| 87 | 83 | ||
| 88 | // Resume threads waiting for event to signal | 84 | // Resume threads waiting for event to signal |
| 89 | bool event_caught = false; | 85 | bool event_caught = evt->ResumeAllWaitingThreads(); |
| 90 | for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { | ||
| 91 | Thread* thread = Kernel::g_handle_table.Get<Thread>(evt->waiting_threads[i]).get(); | ||
| 92 | if (thread != nullptr) | ||
| 93 | thread->ResumeFromWait(); | ||
| 94 | |||
| 95 | // If any thread is signalled awake by this event, assume the event was "caught" and reset | ||
| 96 | // the event. This will result in the next thread waiting on the event to block. Otherwise, | ||
| 97 | // the event will not be reset, and the next thread to call WaitSynchronization on it will | ||
| 98 | // not block. Not sure if this is correct behavior, but it seems to work. | ||
| 99 | event_caught = true; | ||
| 100 | } | ||
| 101 | evt->waiting_threads.clear(); | ||
| 102 | 86 | ||
| 87 | // If any thread is signalled awake by this event, assume the event was "caught" and reset | ||
| 88 | // the event. This will result in the next thread waiting on the event to block. Otherwise, | ||
| 89 | // the event will not be reset, and the next thread to call WaitSynchronization on it will | ||
| 90 | // not block. Not sure if this is correct behavior, but it seems to work. | ||
| 103 | if (!evt->permanent_locked) { | 91 | if (!evt->permanent_locked) { |
| 104 | evt->locked = event_caught; | 92 | evt->locked = event_caught; |
| 105 | } | 93 | } |
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<Thread> g_main_thread = nullptr; | |||
| 18 | HandleTable g_handle_table; | 18 | HandleTable g_handle_table; |
| 19 | u64 g_program_id = 0; | 19 | u64 g_program_id = 0; |
| 20 | 20 | ||
| 21 | void WaitObject::AddWaitingThread(Thread* thread) { | ||
| 22 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | ||
| 23 | waiting_threads.push_back(thread); | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | Thread* WaitObject::ResumeNextThread() { | ||
| 28 | if (waiting_threads.empty()) return nullptr; | ||
| 29 | |||
| 30 | auto next_thread = waiting_threads.front(); | ||
| 31 | |||
| 32 | next_thread->ResumeFromWait(); | ||
| 33 | waiting_threads.erase(waiting_threads.begin()); | ||
| 34 | |||
| 35 | return next_thread.get(); | ||
| 36 | } | ||
| 37 | |||
| 38 | void WaitObject::ReleaseAllWaitingThreads() { | ||
| 39 | auto waiting_threads_copy = waiting_threads; | ||
| 40 | |||
| 41 | for (auto thread : waiting_threads_copy) | ||
| 42 | thread->ReleaseWaitObject(this); | ||
| 43 | |||
| 44 | waiting_threads.clear(); | ||
| 45 | } | ||
| 46 | |||
| 21 | HandleTable::HandleTable() { | 47 | HandleTable::HandleTable() { |
| 22 | next_generation = 1; | 48 | next_generation = 1; |
| 23 | Clear(); | 49 | 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 @@ | |||
| 8 | 8 | ||
| 9 | #include <array> | 9 | #include <array> |
| 10 | #include <string> | 10 | #include <string> |
| 11 | #include <vector> | ||
| 12 | |||
| 11 | #include "common/common.h" | 13 | #include "common/common.h" |
| 12 | #include "core/hle/result.h" | 14 | #include "core/hle/result.h" |
| 13 | 15 | ||
| @@ -92,6 +94,29 @@ inline void intrusive_ptr_release(Object* object) { | |||
| 92 | template <typename T> | 94 | template <typename T> |
| 93 | using SharedPtr = boost::intrusive_ptr<T>; | 95 | using SharedPtr = boost::intrusive_ptr<T>; |
| 94 | 96 | ||
| 97 | /// Class that represents a Kernel object that a thread can be waiting on | ||
| 98 | class WaitObject : public Object { | ||
| 99 | public: | ||
| 100 | |||
| 101 | /** | ||
| 102 | * Add a thread to wait on this object | ||
| 103 | * @param thread Pointer to thread to add | ||
| 104 | */ | ||
| 105 | void AddWaitingThread(Thread* thread); | ||
| 106 | |||
| 107 | /** | ||
| 108 | * Resumes the next thread waiting on this object | ||
| 109 | * @return Pointer to the thread that was resumed, nullptr if no threads are waiting | ||
| 110 | */ | ||
| 111 | Thread* ResumeNextThread(); | ||
| 112 | |||
| 113 | /// Releases all threads waiting on this object | ||
| 114 | void ReleaseAllWaitingThreads(); | ||
| 115 | |||
| 116 | private: | ||
| 117 | std::vector<Thread*> waiting_threads; ///< Threads waiting for this object to become available | ||
| 118 | }; | ||
| 119 | |||
| 95 | /** | 120 | /** |
| 96 | * This class allows the creation of Handles, which are references to objects that can be tested | 121 | * This class allows the creation of Handles, which are references to objects that can be tested |
| 97 | * for validity and looked up. Here they are used to pass references to kernel objects to/from the | 122 | * 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 @@ | |||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | class Mutex : public Object { | 16 | class Mutex : public WaitObject { |
| 17 | public: | 17 | public: |
| 18 | std::string GetTypeName() const override { return "Mutex"; } | 18 | std::string GetTypeName() const override { return "Mutex"; } |
| 19 | std::string GetName() const override { return name; } | 19 | std::string GetName() const override { return name; } |
| @@ -24,7 +24,6 @@ public: | |||
| 24 | bool initial_locked; ///< Initial lock state when mutex was created | 24 | bool initial_locked; ///< Initial lock state when mutex was created |
| 25 | bool locked; ///< Current locked state | 25 | bool locked; ///< Current locked state |
| 26 | Handle lock_thread; ///< Handle to thread that currently has mutex | 26 | Handle lock_thread; ///< Handle to thread that currently has mutex |
| 27 | std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex | ||
| 28 | std::string name; ///< Name of mutex (optional) | 27 | std::string name; ///< Name of mutex (optional) |
| 29 | 28 | ||
| 30 | ResultVal<bool> WaitSynchronization() override; | 29 | ResultVal<bool> WaitSynchronization() override; |
| @@ -45,36 +44,20 @@ void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandl | |||
| 45 | mutex->lock_thread = thread; | 44 | mutex->lock_thread = thread; |
| 46 | } | 45 | } |
| 47 | 46 | ||
| 48 | bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) { | ||
| 49 | MutexAcquireLock(mutex, thread_handle); | ||
| 50 | |||
| 51 | Thread* thread = Kernel::g_handle_table.Get<Thread>(thread_handle).get(); | ||
| 52 | if (thread == nullptr) { | ||
| 53 | LOG_ERROR(Kernel, "Called with invalid handle: %08X", thread_handle); | ||
| 54 | return false; | ||
| 55 | } | ||
| 56 | |||
| 57 | thread->ResumeFromWait(); | ||
| 58 | return true; | ||
| 59 | } | ||
| 60 | |||
| 61 | /** | 47 | /** |
| 62 | * Resumes a thread waiting for the specified mutex | 48 | * Resumes a thread waiting for the specified mutex |
| 63 | * @param mutex The mutex that some thread is waiting on | 49 | * @param mutex The mutex that some thread is waiting on |
| 64 | */ | 50 | */ |
| 65 | void ResumeWaitingThread(Mutex* mutex) { | 51 | void ResumeWaitingThread(Mutex* mutex) { |
| 66 | // Find the next waiting thread for the mutex... | 52 | // Find the next waiting thread for the mutex... |
| 67 | if (mutex->waiting_threads.empty()) { | 53 | auto next_thread = mutex->ResumeNextThread(); |
| 54 | if (next_thread != nullptr) { | ||
| 55 | MutexAcquireLock(mutex, next_thread->GetHandle()); | ||
| 56 | } else { | ||
| 68 | // Reset mutex lock thread handle, nothing is waiting | 57 | // Reset mutex lock thread handle, nothing is waiting |
| 69 | mutex->locked = false; | 58 | mutex->locked = false; |
| 70 | mutex->lock_thread = -1; | 59 | mutex->lock_thread = -1; |
| 71 | } | 60 | } |
| 72 | else { | ||
| 73 | // Resume the next waiting thread and re-lock the mutex | ||
| 74 | std::vector<Handle>::iterator iter = mutex->waiting_threads.begin(); | ||
| 75 | ReleaseMutexForThread(mutex, *iter); | ||
| 76 | mutex->waiting_threads.erase(iter); | ||
| 77 | } | ||
| 78 | } | 61 | } |
| 79 | 62 | ||
| 80 | void MutexEraseLock(Mutex* mutex) { | 63 | void MutexEraseLock(Mutex* mutex) { |
| @@ -175,7 +158,7 @@ Handle CreateMutex(bool initial_locked, const std::string& name) { | |||
| 175 | ResultVal<bool> Mutex::WaitSynchronization() { | 158 | ResultVal<bool> Mutex::WaitSynchronization() { |
| 176 | bool wait = locked; | 159 | bool wait = locked; |
| 177 | if (locked) { | 160 | if (locked) { |
| 178 | waiting_threads.push_back(GetCurrentThread()->GetHandle()); | 161 | AddWaitingThread(GetCurrentThread()); |
| 179 | Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); | 162 | Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); |
| 180 | } else { | 163 | } else { |
| 181 | // Lock the mutex when the first thread accesses it | 164 | // 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 @@ | |||
| 12 | 12 | ||
| 13 | namespace Kernel { | 13 | namespace Kernel { |
| 14 | 14 | ||
| 15 | class Semaphore : public Object { | 15 | class Semaphore : public WaitObject { |
| 16 | public: | 16 | public: |
| 17 | std::string GetTypeName() const override { return "Semaphore"; } | 17 | std::string GetTypeName() const override { return "Semaphore"; } |
| 18 | std::string GetName() const override { return name; } | 18 | std::string GetName() const override { return name; } |
| @@ -22,7 +22,6 @@ public: | |||
| 22 | 22 | ||
| 23 | s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have | 23 | s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have |
| 24 | s32 available_count; ///< Number of free slots left in the semaphore | 24 | s32 available_count; ///< Number of free slots left in the semaphore |
| 25 | std::queue<Handle> waiting_threads; ///< Threads that are waiting for the semaphore | ||
| 26 | std::string name; ///< Name of semaphore (optional) | 25 | std::string name; ///< Name of semaphore (optional) |
| 27 | 26 | ||
| 28 | /** | 27 | /** |
| @@ -38,7 +37,7 @@ public: | |||
| 38 | 37 | ||
| 39 | if (wait) { | 38 | if (wait) { |
| 40 | Kernel::WaitCurrentThread(WAITTYPE_SEMA, this); | 39 | Kernel::WaitCurrentThread(WAITTYPE_SEMA, this); |
| 41 | waiting_threads.push(GetCurrentThread()->GetHandle()); | 40 | AddWaitingThread(GetCurrentThread()); |
| 42 | } else { | 41 | } else { |
| 43 | --available_count; | 42 | --available_count; |
| 44 | } | 43 | } |
| @@ -83,11 +82,7 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { | |||
| 83 | 82 | ||
| 84 | // Notify some of the threads that the semaphore has been released | 83 | // Notify some of the threads that the semaphore has been released |
| 85 | // stop once the semaphore is full again or there are no more waiting threads | 84 | // stop once the semaphore is full again or there are no more waiting threads |
| 86 | while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) { | 85 | while (semaphore->IsAvailable() && semaphore->ResumeNextThread() != nullptr) { |
| 87 | Thread* thread = Kernel::g_handle_table.Get<Thread>(semaphore->waiting_threads.front()).get(); | ||
| 88 | if (thread != nullptr) | ||
| 89 | thread->ResumeFromWait(); | ||
| 90 | semaphore->waiting_threads.pop(); | ||
| 91 | --semaphore->available_count; | 86 | --semaphore->available_count; |
| 92 | } | 87 | } |
| 93 | 88 | ||
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 { | |||
| 25 | ResultVal<bool> Thread::WaitSynchronization() { | 25 | ResultVal<bool> Thread::WaitSynchronization() { |
| 26 | const bool wait = status != THREADSTATUS_DORMANT; | 26 | const bool wait = status != THREADSTATUS_DORMANT; |
| 27 | if (wait) { | 27 | if (wait) { |
| 28 | Thread* thread = GetCurrentThread(); | 28 | AddWaitingThread(GetCurrentThread()); |
| 29 | if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { | ||
| 30 | waiting_threads.push_back(thread); | ||
| 31 | } | ||
| 32 | WaitCurrentThread(WAITTYPE_THREADEND, this); | 29 | WaitCurrentThread(WAITTYPE_THREADEND, this); |
| 33 | } | 30 | } |
| 34 | 31 | ||
| @@ -110,11 +107,7 @@ void Thread::Stop(const char* reason) { | |||
| 110 | 107 | ||
| 111 | ChangeReadyState(this, false); | 108 | ChangeReadyState(this, false); |
| 112 | status = THREADSTATUS_DORMANT; | 109 | status = THREADSTATUS_DORMANT; |
| 113 | for (auto& waiting_thread : waiting_threads) { | 110 | ResumeAllWaitingThreads(); |
| 114 | if (CheckWaitType(waiting_thread.get(), WAITTYPE_THREADEND, this)) | ||
| 115 | waiting_thread->ResumeFromWait(); | ||
| 116 | } | ||
| 117 | waiting_threads.clear(); | ||
| 118 | 111 | ||
| 119 | // Stopped threads are never waiting. | 112 | // Stopped threads are never waiting. |
| 120 | wait_type = WAITTYPE_NONE; | 113 | 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 { | |||
| 52 | 52 | ||
| 53 | namespace Kernel { | 53 | namespace Kernel { |
| 54 | 54 | ||
| 55 | class Thread : public Kernel::Object { | 55 | class Thread : public WaitObject { |
| 56 | public: | 56 | public: |
| 57 | static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, | 57 | static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, |
| 58 | u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); | 58 | u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); |
| @@ -99,8 +99,6 @@ public: | |||
| 99 | Object* wait_object; | 99 | Object* wait_object; |
| 100 | VAddr wait_address; | 100 | VAddr wait_address; |
| 101 | 101 | ||
| 102 | std::vector<SharedPtr<Thread>> waiting_threads; | ||
| 103 | |||
| 104 | std::string name; | 102 | std::string name; |
| 105 | 103 | ||
| 106 | /// Whether this thread is intended to never actually be executed, i.e. always idle | 104 | /// 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 @@ | |||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | class Timer : public Object { | 16 | class Timer : public WaitObject { |
| 17 | public: | 17 | public: |
| 18 | std::string GetTypeName() const override { return "Timer"; } | 18 | std::string GetTypeName() const override { return "Timer"; } |
| 19 | std::string GetName() const override { return name; } | 19 | std::string GetName() const override { return name; } |
| @@ -24,7 +24,6 @@ public: | |||
| 24 | ResetType reset_type; ///< The ResetType of this timer | 24 | ResetType reset_type; ///< The ResetType of this timer |
| 25 | 25 | ||
| 26 | bool signaled; ///< Whether the timer has been signaled or not | 26 | bool signaled; ///< Whether the timer has been signaled or not |
| 27 | std::set<Handle> waiting_threads; ///< Threads that are waiting for the timer | ||
| 28 | std::string name; ///< Name of timer (optional) | 27 | std::string name; ///< Name of timer (optional) |
| 29 | 28 | ||
| 30 | u64 initial_delay; ///< The delay until the timer fires for the first time | 29 | u64 initial_delay; ///< The delay until the timer fires for the first time |
| @@ -33,7 +32,7 @@ public: | |||
| 33 | ResultVal<bool> WaitSynchronization() override { | 32 | ResultVal<bool> WaitSynchronization() override { |
| 34 | bool wait = !signaled; | 33 | bool wait = !signaled; |
| 35 | if (wait) { | 34 | if (wait) { |
| 36 | waiting_threads.insert(GetCurrentThread()->GetHandle()); | 35 | AddWaitingThread(GetCurrentThread()); |
| 37 | Kernel::WaitCurrentThread(WAITTYPE_TIMER, this); | 36 | Kernel::WaitCurrentThread(WAITTYPE_TIMER, this); |
| 38 | } | 37 | } |
| 39 | return MakeResult<bool>(wait); | 38 | return MakeResult<bool>(wait); |
| @@ -92,12 +91,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { | |||
| 92 | timer->signaled = true; | 91 | timer->signaled = true; |
| 93 | 92 | ||
| 94 | // Resume all waiting threads | 93 | // Resume all waiting threads |
| 95 | for (Handle thread_handle : timer->waiting_threads) { | 94 | timer->ResumeAllWaitingThreads(); |
| 96 | if (SharedPtr<Thread> thread = Kernel::g_handle_table.Get<Thread>(thread_handle)) | ||
| 97 | thread->ResumeFromWait(); | ||
| 98 | } | ||
| 99 | |||
| 100 | timer->waiting_threads.clear(); | ||
| 101 | 95 | ||
| 102 | if (timer->reset_type == RESETTYPE_ONESHOT) | 96 | if (timer->reset_type == RESETTYPE_ONESHOT) |
| 103 | timer->signaled = false; | 97 | timer->signaled = false; |