diff options
| author | 2021-11-09 19:02:11 -0800 | |
|---|---|---|
| committer | 2021-12-06 16:39:17 -0800 | |
| commit | bc1399204b914608715306a8a8dbe2f201dd4365 (patch) | |
| tree | 7799195284bb20b15cd6be6addea57f45364136f /src/core/hle/kernel | |
| parent | core: hle: kernel: Disable dispatch count tracking on single core. (diff) | |
| download | yuzu-bc1399204b914608715306a8a8dbe2f201dd4365.tar.gz yuzu-bc1399204b914608715306a8a8dbe2f201dd4365.tar.xz yuzu-bc1399204b914608715306a8a8dbe2f201dd4365.zip | |
hle: kernel: Update KThreadQueue and migrate KSynchronizationObject.
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_synchronization_object.cpp | 155 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_synchronization_object.h | 32 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.cpp | 42 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.h | 27 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread_queue.cpp | 51 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread_queue.h | 17 |
7 files changed, 250 insertions, 75 deletions
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index 61dc2858f..2995c492d 100644 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #pragma once | 8 | #pragma once |
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/kernel/global_scheduler_context.h" | ||
| 11 | #include "core/hle/kernel/k_thread.h" | 12 | #include "core/hle/kernel/k_thread.h" |
| 12 | #include "core/hle/kernel/kernel.h" | 13 | #include "core/hle/kernel/kernel.h" |
| 13 | #include "core/hle/kernel/time_manager.h" | 14 | #include "core/hle/kernel/time_manager.h" |
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index f168b4f21..ba8fc4010 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp | |||
| @@ -8,11 +8,70 @@ | |||
| 8 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 8 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 9 | #include "core/hle/kernel/k_synchronization_object.h" | 9 | #include "core/hle/kernel/k_synchronization_object.h" |
| 10 | #include "core/hle/kernel/k_thread.h" | 10 | #include "core/hle/kernel/k_thread.h" |
| 11 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/svc_results.h" | 13 | #include "core/hle/kernel/svc_results.h" |
| 13 | 14 | ||
| 14 | namespace Kernel { | 15 | namespace Kernel { |
| 15 | 16 | ||
| 17 | namespace { | ||
| 18 | |||
| 19 | class ThreadQueueImplForKSynchronizationObjectWait final : public KThreadQueueWithoutEndWait { | ||
| 20 | private: | ||
| 21 | using ThreadListNode = KSynchronizationObject::ThreadListNode; | ||
| 22 | |||
| 23 | private: | ||
| 24 | KSynchronizationObject** m_objects; | ||
| 25 | ThreadListNode* m_nodes; | ||
| 26 | s32 m_count; | ||
| 27 | |||
| 28 | public: | ||
| 29 | ThreadQueueImplForKSynchronizationObjectWait(KernelCore& kernel_, KSynchronizationObject** o, | ||
| 30 | ThreadListNode* n, s32 c) | ||
| 31 | : KThreadQueueWithoutEndWait(kernel_), m_objects(o), m_nodes(n), m_count(c) { // ... | ||
| 32 | } | ||
| 33 | |||
| 34 | virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object, | ||
| 35 | ResultCode wait_result) override { | ||
| 36 | // Determine the sync index, and unlink all nodes. | ||
| 37 | s32 sync_index = -1; | ||
| 38 | for (auto i = 0; i < m_count; ++i) { | ||
| 39 | // Check if this is the signaled object. | ||
| 40 | if (m_objects[i] == signaled_object && sync_index == -1) { | ||
| 41 | sync_index = i; | ||
| 42 | } | ||
| 43 | |||
| 44 | // Unlink the current node from the current object. | ||
| 45 | m_objects[i]->UnlinkNode(std::addressof(m_nodes[i])); | ||
| 46 | } | ||
| 47 | |||
| 48 | // Set the waiting thread's sync index. | ||
| 49 | waiting_thread->SetSyncedIndex(sync_index); | ||
| 50 | |||
| 51 | // Set the waiting thread as not cancellable. | ||
| 52 | waiting_thread->ClearCancellable(); | ||
| 53 | |||
| 54 | // Invoke the base end wait handler. | ||
| 55 | KThreadQueue::EndWait(waiting_thread, wait_result); | ||
| 56 | } | ||
| 57 | |||
| 58 | virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, | ||
| 59 | bool cancel_timer_task) override { | ||
| 60 | // Remove all nodes from our list. | ||
| 61 | for (auto i = 0; i < m_count; ++i) { | ||
| 62 | m_objects[i]->UnlinkNode(std::addressof(m_nodes[i])); | ||
| 63 | } | ||
| 64 | |||
| 65 | // Set the waiting thread as not cancellable. | ||
| 66 | waiting_thread->ClearCancellable(); | ||
| 67 | |||
| 68 | // Invoke the base cancel wait handler. | ||
| 69 | KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); | ||
| 70 | } | ||
| 71 | }; | ||
| 72 | |||
| 73 | } // namespace | ||
| 74 | |||
| 16 | void KSynchronizationObject::Finalize() { | 75 | void KSynchronizationObject::Finalize() { |
| 17 | this->OnFinalizeSynchronizationObject(); | 76 | this->OnFinalizeSynchronizationObject(); |
| 18 | KAutoObject::Finalize(); | 77 | KAutoObject::Finalize(); |
| @@ -25,11 +84,19 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index, | |||
| 25 | std::vector<ThreadListNode> thread_nodes(num_objects); | 84 | std::vector<ThreadListNode> thread_nodes(num_objects); |
| 26 | 85 | ||
| 27 | // Prepare for wait. | 86 | // Prepare for wait. |
| 28 | KThread* thread = kernel_ctx.CurrentScheduler()->GetCurrentThread(); | 87 | KThread* thread = GetCurrentThreadPointer(kernel_ctx); |
| 88 | ThreadQueueImplForKSynchronizationObjectWait wait_queue(kernel_ctx, objects, | ||
| 89 | thread_nodes.data(), num_objects); | ||
| 29 | 90 | ||
| 30 | { | 91 | { |
| 31 | // Setup the scheduling lock and sleep. | 92 | // Setup the scheduling lock and sleep. |
| 32 | KScopedSchedulerLockAndSleep slp{kernel_ctx, thread, timeout}; | 93 | KScopedSchedulerLockAndSleep slp(kernel_ctx, thread, timeout); |
| 94 | |||
| 95 | // Check if the thread should terminate. | ||
| 96 | if (thread->IsTerminationRequested()) { | ||
| 97 | slp.CancelSleep(); | ||
| 98 | return ResultTerminationRequested; | ||
| 99 | } | ||
| 33 | 100 | ||
| 34 | // Check if any of the objects are already signaled. | 101 | // Check if any of the objects are already signaled. |
| 35 | for (auto i = 0; i < num_objects; ++i) { | 102 | for (auto i = 0; i < num_objects; ++i) { |
| @@ -48,12 +115,6 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index, | |||
| 48 | return ResultTimedOut; | 115 | return ResultTimedOut; |
| 49 | } | 116 | } |
| 50 | 117 | ||
| 51 | // Check if the thread should terminate. | ||
| 52 | if (thread->IsTerminationRequested()) { | ||
| 53 | slp.CancelSleep(); | ||
| 54 | return ResultTerminationRequested; | ||
| 55 | } | ||
| 56 | |||
| 57 | // Check if waiting was canceled. | 118 | // Check if waiting was canceled. |
| 58 | if (thread->IsWaitCancelled()) { | 119 | if (thread->IsWaitCancelled()) { |
| 59 | slp.CancelSleep(); | 120 | slp.CancelSleep(); |
| @@ -66,73 +127,25 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index, | |||
| 66 | thread_nodes[i].thread = thread; | 127 | thread_nodes[i].thread = thread; |
| 67 | thread_nodes[i].next = nullptr; | 128 | thread_nodes[i].next = nullptr; |
| 68 | 129 | ||
| 69 | if (objects[i]->thread_list_tail == nullptr) { | 130 | objects[i]->LinkNode(std::addressof(thread_nodes[i])); |
| 70 | objects[i]->thread_list_head = std::addressof(thread_nodes[i]); | ||
| 71 | } else { | ||
| 72 | objects[i]->thread_list_tail->next = std::addressof(thread_nodes[i]); | ||
| 73 | } | ||
| 74 | |||
| 75 | objects[i]->thread_list_tail = std::addressof(thread_nodes[i]); | ||
| 76 | } | 131 | } |
| 77 | 132 | ||
| 78 | // For debugging only | 133 | // Mark the thread as cancellable. |
| 79 | thread->SetWaitObjectsForDebugging({objects, static_cast<std::size_t>(num_objects)}); | ||
| 80 | |||
| 81 | // Mark the thread as waiting. | ||
| 82 | thread->SetCancellable(); | 134 | thread->SetCancellable(); |
| 83 | thread->SetSyncedObject(nullptr, ResultTimedOut); | ||
| 84 | thread->SetState(ThreadState::Waiting); | ||
| 85 | thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization); | ||
| 86 | } | ||
| 87 | |||
| 88 | // The lock/sleep is done, so we should be able to get our result. | ||
| 89 | 135 | ||
| 90 | // Thread is no longer cancellable. | 136 | // Clear the thread's synced index. |
| 91 | thread->ClearCancellable(); | 137 | thread->SetSyncedIndex(-1); |
| 92 | 138 | ||
| 93 | // For debugging only | 139 | // Wait for an object to be signaled. |
| 94 | thread->SetWaitObjectsForDebugging({}); | 140 | thread->BeginWait(std::addressof(wait_queue)); |
| 141 | thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization); | ||
| 142 | } | ||
| 95 | 143 | ||
| 96 | // Cancel the timer as needed. | 144 | // Set the output index. |
| 97 | kernel_ctx.TimeManager().UnscheduleTimeEvent(thread); | 145 | *out_index = thread->GetSyncedIndex(); |
| 98 | 146 | ||
| 99 | // Get the wait result. | 147 | // Get the wait result. |
| 100 | ResultCode wait_result{ResultSuccess}; | 148 | return thread->GetWaitResult(); |
| 101 | s32 sync_index = -1; | ||
| 102 | { | ||
| 103 | KScopedSchedulerLock lock(kernel_ctx); | ||
| 104 | KSynchronizationObject* synced_obj; | ||
| 105 | wait_result = thread->GetWaitResult(std::addressof(synced_obj)); | ||
| 106 | |||
| 107 | for (auto i = 0; i < num_objects; ++i) { | ||
| 108 | // Unlink the object from the list. | ||
| 109 | ThreadListNode* prev_ptr = | ||
| 110 | reinterpret_cast<ThreadListNode*>(std::addressof(objects[i]->thread_list_head)); | ||
| 111 | ThreadListNode* prev_val = nullptr; | ||
| 112 | ThreadListNode *prev, *tail_prev; | ||
| 113 | |||
| 114 | do { | ||
| 115 | prev = prev_ptr; | ||
| 116 | prev_ptr = prev_ptr->next; | ||
| 117 | tail_prev = prev_val; | ||
| 118 | prev_val = prev_ptr; | ||
| 119 | } while (prev_ptr != std::addressof(thread_nodes[i])); | ||
| 120 | |||
| 121 | if (objects[i]->thread_list_tail == std::addressof(thread_nodes[i])) { | ||
| 122 | objects[i]->thread_list_tail = tail_prev; | ||
| 123 | } | ||
| 124 | |||
| 125 | prev->next = thread_nodes[i].next; | ||
| 126 | |||
| 127 | if (objects[i] == synced_obj) { | ||
| 128 | sync_index = i; | ||
| 129 | } | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | // Set output. | ||
| 134 | *out_index = sync_index; | ||
| 135 | return wait_result; | ||
| 136 | } | 149 | } |
| 137 | 150 | ||
| 138 | KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) | 151 | KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) |
| @@ -141,7 +154,7 @@ KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) | |||
| 141 | KSynchronizationObject::~KSynchronizationObject() = default; | 154 | KSynchronizationObject::~KSynchronizationObject() = default; |
| 142 | 155 | ||
| 143 | void KSynchronizationObject::NotifyAvailable(ResultCode result) { | 156 | void KSynchronizationObject::NotifyAvailable(ResultCode result) { |
| 144 | KScopedSchedulerLock lock(kernel); | 157 | KScopedSchedulerLock sl(kernel); |
| 145 | 158 | ||
| 146 | // If we're not signaled, we've nothing to notify. | 159 | // If we're not signaled, we've nothing to notify. |
| 147 | if (!this->IsSignaled()) { | 160 | if (!this->IsSignaled()) { |
| @@ -150,11 +163,7 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) { | |||
| 150 | 163 | ||
| 151 | // Iterate over each thread. | 164 | // Iterate over each thread. |
| 152 | for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { | 165 | for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { |
| 153 | KThread* thread = cur_node->thread; | 166 | cur_node->thread->NotifyAvailable(this, result); |
| 154 | if (thread->GetState() == ThreadState::Waiting) { | ||
| 155 | thread->SetSyncedObject(this, result); | ||
| 156 | thread->SetState(ThreadState::Runnable); | ||
| 157 | } | ||
| 158 | } | 167 | } |
| 159 | } | 168 | } |
| 160 | 169 | ||
diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index 898e58e16..789ff4780 100644 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h | |||
| @@ -35,6 +35,38 @@ public: | |||
| 35 | 35 | ||
| 36 | [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const; | 36 | [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const; |
| 37 | 37 | ||
| 38 | void LinkNode(ThreadListNode* node) { | ||
| 39 | // Link the node to the list. | ||
| 40 | if (thread_list_tail == nullptr) { | ||
| 41 | thread_list_head = node; | ||
| 42 | } else { | ||
| 43 | thread_list_tail->next = node; | ||
| 44 | } | ||
| 45 | |||
| 46 | thread_list_tail = node; | ||
| 47 | } | ||
| 48 | |||
| 49 | void UnlinkNode(ThreadListNode* node) { | ||
| 50 | // Unlink the node from the list. | ||
| 51 | ThreadListNode* prev_ptr = | ||
| 52 | reinterpret_cast<ThreadListNode*>(std::addressof(thread_list_head)); | ||
| 53 | ThreadListNode* prev_val = nullptr; | ||
| 54 | ThreadListNode *prev, *tail_prev; | ||
| 55 | |||
| 56 | do { | ||
| 57 | prev = prev_ptr; | ||
| 58 | prev_ptr = prev_ptr->next; | ||
| 59 | tail_prev = prev_val; | ||
| 60 | prev_val = prev_ptr; | ||
| 61 | } while (prev_ptr != node); | ||
| 62 | |||
| 63 | if (thread_list_tail == node) { | ||
| 64 | thread_list_tail = tail_prev; | ||
| 65 | } | ||
| 66 | |||
| 67 | prev->next = node->next; | ||
| 68 | } | ||
| 69 | |||
| 38 | protected: | 70 | protected: |
| 39 | explicit KSynchronizationObject(KernelCore& kernel); | 71 | explicit KSynchronizationObject(KernelCore& kernel); |
| 40 | ~KSynchronizationObject() override; | 72 | ~KSynchronizationObject() override; |
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 41bf9a6bb..3331b4845 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -303,7 +303,7 @@ void KThread::Wakeup() { | |||
| 303 | 303 | ||
| 304 | if (GetState() == ThreadState::Waiting) { | 304 | if (GetState() == ThreadState::Waiting) { |
| 305 | if (sleeping_queue != nullptr) { | 305 | if (sleeping_queue != nullptr) { |
| 306 | sleeping_queue->WakeupThread(this); | 306 | sleeping_queue->EndWait(this, ResultSuccess); |
| 307 | } else { | 307 | } else { |
| 308 | SetState(ThreadState::Runnable); | 308 | SetState(ThreadState::Runnable); |
| 309 | } | 309 | } |
| @@ -331,7 +331,7 @@ void KThread::StartTermination() { | |||
| 331 | 331 | ||
| 332 | // Signal. | 332 | // Signal. |
| 333 | signaled = true; | 333 | signaled = true; |
| 334 | NotifyAvailable(); | 334 | KSynchronizationObject::NotifyAvailable(); |
| 335 | 335 | ||
| 336 | // Clear previous thread in KScheduler. | 336 | // Clear previous thread in KScheduler. |
| 337 | KScheduler::ClearPreviousThread(kernel, this); | 337 | KScheduler::ClearPreviousThread(kernel, this); |
| @@ -1026,6 +1026,44 @@ ResultCode KThread::Sleep(s64 timeout) { | |||
| 1026 | return ResultSuccess; | 1026 | return ResultSuccess; |
| 1027 | } | 1027 | } |
| 1028 | 1028 | ||
| 1029 | void KThread::BeginWait(KThreadQueue* queue) { | ||
| 1030 | // Set our state as waiting. | ||
| 1031 | SetState(ThreadState::Waiting); | ||
| 1032 | |||
| 1033 | // Set our wait queue. | ||
| 1034 | sleeping_queue = queue; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { | ||
| 1038 | // Lock the scheduler. | ||
| 1039 | KScopedSchedulerLock sl(kernel); | ||
| 1040 | |||
| 1041 | // If we're waiting, notify our queue that we're available. | ||
| 1042 | if (GetState() == ThreadState::Waiting) { | ||
| 1043 | sleeping_queue->NotifyAvailable(this, signaled_object, wait_result_); | ||
| 1044 | } | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | void KThread::EndWait(ResultCode wait_result_) { | ||
| 1048 | // Lock the scheduler. | ||
| 1049 | KScopedSchedulerLock sl(kernel); | ||
| 1050 | |||
| 1051 | // If we're waiting, notify our queue that we're available. | ||
| 1052 | if (GetState() == ThreadState::Waiting) { | ||
| 1053 | sleeping_queue->EndWait(this, wait_result_); | ||
| 1054 | } | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | void KThread::CancelWait(ResultCode wait_result_, bool cancel_timer_task) { | ||
| 1058 | // Lock the scheduler. | ||
| 1059 | KScopedSchedulerLock sl(kernel); | ||
| 1060 | |||
| 1061 | // If we're waiting, notify our queue that we're available. | ||
| 1062 | if (GetState() == ThreadState::Waiting) { | ||
| 1063 | sleeping_queue->CancelWait(this, wait_result_, cancel_timer_task); | ||
| 1064 | } | ||
| 1065 | } | ||
| 1066 | |||
| 1029 | void KThread::SetState(ThreadState state) { | 1067 | void KThread::SetState(ThreadState state) { |
| 1030 | KScopedSchedulerLock sl{kernel}; | 1068 | KScopedSchedulerLock sl{kernel}; |
| 1031 | 1069 | ||
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index e4c4c877d..bea5fd84d 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -202,6 +202,23 @@ public: | |||
| 202 | wait_result = wait_res; | 202 | wait_result = wait_res; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | constexpr void SetSyncedIndex(s32 index) { | ||
| 206 | synced_index = index; | ||
| 207 | } | ||
| 208 | |||
| 209 | constexpr s32 GetSyncedIndex() const { | ||
| 210 | return synced_index; | ||
| 211 | } | ||
| 212 | |||
| 213 | constexpr void SetWaitResult(ResultCode wait_res) { | ||
| 214 | wait_result = wait_res; | ||
| 215 | synced_object = nullptr; | ||
| 216 | } | ||
| 217 | |||
| 218 | constexpr ResultCode GetWaitResult() const { | ||
| 219 | return wait_result; | ||
| 220 | } | ||
| 221 | |||
| 205 | [[nodiscard]] ResultCode GetWaitResult(KSynchronizationObject** out) const { | 222 | [[nodiscard]] ResultCode GetWaitResult(KSynchronizationObject** out) const { |
| 206 | *out = synced_object; | 223 | *out = synced_object; |
| 207 | return wait_result; | 224 | return wait_result; |
| @@ -596,6 +613,15 @@ public: | |||
| 596 | address_key_value = val; | 613 | address_key_value = val; |
| 597 | } | 614 | } |
| 598 | 615 | ||
| 616 | void ClearWaitQueue() { | ||
| 617 | sleeping_queue = nullptr; | ||
| 618 | } | ||
| 619 | |||
| 620 | void BeginWait(KThreadQueue* queue); | ||
| 621 | void NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_); | ||
| 622 | void EndWait(ResultCode wait_result_); | ||
| 623 | void CancelWait(ResultCode wait_result_, bool cancel_timer_task); | ||
| 624 | |||
| 599 | [[nodiscard]] bool HasWaiters() const { | 625 | [[nodiscard]] bool HasWaiters() const { |
| 600 | return !waiter_list.empty(); | 626 | return !waiter_list.empty(); |
| 601 | } | 627 | } |
| @@ -707,6 +733,7 @@ private: | |||
| 707 | u32 address_key_value{}; | 733 | u32 address_key_value{}; |
| 708 | u32 suspend_request_flags{}; | 734 | u32 suspend_request_flags{}; |
| 709 | u32 suspend_allowed_flags{}; | 735 | u32 suspend_allowed_flags{}; |
| 736 | s32 synced_index{}; | ||
| 710 | ResultCode wait_result{ResultSuccess}; | 737 | ResultCode wait_result{ResultSuccess}; |
| 711 | s32 base_priority{}; | 738 | s32 base_priority{}; |
| 712 | s32 physical_ideal_core_id{}; | 739 | s32 physical_ideal_core_id{}; |
diff --git a/src/core/hle/kernel/k_thread_queue.cpp b/src/core/hle/kernel/k_thread_queue.cpp new file mode 100644 index 000000000..46f27172b --- /dev/null +++ b/src/core/hle/kernel/k_thread_queue.cpp | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 8 | #include "core/hle/kernel/kernel.h" | ||
| 9 | #include "core/hle/kernel/time_manager.h" | ||
| 10 | |||
| 11 | namespace Kernel { | ||
| 12 | |||
| 13 | void KThreadQueue::NotifyAvailable([[maybe_unused]] KThread* waiting_thread, | ||
| 14 | [[maybe_unused]] KSynchronizationObject* signaled_object, | ||
| 15 | [[maybe_unused]] ResultCode wait_result) {} | ||
| 16 | |||
| 17 | void KThreadQueue::EndWait(KThread* waiting_thread, ResultCode wait_result) { | ||
| 18 | // Set the thread's wait result. | ||
| 19 | waiting_thread->SetWaitResult(wait_result); | ||
| 20 | |||
| 21 | // Set the thread as runnable. | ||
| 22 | waiting_thread->SetState(ThreadState::Runnable); | ||
| 23 | |||
| 24 | // Clear the thread's wait queue. | ||
| 25 | waiting_thread->ClearWaitQueue(); | ||
| 26 | |||
| 27 | // Cancel the thread task. | ||
| 28 | kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); | ||
| 29 | } | ||
| 30 | |||
| 31 | void KThreadQueue::CancelWait(KThread* waiting_thread, ResultCode wait_result, | ||
| 32 | bool cancel_timer_task) { | ||
| 33 | // Set the thread's wait result. | ||
| 34 | waiting_thread->SetWaitResult(wait_result); | ||
| 35 | |||
| 36 | // Set the thread as runnable. | ||
| 37 | waiting_thread->SetState(ThreadState::Runnable); | ||
| 38 | |||
| 39 | // Clear the thread's wait queue. | ||
| 40 | waiting_thread->ClearWaitQueue(); | ||
| 41 | |||
| 42 | // Cancel the thread task. | ||
| 43 | if (cancel_timer_task) { | ||
| 44 | kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | void KThreadQueueWithoutEndWait::EndWait([[maybe_unused]] KThread* waiting_thread, | ||
| 49 | [[maybe_unused]] ResultCode wait_result) {} | ||
| 50 | |||
| 51 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h index 35d471dc5..74e76e7cb 100644 --- a/src/core/hle/kernel/k_thread_queue.h +++ b/src/core/hle/kernel/k_thread_queue.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/kernel/k_scheduler.h" | ||
| 7 | #include "core/hle/kernel/k_thread.h" | 8 | #include "core/hle/kernel/k_thread.h" |
| 8 | 9 | ||
| 9 | namespace Kernel { | 10 | namespace Kernel { |
| @@ -11,7 +12,16 @@ namespace Kernel { | |||
| 11 | class KThreadQueue { | 12 | class KThreadQueue { |
| 12 | public: | 13 | public: |
| 13 | explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {} | 14 | explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {} |
| 15 | virtual ~KThreadQueue(){}; | ||
| 14 | 16 | ||
| 17 | virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object, | ||
| 18 | ResultCode wait_result); | ||
| 19 | virtual void EndWait(KThread* waiting_thread, ResultCode wait_result); | ||
| 20 | virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, | ||
| 21 | bool cancel_timer_task); | ||
| 22 | |||
| 23 | // Deprecated, will be removed in subsequent commits. | ||
| 24 | public: | ||
| 15 | bool IsEmpty() const { | 25 | bool IsEmpty() const { |
| 16 | return wait_list.empty(); | 26 | return wait_list.empty(); |
| 17 | } | 27 | } |
| @@ -78,4 +88,11 @@ private: | |||
| 78 | KThread::WaiterList wait_list{}; | 88 | KThread::WaiterList wait_list{}; |
| 79 | }; | 89 | }; |
| 80 | 90 | ||
| 91 | class KThreadQueueWithoutEndWait : public KThreadQueue { | ||
| 92 | public: | ||
| 93 | explicit KThreadQueueWithoutEndWait(KernelCore& kernel_) : KThreadQueue(kernel_) {} | ||
| 94 | |||
| 95 | virtual void EndWait(KThread* waiting_thread, ResultCode wait_result) override final; | ||
| 96 | }; | ||
| 97 | |||
| 81 | } // namespace Kernel | 98 | } // namespace Kernel |