hle: kernel: Update KThreadQueue and migrate KSynchronizationObject.
This commit is contained in:
parent
3dc803a430
commit
bc1399204b
8 changed files with 251 additions and 75 deletions
|
@ -237,6 +237,7 @@ add_library(core STATIC
|
||||||
hle/kernel/k_system_control.h
|
hle/kernel/k_system_control.h
|
||||||
hle/kernel/k_thread.cpp
|
hle/kernel/k_thread.cpp
|
||||||
hle/kernel/k_thread.h
|
hle/kernel/k_thread.h
|
||||||
|
hle/kernel/k_thread_queue.cpp
|
||||||
hle/kernel/k_thread_queue.h
|
hle/kernel/k_thread_queue.h
|
||||||
hle/kernel/k_trace.h
|
hle/kernel/k_trace.h
|
||||||
hle/kernel/k_transfer_memory.cpp
|
hle/kernel/k_transfer_memory.cpp
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/kernel/global_scheduler_context.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/time_manager.h"
|
#include "core/hle/kernel/time_manager.h"
|
||||||
|
|
|
@ -8,11 +8,70 @@
|
||||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||||
#include "core/hle/kernel/k_synchronization_object.h"
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
|
#include "core/hle/kernel/k_thread_queue.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/svc_results.h"
|
#include "core/hle/kernel/svc_results.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class ThreadQueueImplForKSynchronizationObjectWait final : public KThreadQueueWithoutEndWait {
|
||||||
|
private:
|
||||||
|
using ThreadListNode = KSynchronizationObject::ThreadListNode;
|
||||||
|
|
||||||
|
private:
|
||||||
|
KSynchronizationObject** m_objects;
|
||||||
|
ThreadListNode* m_nodes;
|
||||||
|
s32 m_count;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ThreadQueueImplForKSynchronizationObjectWait(KernelCore& kernel_, KSynchronizationObject** o,
|
||||||
|
ThreadListNode* n, s32 c)
|
||||||
|
: KThreadQueueWithoutEndWait(kernel_), m_objects(o), m_nodes(n), m_count(c) { // ...
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object,
|
||||||
|
ResultCode wait_result) override {
|
||||||
|
// Determine the sync index, and unlink all nodes.
|
||||||
|
s32 sync_index = -1;
|
||||||
|
for (auto i = 0; i < m_count; ++i) {
|
||||||
|
// Check if this is the signaled object.
|
||||||
|
if (m_objects[i] == signaled_object && sync_index == -1) {
|
||||||
|
sync_index = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlink the current node from the current object.
|
||||||
|
m_objects[i]->UnlinkNode(std::addressof(m_nodes[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the waiting thread's sync index.
|
||||||
|
waiting_thread->SetSyncedIndex(sync_index);
|
||||||
|
|
||||||
|
// Set the waiting thread as not cancellable.
|
||||||
|
waiting_thread->ClearCancellable();
|
||||||
|
|
||||||
|
// Invoke the base end wait handler.
|
||||||
|
KThreadQueue::EndWait(waiting_thread, wait_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result,
|
||||||
|
bool cancel_timer_task) override {
|
||||||
|
// Remove all nodes from our list.
|
||||||
|
for (auto i = 0; i < m_count; ++i) {
|
||||||
|
m_objects[i]->UnlinkNode(std::addressof(m_nodes[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the waiting thread as not cancellable.
|
||||||
|
waiting_thread->ClearCancellable();
|
||||||
|
|
||||||
|
// Invoke the base cancel wait handler.
|
||||||
|
KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void KSynchronizationObject::Finalize() {
|
void KSynchronizationObject::Finalize() {
|
||||||
this->OnFinalizeSynchronizationObject();
|
this->OnFinalizeSynchronizationObject();
|
||||||
KAutoObject::Finalize();
|
KAutoObject::Finalize();
|
||||||
|
@ -25,11 +84,19 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,
|
||||||
std::vector<ThreadListNode> thread_nodes(num_objects);
|
std::vector<ThreadListNode> thread_nodes(num_objects);
|
||||||
|
|
||||||
// Prepare for wait.
|
// Prepare for wait.
|
||||||
KThread* thread = kernel_ctx.CurrentScheduler()->GetCurrentThread();
|
KThread* thread = GetCurrentThreadPointer(kernel_ctx);
|
||||||
|
ThreadQueueImplForKSynchronizationObjectWait wait_queue(kernel_ctx, objects,
|
||||||
|
thread_nodes.data(), num_objects);
|
||||||
|
|
||||||
{
|
{
|
||||||
// Setup the scheduling lock and sleep.
|
// Setup the scheduling lock and sleep.
|
||||||
KScopedSchedulerLockAndSleep slp{kernel_ctx, thread, timeout};
|
KScopedSchedulerLockAndSleep slp(kernel_ctx, thread, timeout);
|
||||||
|
|
||||||
|
// Check if the thread should terminate.
|
||||||
|
if (thread->IsTerminationRequested()) {
|
||||||
|
slp.CancelSleep();
|
||||||
|
return ResultTerminationRequested;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if any of the objects are already signaled.
|
// Check if any of the objects are already signaled.
|
||||||
for (auto i = 0; i < num_objects; ++i) {
|
for (auto i = 0; i < num_objects; ++i) {
|
||||||
|
@ -48,12 +115,6 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,
|
||||||
return ResultTimedOut;
|
return ResultTimedOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the thread should terminate.
|
|
||||||
if (thread->IsTerminationRequested()) {
|
|
||||||
slp.CancelSleep();
|
|
||||||
return ResultTerminationRequested;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if waiting was canceled.
|
// Check if waiting was canceled.
|
||||||
if (thread->IsWaitCancelled()) {
|
if (thread->IsWaitCancelled()) {
|
||||||
slp.CancelSleep();
|
slp.CancelSleep();
|
||||||
|
@ -66,73 +127,25 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,
|
||||||
thread_nodes[i].thread = thread;
|
thread_nodes[i].thread = thread;
|
||||||
thread_nodes[i].next = nullptr;
|
thread_nodes[i].next = nullptr;
|
||||||
|
|
||||||
if (objects[i]->thread_list_tail == nullptr) {
|
objects[i]->LinkNode(std::addressof(thread_nodes[i]));
|
||||||
objects[i]->thread_list_head = std::addressof(thread_nodes[i]);
|
|
||||||
} else {
|
|
||||||
objects[i]->thread_list_tail->next = std::addressof(thread_nodes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
objects[i]->thread_list_tail = std::addressof(thread_nodes[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For debugging only
|
// Mark the thread as cancellable.
|
||||||
thread->SetWaitObjectsForDebugging({objects, static_cast<std::size_t>(num_objects)});
|
|
||||||
|
|
||||||
// Mark the thread as waiting.
|
|
||||||
thread->SetCancellable();
|
thread->SetCancellable();
|
||||||
thread->SetSyncedObject(nullptr, ResultTimedOut);
|
|
||||||
thread->SetState(ThreadState::Waiting);
|
// Clear the thread's synced index.
|
||||||
|
thread->SetSyncedIndex(-1);
|
||||||
|
|
||||||
|
// Wait for an object to be signaled.
|
||||||
|
thread->BeginWait(std::addressof(wait_queue));
|
||||||
thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization);
|
thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The lock/sleep is done, so we should be able to get our result.
|
// Set the output index.
|
||||||
|
*out_index = thread->GetSyncedIndex();
|
||||||
// Thread is no longer cancellable.
|
|
||||||
thread->ClearCancellable();
|
|
||||||
|
|
||||||
// For debugging only
|
|
||||||
thread->SetWaitObjectsForDebugging({});
|
|
||||||
|
|
||||||
// Cancel the timer as needed.
|
|
||||||
kernel_ctx.TimeManager().UnscheduleTimeEvent(thread);
|
|
||||||
|
|
||||||
// Get the wait result.
|
// Get the wait result.
|
||||||
ResultCode wait_result{ResultSuccess};
|
return thread->GetWaitResult();
|
||||||
s32 sync_index = -1;
|
|
||||||
{
|
|
||||||
KScopedSchedulerLock lock(kernel_ctx);
|
|
||||||
KSynchronizationObject* synced_obj;
|
|
||||||
wait_result = thread->GetWaitResult(std::addressof(synced_obj));
|
|
||||||
|
|
||||||
for (auto i = 0; i < num_objects; ++i) {
|
|
||||||
// Unlink the object from the list.
|
|
||||||
ThreadListNode* prev_ptr =
|
|
||||||
reinterpret_cast<ThreadListNode*>(std::addressof(objects[i]->thread_list_head));
|
|
||||||
ThreadListNode* prev_val = nullptr;
|
|
||||||
ThreadListNode *prev, *tail_prev;
|
|
||||||
|
|
||||||
do {
|
|
||||||
prev = prev_ptr;
|
|
||||||
prev_ptr = prev_ptr->next;
|
|
||||||
tail_prev = prev_val;
|
|
||||||
prev_val = prev_ptr;
|
|
||||||
} while (prev_ptr != std::addressof(thread_nodes[i]));
|
|
||||||
|
|
||||||
if (objects[i]->thread_list_tail == std::addressof(thread_nodes[i])) {
|
|
||||||
objects[i]->thread_list_tail = tail_prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev->next = thread_nodes[i].next;
|
|
||||||
|
|
||||||
if (objects[i] == synced_obj) {
|
|
||||||
sync_index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set output.
|
|
||||||
*out_index = sync_index;
|
|
||||||
return wait_result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_)
|
KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_)
|
||||||
|
@ -141,7 +154,7 @@ KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_)
|
||||||
KSynchronizationObject::~KSynchronizationObject() = default;
|
KSynchronizationObject::~KSynchronizationObject() = default;
|
||||||
|
|
||||||
void KSynchronizationObject::NotifyAvailable(ResultCode result) {
|
void KSynchronizationObject::NotifyAvailable(ResultCode result) {
|
||||||
KScopedSchedulerLock lock(kernel);
|
KScopedSchedulerLock sl(kernel);
|
||||||
|
|
||||||
// If we're not signaled, we've nothing to notify.
|
// If we're not signaled, we've nothing to notify.
|
||||||
if (!this->IsSignaled()) {
|
if (!this->IsSignaled()) {
|
||||||
|
@ -150,11 +163,7 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) {
|
||||||
|
|
||||||
// Iterate over each thread.
|
// Iterate over each thread.
|
||||||
for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) {
|
for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) {
|
||||||
KThread* thread = cur_node->thread;
|
cur_node->thread->NotifyAvailable(this, result);
|
||||||
if (thread->GetState() == ThreadState::Waiting) {
|
|
||||||
thread->SetSyncedObject(this, result);
|
|
||||||
thread->SetState(ThreadState::Runnable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,38 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const;
|
[[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const;
|
||||||
|
|
||||||
|
void LinkNode(ThreadListNode* node) {
|
||||||
|
// Link the node to the list.
|
||||||
|
if (thread_list_tail == nullptr) {
|
||||||
|
thread_list_head = node;
|
||||||
|
} else {
|
||||||
|
thread_list_tail->next = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_list_tail = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnlinkNode(ThreadListNode* node) {
|
||||||
|
// Unlink the node from the list.
|
||||||
|
ThreadListNode* prev_ptr =
|
||||||
|
reinterpret_cast<ThreadListNode*>(std::addressof(thread_list_head));
|
||||||
|
ThreadListNode* prev_val = nullptr;
|
||||||
|
ThreadListNode *prev, *tail_prev;
|
||||||
|
|
||||||
|
do {
|
||||||
|
prev = prev_ptr;
|
||||||
|
prev_ptr = prev_ptr->next;
|
||||||
|
tail_prev = prev_val;
|
||||||
|
prev_val = prev_ptr;
|
||||||
|
} while (prev_ptr != node);
|
||||||
|
|
||||||
|
if (thread_list_tail == node) {
|
||||||
|
thread_list_tail = tail_prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev->next = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit KSynchronizationObject(KernelCore& kernel);
|
explicit KSynchronizationObject(KernelCore& kernel);
|
||||||
~KSynchronizationObject() override;
|
~KSynchronizationObject() override;
|
||||||
|
|
|
@ -303,7 +303,7 @@ void KThread::Wakeup() {
|
||||||
|
|
||||||
if (GetState() == ThreadState::Waiting) {
|
if (GetState() == ThreadState::Waiting) {
|
||||||
if (sleeping_queue != nullptr) {
|
if (sleeping_queue != nullptr) {
|
||||||
sleeping_queue->WakeupThread(this);
|
sleeping_queue->EndWait(this, ResultSuccess);
|
||||||
} else {
|
} else {
|
||||||
SetState(ThreadState::Runnable);
|
SetState(ThreadState::Runnable);
|
||||||
}
|
}
|
||||||
|
@ -331,7 +331,7 @@ void KThread::StartTermination() {
|
||||||
|
|
||||||
// Signal.
|
// Signal.
|
||||||
signaled = true;
|
signaled = true;
|
||||||
NotifyAvailable();
|
KSynchronizationObject::NotifyAvailable();
|
||||||
|
|
||||||
// Clear previous thread in KScheduler.
|
// Clear previous thread in KScheduler.
|
||||||
KScheduler::ClearPreviousThread(kernel, this);
|
KScheduler::ClearPreviousThread(kernel, this);
|
||||||
|
@ -1026,6 +1026,44 @@ ResultCode KThread::Sleep(s64 timeout) {
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KThread::BeginWait(KThreadQueue* queue) {
|
||||||
|
// Set our state as waiting.
|
||||||
|
SetState(ThreadState::Waiting);
|
||||||
|
|
||||||
|
// Set our wait queue.
|
||||||
|
sleeping_queue = queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) {
|
||||||
|
// Lock the scheduler.
|
||||||
|
KScopedSchedulerLock sl(kernel);
|
||||||
|
|
||||||
|
// If we're waiting, notify our queue that we're available.
|
||||||
|
if (GetState() == ThreadState::Waiting) {
|
||||||
|
sleeping_queue->NotifyAvailable(this, signaled_object, wait_result_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KThread::EndWait(ResultCode wait_result_) {
|
||||||
|
// Lock the scheduler.
|
||||||
|
KScopedSchedulerLock sl(kernel);
|
||||||
|
|
||||||
|
// If we're waiting, notify our queue that we're available.
|
||||||
|
if (GetState() == ThreadState::Waiting) {
|
||||||
|
sleeping_queue->EndWait(this, wait_result_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KThread::CancelWait(ResultCode wait_result_, bool cancel_timer_task) {
|
||||||
|
// Lock the scheduler.
|
||||||
|
KScopedSchedulerLock sl(kernel);
|
||||||
|
|
||||||
|
// If we're waiting, notify our queue that we're available.
|
||||||
|
if (GetState() == ThreadState::Waiting) {
|
||||||
|
sleeping_queue->CancelWait(this, wait_result_, cancel_timer_task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void KThread::SetState(ThreadState state) {
|
void KThread::SetState(ThreadState state) {
|
||||||
KScopedSchedulerLock sl{kernel};
|
KScopedSchedulerLock sl{kernel};
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,23 @@ public:
|
||||||
wait_result = wait_res;
|
wait_result = wait_res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr void SetSyncedIndex(s32 index) {
|
||||||
|
synced_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr s32 GetSyncedIndex() const {
|
||||||
|
return synced_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void SetWaitResult(ResultCode wait_res) {
|
||||||
|
wait_result = wait_res;
|
||||||
|
synced_object = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ResultCode GetWaitResult() const {
|
||||||
|
return wait_result;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] ResultCode GetWaitResult(KSynchronizationObject** out) const {
|
[[nodiscard]] ResultCode GetWaitResult(KSynchronizationObject** out) const {
|
||||||
*out = synced_object;
|
*out = synced_object;
|
||||||
return wait_result;
|
return wait_result;
|
||||||
|
@ -596,6 +613,15 @@ public:
|
||||||
address_key_value = val;
|
address_key_value = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClearWaitQueue() {
|
||||||
|
sleeping_queue = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginWait(KThreadQueue* queue);
|
||||||
|
void NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_);
|
||||||
|
void EndWait(ResultCode wait_result_);
|
||||||
|
void CancelWait(ResultCode wait_result_, bool cancel_timer_task);
|
||||||
|
|
||||||
[[nodiscard]] bool HasWaiters() const {
|
[[nodiscard]] bool HasWaiters() const {
|
||||||
return !waiter_list.empty();
|
return !waiter_list.empty();
|
||||||
}
|
}
|
||||||
|
@ -707,6 +733,7 @@ private:
|
||||||
u32 address_key_value{};
|
u32 address_key_value{};
|
||||||
u32 suspend_request_flags{};
|
u32 suspend_request_flags{};
|
||||||
u32 suspend_allowed_flags{};
|
u32 suspend_allowed_flags{};
|
||||||
|
s32 synced_index{};
|
||||||
ResultCode wait_result{ResultSuccess};
|
ResultCode wait_result{ResultSuccess};
|
||||||
s32 base_priority{};
|
s32 base_priority{};
|
||||||
s32 physical_ideal_core_id{};
|
s32 physical_ideal_core_id{};
|
||||||
|
|
51
src/core/hle/kernel/k_thread_queue.cpp
Normal file
51
src/core/hle/kernel/k_thread_queue.cpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright 2021 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/kernel/k_thread_queue.h"
|
||||||
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/time_manager.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
void KThreadQueue::NotifyAvailable([[maybe_unused]] KThread* waiting_thread,
|
||||||
|
[[maybe_unused]] KSynchronizationObject* signaled_object,
|
||||||
|
[[maybe_unused]] ResultCode wait_result) {}
|
||||||
|
|
||||||
|
void KThreadQueue::EndWait(KThread* waiting_thread, ResultCode wait_result) {
|
||||||
|
// Set the thread's wait result.
|
||||||
|
waiting_thread->SetWaitResult(wait_result);
|
||||||
|
|
||||||
|
// Set the thread as runnable.
|
||||||
|
waiting_thread->SetState(ThreadState::Runnable);
|
||||||
|
|
||||||
|
// Clear the thread's wait queue.
|
||||||
|
waiting_thread->ClearWaitQueue();
|
||||||
|
|
||||||
|
// Cancel the thread task.
|
||||||
|
kernel.TimeManager().UnscheduleTimeEvent(waiting_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KThreadQueue::CancelWait(KThread* waiting_thread, ResultCode wait_result,
|
||||||
|
bool cancel_timer_task) {
|
||||||
|
// Set the thread's wait result.
|
||||||
|
waiting_thread->SetWaitResult(wait_result);
|
||||||
|
|
||||||
|
// Set the thread as runnable.
|
||||||
|
waiting_thread->SetState(ThreadState::Runnable);
|
||||||
|
|
||||||
|
// Clear the thread's wait queue.
|
||||||
|
waiting_thread->ClearWaitQueue();
|
||||||
|
|
||||||
|
// Cancel the thread task.
|
||||||
|
if (cancel_timer_task) {
|
||||||
|
kernel.TimeManager().UnscheduleTimeEvent(waiting_thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KThreadQueueWithoutEndWait::EndWait([[maybe_unused]] KThread* waiting_thread,
|
||||||
|
[[maybe_unused]] ResultCode wait_result) {}
|
||||||
|
|
||||||
|
} // namespace Kernel
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/kernel/k_scheduler.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -11,7 +12,16 @@ namespace Kernel {
|
||||||
class KThreadQueue {
|
class KThreadQueue {
|
||||||
public:
|
public:
|
||||||
explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {}
|
explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {}
|
||||||
|
virtual ~KThreadQueue(){};
|
||||||
|
|
||||||
|
virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object,
|
||||||
|
ResultCode wait_result);
|
||||||
|
virtual void EndWait(KThread* waiting_thread, ResultCode wait_result);
|
||||||
|
virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result,
|
||||||
|
bool cancel_timer_task);
|
||||||
|
|
||||||
|
// Deprecated, will be removed in subsequent commits.
|
||||||
|
public:
|
||||||
bool IsEmpty() const {
|
bool IsEmpty() const {
|
||||||
return wait_list.empty();
|
return wait_list.empty();
|
||||||
}
|
}
|
||||||
|
@ -78,4 +88,11 @@ private:
|
||||||
KThread::WaiterList wait_list{};
|
KThread::WaiterList wait_list{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class KThreadQueueWithoutEndWait : public KThreadQueue {
|
||||||
|
public:
|
||||||
|
explicit KThreadQueueWithoutEndWait(KernelCore& kernel_) : KThreadQueue(kernel_) {}
|
||||||
|
|
||||||
|
virtual void EndWait(KThread* waiting_thread, ResultCode wait_result) override final;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
Loading…
Reference in a new issue