early-access version 3049

This commit is contained in:
pineappleEA 2022-10-25 15:36:49 +02:00
parent 4ff4da0401
commit 604f9582d6
6 changed files with 52 additions and 31 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 3048. This is the source code for early-access 3049.
## Legal Notice ## Legal Notice

View file

@ -51,17 +51,24 @@ bool GlobalSchedulerContext::IsLocked() const {
void GlobalSchedulerContext::RegisterDummyThreadForWakeup(KThread* thread) { void GlobalSchedulerContext::RegisterDummyThreadForWakeup(KThread* thread) {
ASSERT(IsLocked()); ASSERT(IsLocked());
woken_dummy_thread_list.push_back(thread);
woken_dummy_threads.insert(thread);
}
void GlobalSchedulerContext::UnregisterDummyThreadForWakeup(KThread* thread) {
ASSERT(IsLocked());
woken_dummy_threads.erase(thread);
} }
void GlobalSchedulerContext::WakeupWaitingDummyThreads() { void GlobalSchedulerContext::WakeupWaitingDummyThreads() {
ASSERT(IsLocked()); ASSERT(IsLocked());
for (auto* thread : woken_dummy_thread_list) { for (auto* thread : woken_dummy_threads) {
thread->IfDummyThreadEndWait(); thread->DummyThreadEndWait();
} }
woken_dummy_thread_list.clear(); woken_dummy_threads.clear();
} }
} // namespace Kernel } // namespace Kernel

View file

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <atomic> #include <atomic>
#include <set>
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
@ -58,6 +59,7 @@ public:
/// Returns true if the global scheduler lock is acquired /// Returns true if the global scheduler lock is acquired
bool IsLocked() const; bool IsLocked() const;
void UnregisterDummyThreadForWakeup(KThread* thread);
void RegisterDummyThreadForWakeup(KThread* thread); void RegisterDummyThreadForWakeup(KThread* thread);
void WakeupWaitingDummyThreads(); void WakeupWaitingDummyThreads();
@ -80,7 +82,7 @@ private:
LockType scheduler_lock; LockType scheduler_lock;
/// Lists dummy threads pending wakeup on lock release /// Lists dummy threads pending wakeup on lock release
std::vector<KThread*> woken_dummy_thread_list; std::set<KThread*> woken_dummy_threads;
/// Lists all thread ids that aren't deleted/etc. /// Lists all thread ids that aren't deleted/etc.
std::vector<KThread*> thread_list; std::vector<KThread*> thread_list;

View file

@ -81,8 +81,8 @@ void KScheduler::RescheduleCurrentHLEThread(KernelCore& kernel) {
// HACK: we cannot schedule from this thread, it is not a core thread // HACK: we cannot schedule from this thread, it is not a core thread
ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1); ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1);
// Special case to ensure dummy threads that are waiting block // Ensure dummy threads that are waiting block.
GetCurrentThread(kernel).IfDummyThreadTryWait(); GetCurrentThread(kernel).DummyThreadBeginWait();
ASSERT(GetCurrentThread(kernel).GetState() != ThreadState::Waiting); ASSERT(GetCurrentThread(kernel).GetState() != ThreadState::Waiting);
GetCurrentThread(kernel).EnableDispatch(); GetCurrentThread(kernel).EnableDispatch();
@ -317,6 +317,13 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
// HACK: any waiting dummy threads can wake up now. // HACK: any waiting dummy threads can wake up now.
kernel.GlobalSchedulerContext().WakeupWaitingDummyThreads(); kernel.GlobalSchedulerContext().WakeupWaitingDummyThreads();
// HACK: if we are a dummy thread, and we need to go sleep, indicate
// that for when the lock is released.
KThread* const cur_thread = GetCurrentThreadPointer(kernel);
if (cur_thread->IsDummyThread() && cur_thread->GetState() != ThreadState::Runnable) {
cur_thread->RequestDummyThreadWait();
}
return cores_needing_scheduling; return cores_needing_scheduling;
} }
@ -534,6 +541,12 @@ void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, Threa
GetPriorityQueue(kernel).Remove(thread); GetPriorityQueue(kernel).Remove(thread);
IncrementScheduledCount(thread); IncrementScheduledCount(thread);
SetSchedulerUpdateNeeded(kernel); SetSchedulerUpdateNeeded(kernel);
if (thread->IsDummyThread()) {
// HACK: if this is a dummy thread, it should no longer wake up when the
// scheduler lock is released.
kernel.GlobalSchedulerContext().UnregisterDummyThreadForWakeup(thread);
}
} else if (cur_state == ThreadState::Runnable) { } else if (cur_state == ThreadState::Runnable) {
// If we're now runnable, then we weren't previously, and we should add. // If we're now runnable, then we weren't previously, and we should add.
GetPriorityQueue(kernel).PushBack(thread); GetPriorityQueue(kernel).PushBack(thread);

View file

@ -1176,30 +1176,29 @@ Result KThread::Sleep(s64 timeout) {
R_SUCCEED(); R_SUCCEED();
} }
void KThread::IfDummyThreadTryWait() { void KThread::RequestDummyThreadWait() {
if (!IsDummyThread()) { ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
return; ASSERT(this->IsDummyThread());
}
if (GetState() != ThreadState::Waiting) { // We will block when the scheduler lock is released.
return; dummy_thread_runnable.store(false);
}
ASSERT(!kernel.IsPhantomModeForSingleCore());
// Block until we are no longer waiting.
std::unique_lock lk(dummy_wait_lock);
dummy_wait_cv.wait(
lk, [&] { return GetState() != ThreadState::Waiting || kernel.IsShuttingDown(); });
} }
void KThread::IfDummyThreadEndWait() { void KThread::DummyThreadBeginWait() {
if (!IsDummyThread()) { ASSERT(this->IsDummyThread());
return; ASSERT(!kernel.IsPhantomModeForSingleCore());
}
// Block until runnable is no longer false.
dummy_thread_runnable.wait(false);
}
void KThread::DummyThreadEndWait() {
ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
ASSERT(this->IsDummyThread());
// Wake up the waiting thread. // Wake up the waiting thread.
dummy_wait_cv.notify_one(); dummy_thread_runnable.store(true);
dummy_thread_runnable.notify_one();
} }
void KThread::BeginWait(KThreadQueue* queue) { void KThread::BeginWait(KThreadQueue* queue) {

View file

@ -643,8 +643,9 @@ public:
// therefore will not block on guest kernel synchronization primitives. These methods handle // therefore will not block on guest kernel synchronization primitives. These methods handle
// blocking as needed. // blocking as needed.
void IfDummyThreadTryWait(); void RequestDummyThreadWait();
void IfDummyThreadEndWait(); void DummyThreadBeginWait();
void DummyThreadEndWait();
[[nodiscard]] uintptr_t GetArgument() const { [[nodiscard]] uintptr_t GetArgument() const {
return argument; return argument;
@ -777,8 +778,7 @@ private:
bool is_single_core{}; bool is_single_core{};
ThreadType thread_type{}; ThreadType thread_type{};
StepState step_state{}; StepState step_state{};
std::mutex dummy_wait_lock; std::atomic<bool> dummy_thread_runnable{true};
std::condition_variable dummy_wait_cv;
// For debugging // For debugging
std::vector<KSynchronizationObject*> wait_objects_for_debugging; std::vector<KSynchronizationObject*> wait_objects_for_debugging;