early-access version 2413

This commit is contained in:
pineappleEA 2022-01-18 04:57:01 +01:00
parent d3391096b9
commit 495ed56df7
8 changed files with 29 additions and 32 deletions

View file

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

View file

@ -341,10 +341,6 @@ public:
return *thread; return *thread;
} }
bool IsThreadWaiting() const {
return is_thread_waiting;
}
private: private:
friend class IPC::ResponseBuilder; friend class IPC::ResponseBuilder;
@ -379,7 +375,6 @@ private:
u32 domain_offset{}; u32 domain_offset{};
std::shared_ptr<SessionRequestManager> manager; std::shared_ptr<SessionRequestManager> manager;
bool is_thread_waiting{};
KernelCore& kernel; KernelCore& kernel;
Core::Memory::Memory& memory; Core::Memory::Memory& memory;

View file

@ -739,6 +739,12 @@ void KScheduler::ScheduleImpl() {
next_thread = idle_thread; next_thread = idle_thread;
} }
// We never want to schedule a dummy thread, as these are only used by host threads for locking.
if (next_thread->GetThreadType() == ThreadType::Dummy) {
ASSERT_MSG(false, "Dummy threads should never be scheduled!");
next_thread = idle_thread;
}
// If we're not actually switching thread, there's nothing to do. // If we're not actually switching thread, there's nothing to do.
if (next_thread == current_thread.load()) { if (next_thread == current_thread.load()) {
previous_thread->EnableDispatch(); previous_thread->EnableDispatch();

View file

@ -8,7 +8,6 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/scope_exit.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/hle_ipc.h"
@ -123,20 +122,10 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
// In the event that something fails here, stub a result to prevent the game from crashing.
// This is a work-around in the event that somehow we process a service request after the
// session has been closed by the game. This has been observed to happen rarely in Pokemon
// Sword/Shield and is likely a result of us using host threads/scheduling for services.
// TODO(bunnei): Find a better solution here.
auto error_guard = SCOPE_GUARD({ CompleteSyncRequest(*context); });
// Ensure we have a session request handler // Ensure we have a session request handler
if (manager->HasSessionRequestHandler(*context)) { if (manager->HasSessionRequestHandler(*context)) {
if (auto strong_ptr = manager->GetServiceThread().lock()) { if (auto strong_ptr = manager->GetServiceThread().lock()) {
strong_ptr->QueueSyncRequest(*parent, std::move(context)); strong_ptr->QueueSyncRequest(*parent, std::move(context));
// We succeeded.
error_guard.Cancel();
} else { } else {
ASSERT_MSG(false, "strong_ptr is nullptr!"); ASSERT_MSG(false, "strong_ptr is nullptr!");
} }
@ -171,13 +160,8 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) {
convert_to_domain = false; convert_to_domain = false;
} }
// Some service requests require the thread to block // The calling thread is waiting for this request to complete, so wake it up.
{ context.GetThread().EndWait(result);
KScopedSchedulerLock lock(kernel);
if (!context.IsThreadWaiting()) {
context.GetThread().EndWait(result);
}
}
return result; return result;
} }

View file

@ -106,7 +106,7 @@ KThread::~KThread() = default;
ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio,
s32 virt_core, KProcess* owner, ThreadType type) { s32 virt_core, KProcess* owner, ThreadType type) {
// Assert parameters are valid. // Assert parameters are valid.
ASSERT((type == ThreadType::Main) || ASSERT((type == ThreadType::Main) || (type == ThreadType::Dummy) ||
(Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority)); (Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority));
ASSERT((owner != nullptr) || (type != ThreadType::User)); ASSERT((owner != nullptr) || (type != ThreadType::User));
ASSERT(0 <= virt_core && virt_core < static_cast<s32>(Common::BitSize<u64>())); ASSERT(0 <= virt_core && virt_core < static_cast<s32>(Common::BitSize<u64>()));
@ -140,7 +140,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type)); UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type));
break; break;
} }
thread_type_for_debugging = type; thread_type = type;
// Set the ideal core ID and affinity mask. // Set the ideal core ID and affinity mask.
virtual_ideal_core_id = virt_core; virtual_ideal_core_id = virt_core;
@ -262,7 +262,7 @@ ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uint
} }
ResultCode KThread::InitializeDummyThread(KThread* thread) { ResultCode KThread::InitializeDummyThread(KThread* thread) {
return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Dummy); return thread->Initialize({}, {}, {}, DummyThreadPriority, 3, {}, ThreadType::Dummy);
} }
ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
@ -1097,6 +1097,12 @@ void KThread::EndWait(ResultCode wait_result_) {
// Lock the scheduler. // Lock the scheduler.
KScopedSchedulerLock sl(kernel); KScopedSchedulerLock sl(kernel);
// Dummy threads are just used by host threads for locking, and will never have a wait_queue.
if (thread_type == ThreadType::Dummy) {
ASSERT_MSG(false, "Dummy threads should never call EndWait!");
return;
}
// If we're waiting, notify our queue that we're available. // If we're waiting, notify our queue that we're available.
if (GetState() == ThreadState::Waiting) { if (GetState() == ThreadState::Waiting) {
wait_queue->EndWait(this, wait_result_); wait_queue->EndWait(this, wait_result_);

View file

@ -112,6 +112,7 @@ private:
public: public:
static constexpr s32 DefaultThreadPriority = 44; static constexpr s32 DefaultThreadPriority = 44;
static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1; static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1;
static constexpr s32 DummyThreadPriority = Svc::LowestThreadPriority + 2;
explicit KThread(KernelCore& kernel_); explicit KThread(KernelCore& kernel_);
~KThread() override; ~KThread() override;
@ -553,8 +554,8 @@ public:
return wait_reason_for_debugging; return wait_reason_for_debugging;
} }
[[nodiscard]] ThreadType GetThreadTypeForDebugging() const { [[nodiscard]] ThreadType GetThreadType() const {
return thread_type_for_debugging; return thread_type;
} }
void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) {
@ -753,12 +754,12 @@ private:
// For emulation // For emulation
std::shared_ptr<Common::Fiber> host_context{}; std::shared_ptr<Common::Fiber> host_context{};
bool is_single_core{}; bool is_single_core{};
ThreadType thread_type{};
// For debugging // For debugging
std::vector<KSynchronizationObject*> wait_objects_for_debugging; std::vector<KSynchronizationObject*> wait_objects_for_debugging;
VAddr mutex_wait_address_for_debugging{}; VAddr mutex_wait_address_for_debugging{};
ThreadWaitReasonForDebugging wait_reason_for_debugging{}; ThreadWaitReasonForDebugging wait_reason_for_debugging{};
ThreadType thread_type_for_debugging{};
public: public:
using ConditionVariableThreadTreeType = ConditionVariableThreadTree; using ConditionVariableThreadTreeType = ConditionVariableThreadTree;

View file

@ -12,6 +12,7 @@
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "common/thread.h" #include "common/thread.h"
#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/service_thread.h" #include "core/hle/kernel/service_thread.h"
@ -50,6 +51,10 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std
kernel.RegisterHostThread(); kernel.RegisterHostThread();
// Ensure the dummy thread allocated for this host thread is closed on exit.
auto* dummy_thread = kernel.GetCurrentEmuThread();
SCOPE_EXIT({ dummy_thread->Close(); });
while (true) { while (true) {
std::function<void()> task; std::function<void()> task;

View file

@ -95,7 +95,7 @@ std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList(
std::size_t row = 0; std::size_t row = 0;
auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) { auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) {
for (std::size_t i = 0; i < threads.size(); ++i) { for (std::size_t i = 0; i < threads.size(); ++i) {
if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) { if (threads[i]->GetThreadType() == Kernel::ThreadType::User) {
item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i], system)); item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i], system));
item_list.back()->row = row; item_list.back()->row = row;
} }
@ -153,7 +153,7 @@ QString WaitTreeCallstack::GetText() const {
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const {
std::vector<std::unique_ptr<WaitTreeItem>> list; std::vector<std::unique_ptr<WaitTreeItem>> list;
if (thread.GetThreadTypeForDebugging() != Kernel::ThreadType::User) { if (thread.GetThreadType() != Kernel::ThreadType::User) {
return list; return list;
} }