3 changed files with 87 additions and 54 deletions
-
1src/core/CMakeLists.txt
-
80src/core/hle/kernel/k_light_condition_variable.cpp
-
60src/core/hle/kernel/k_light_condition_variable.h
@ -0,0 +1,80 @@ |
|||||
|
// Copyright 2021 yuzu Emulator Project
|
||||
|
// Licensed under GPLv2 or any later version
|
||||
|
// Refer to the license.txt file included.
|
||||
|
|
||||
|
#include "core/hle/kernel/k_light_condition_variable.h"
|
||||
|
#include "core/hle/kernel/k_scheduler.h"
|
||||
|
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
|
||||
|
#include "core/hle/kernel/k_thread_queue.h"
|
||||
|
#include "core/hle/kernel/svc_results.h"
|
||||
|
|
||||
|
namespace Kernel { |
||||
|
|
||||
|
namespace { |
||||
|
|
||||
|
class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue { |
||||
|
private: |
||||
|
KThread::WaiterList* m_wait_list; |
||||
|
bool m_allow_terminating_thread; |
||||
|
|
||||
|
public: |
||||
|
ThreadQueueImplForKLightConditionVariable(KernelCore& kernel_, KThread::WaiterList* wl, |
||||
|
bool term) |
||||
|
: KThreadQueue(kernel_), m_wait_list(wl), m_allow_terminating_thread(term) {} |
||||
|
|
||||
|
virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, |
||||
|
bool cancel_timer_task) override { |
||||
|
// Only process waits if we're allowed to.
|
||||
|
if (ResultTerminationRequested == wait_result && m_allow_terminating_thread) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Remove the thread from the waiting thread from the light condition variable.
|
||||
|
m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); |
||||
|
|
||||
|
// Invoke the base cancel wait handler.
|
||||
|
KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
} // namespace
|
||||
|
|
||||
|
void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_terminating_thread) { |
||||
|
// Create thread queue.
|
||||
|
KThread* owner = GetCurrentThreadPointer(kernel); |
||||
|
|
||||
|
ThreadQueueImplForKLightConditionVariable wait_queue(kernel, std::addressof(wait_list), |
||||
|
allow_terminating_thread); |
||||
|
|
||||
|
// Sleep the thread.
|
||||
|
{ |
||||
|
KScopedSchedulerLockAndSleep lk(kernel, owner, timeout); |
||||
|
|
||||
|
if (!allow_terminating_thread && owner->IsTerminationRequested()) { |
||||
|
lk.CancelSleep(); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
lock->Unlock(); |
||||
|
|
||||
|
// Add the thread to the queue.
|
||||
|
wait_list.push_back(*owner); |
||||
|
|
||||
|
// Begin waiting.
|
||||
|
owner->BeginWait(std::addressof(wait_queue)); |
||||
|
} |
||||
|
|
||||
|
// Re-acquire the lock.
|
||||
|
lock->Lock(); |
||||
|
} |
||||
|
|
||||
|
void KLightConditionVariable::Broadcast() { |
||||
|
KScopedSchedulerLock lk(kernel); |
||||
|
|
||||
|
// Signal all threads.
|
||||
|
for (auto it = wait_list.begin(); it != wait_list.end(); it = wait_list.erase(it)) { |
||||
|
it->EndWait(ResultSuccess); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} // namespace Kernel
|
||||
@ -1,73 +1,25 @@ |
|||||
// Copyright 2020 yuzu Emulator Project |
|
||||
|
// Copyright 2021 yuzu Emulator Project |
||||
// Licensed under GPLv2 or any later version |
// Licensed under GPLv2 or any later version |
||||
// Refer to the license.txt file included. |
// Refer to the license.txt file included. |
||||
|
|
||||
// This file references various implementation details from Atmosphere, an open-source firmware for |
|
||||
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. |
|
||||
|
|
||||
#pragma once |
#pragma once |
||||
|
|
||||
#include "common/common_types.h" |
#include "common/common_types.h" |
||||
#include "core/hle/kernel/k_scheduler.h" |
|
||||
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
|
||||
#include "core/hle/kernel/time_manager.h" |
|
||||
|
#include "core/hle/kernel/k_thread.h" |
||||
|
|
||||
namespace Kernel { |
namespace Kernel { |
||||
|
|
||||
class KernelCore; |
class KernelCore; |
||||
|
class KLightLock; |
||||
|
|
||||
class KLightConditionVariable { |
class KLightConditionVariable { |
||||
public: |
public: |
||||
explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {} |
explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {} |
||||
|
|
||||
void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true) { |
|
||||
WaitImpl(lock, timeout, allow_terminating_thread); |
|
||||
} |
|
||||
|
|
||||
void Broadcast() { |
|
||||
KScopedSchedulerLock lk{kernel}; |
|
||||
|
|
||||
// Signal all threads. |
|
||||
for (auto& thread : wait_list) { |
|
||||
thread.SetState(ThreadState::Runnable); |
|
||||
} |
|
||||
} |
|
||||
|
void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true); |
||||
|
void Broadcast(); |
||||
|
|
||||
private: |
private: |
||||
void WaitImpl(KLightLock* lock, s64 timeout, bool allow_terminating_thread) { |
|
||||
KThread* owner = GetCurrentThreadPointer(kernel); |
|
||||
|
|
||||
// Sleep the thread. |
|
||||
{ |
|
||||
KScopedSchedulerLockAndSleep lk{kernel, owner, timeout}; |
|
||||
|
|
||||
if (!allow_terminating_thread && owner->IsTerminationRequested()) { |
|
||||
lk.CancelSleep(); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
lock->Unlock(); |
|
||||
|
|
||||
// Set the thread as waiting. |
|
||||
GetCurrentThread(kernel).SetState(ThreadState::Waiting); |
|
||||
|
|
||||
// Add the thread to the queue. |
|
||||
wait_list.push_back(GetCurrentThread(kernel)); |
|
||||
} |
|
||||
|
|
||||
// Remove the thread from the wait list. |
|
||||
{ |
|
||||
KScopedSchedulerLock sl{kernel}; |
|
||||
|
|
||||
wait_list.erase(wait_list.iterator_to(GetCurrentThread(kernel))); |
|
||||
} |
|
||||
|
|
||||
// Cancel the task that the sleep setup. |
|
||||
kernel.TimeManager().UnscheduleTimeEvent(owner); |
|
||||
|
|
||||
// Re-acquire the lock. |
|
||||
lock->Lock(); |
|
||||
} |
|
||||
|
|
||||
KernelCore& kernel; |
KernelCore& kernel; |
||||
KThread::WaiterList wait_list{}; |
KThread::WaiterList wait_list{}; |
||||
}; |
}; |
||||
|
|||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue