From e31425df3877636c098ec7426ebd2067920715cb Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 24 Feb 2020 22:04:12 -0400 Subject: General: Recover Prometheus project from harddrive failure This commit: Implements CPU Interrupts, Replaces Cycle Timing for Host Timing, Reworks the Kernel's Scheduler, Introduce Idle State and Suspended State, Recreates the bootmanager, Initializes Multicore system. --- src/core/hle/kernel/kernel.cpp | 84 ++++++- src/core/hle/kernel/kernel.h | 19 ++ src/core/hle/kernel/physical_core.cpp | 37 ++- src/core/hle/kernel/physical_core.h | 21 ++ src/core/hle/kernel/process.cpp | 17 +- src/core/hle/kernel/scheduler.cpp | 415 ++++++++++++++++++++++++---------- src/core/hle/kernel/scheduler.h | 94 ++++---- src/core/hle/kernel/svc.cpp | 21 +- src/core/hle/kernel/thread.cpp | 232 ++++++++----------- src/core/hle/kernel/thread.h | 81 +++++-- src/core/hle/kernel/time_manager.cpp | 2 +- 11 files changed, 679 insertions(+), 344 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 7655382fa..ba051a7d8 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -13,11 +13,13 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "common/thread.h" #include "core/arm/arm_interface.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/cpu_manager.h" #include "core/device_memory.h" #include "core/hardware_properties.h" #include "core/hle/kernel/client_port.h" @@ -117,7 +119,9 @@ struct KernelCore::Impl { InitializeSystemResourceLimit(kernel); InitializeMemoryLayout(); InitializeThreads(); - InitializePreemption(); + InitializePreemption(kernel); + InitializeSchedulers(); + InitializeSuspendThreads(); } void Shutdown() { @@ -155,6 +159,12 @@ struct KernelCore::Impl { } } + void InitializeSchedulers() { + for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + cores[i].Scheduler().Initialize(); + } + } + // Creates the default system resource limit void InitializeSystemResourceLimit(KernelCore& kernel) { system_resource_limit = ResourceLimit::Create(kernel); @@ -178,10 +188,13 @@ struct KernelCore::Impl { Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback); } - void InitializePreemption() { - preemption_event = - Core::Timing::CreateEvent("PreemptionCallback", [this](u64 userdata, s64 cycles_late) { - global_scheduler.PreemptThreads(); + void InitializePreemption(KernelCore& kernel) { + preemption_event = Core::Timing::CreateEvent( + "PreemptionCallback", [this, &kernel](u64 userdata, s64 cycles_late) { + { + SchedulerLock lock(kernel); + global_scheduler.PreemptThreads(); + } s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10)); system.CoreTiming().ScheduleEvent(time_interval, preemption_event); }); @@ -190,6 +203,20 @@ struct KernelCore::Impl { system.CoreTiming().ScheduleEvent(time_interval, preemption_event); } + void InitializeSuspendThreads() { + for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + std::string name = "Suspend Thread Id:" + std::to_string(i); + std::function init_func = + system.GetCpuManager().GetSuspendThreadStartFunc(); + void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); + ThreadType type = + static_cast(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND); + auto thread_res = Thread::Create(system, type, name, 0, 0, 0, static_cast(i), 0, + nullptr, std::move(init_func), init_func_parameter); + suspend_threads[i] = std::move(thread_res).Unwrap(); + } + } + void MakeCurrentProcess(Process* process) { current_process = process; @@ -201,7 +228,10 @@ struct KernelCore::Impl { core.SetIs64Bit(process->Is64BitProcess()); } - system.Memory().SetCurrentPageTable(*process); + u32 core_id = GetCurrentHostThreadID(); + if (core_id < Core::Hardware::NUM_CPU_CORES) { + system.Memory().SetCurrentPageTable(*process, core_id); + } } void RegisterCoreThread(std::size_t core_id) { @@ -219,7 +249,9 @@ struct KernelCore::Impl { std::unique_lock lock{register_thread_mutex}; const std::thread::id this_id = std::this_thread::get_id(); const auto it = host_thread_ids.find(this_id); - ASSERT(it == host_thread_ids.end()); + if (it != host_thread_ids.end()) { + return; + } host_thread_ids[this_id] = registered_thread_ids++; } @@ -343,6 +375,8 @@ struct KernelCore::Impl { std::shared_ptr irs_shared_mem; std::shared_ptr time_shared_mem; + std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; + // System context Core::System& system; }; @@ -412,6 +446,26 @@ const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const { return impl->cores[id]; } +Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() { + u32 core_id = impl->GetCurrentHostThreadID(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + return impl->cores[core_id]; +} + +const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { + u32 core_id = impl->GetCurrentHostThreadID(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + return impl->cores[core_id]; +} + +Kernel::Scheduler& KernelCore::CurrentScheduler() { + return CurrentPhysicalCore().Scheduler(); +} + +const Kernel::Scheduler& KernelCore::CurrentScheduler() const { + return CurrentPhysicalCore().Scheduler(); +} + Kernel::Synchronization& KernelCore::Synchronization() { return impl->synchronization; } @@ -557,4 +611,20 @@ const Kernel::SharedMemory& KernelCore::GetTimeSharedMem() const { return *impl->time_shared_mem; } +void KernelCore::Suspend(bool in_suspention) { + const bool should_suspend = exception_exited || in_suspention; + { + SchedulerLock lock(*this); + ThreadStatus status = should_suspend ? ThreadStatus::Ready : ThreadStatus::WaitSleep; + for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + impl->suspend_threads[i]->SetStatus(status); + } + } +} + +void KernelCore::ExceptionalExit() { + exception_exited = true; + Suspend(true); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 83de1f542..5d32a8329 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -110,6 +110,18 @@ public: /// Gets the an instance of the respective physical CPU core. const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; + /// Gets the sole instance of the Scheduler at the current running core. + Kernel::Scheduler& CurrentScheduler(); + + /// Gets the sole instance of the Scheduler at the current running core. + const Kernel::Scheduler& CurrentScheduler() const; + + /// Gets the an instance of the current physical CPU core. + Kernel::PhysicalCore& CurrentPhysicalCore(); + + /// Gets the an instance of the current physical CPU core. + const Kernel::PhysicalCore& CurrentPhysicalCore() const; + /// Gets the an instance of the Synchronization Interface. Kernel::Synchronization& Synchronization(); @@ -191,6 +203,12 @@ public: /// Gets the shared memory object for Time services. const Kernel::SharedMemory& GetTimeSharedMem() const; + /// Suspend/unsuspend the OS. + void Suspend(bool in_suspention); + + /// Exceptional exit the OS. + void ExceptionalExit(); + private: friend class Object; friend class Process; @@ -219,6 +237,7 @@ private: struct Impl; std::unique_ptr impl; + bool exception_exited{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index a15011076..69202540b 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -2,12 +2,15 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/assert.h" #include "common/logging/log.h" +#include "common/spin_lock.h" #include "core/arm/arm_interface.h" #ifdef ARCHITECTURE_x86_64 #include "core/arm/dynarmic/arm_dynarmic_32.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" #endif +#include "core/arm/cpu_interrupt_handler.h" #include "core/arm/exclusive_monitor.h" #include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" @@ -19,21 +22,23 @@ namespace Kernel { PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor) - : core_index{id} { + : interrupt_handler{}, core_index{id} { #ifdef ARCHITECTURE_x86_64 - arm_interface_32 = - std::make_unique(system, exclusive_monitor, core_index); - arm_interface_64 = - std::make_unique(system, exclusive_monitor, core_index); - + arm_interface_32 = std::make_unique(system, interrupt_handler, + exclusive_monitor, core_index); + arm_interface_64 = std::make_unique(system, interrupt_handler, + exclusive_monitor, core_index); #else using Core::ARM_Unicorn; - arm_interface_32 = std::make_unique(system, ARM_Unicorn::Arch::AArch32); - arm_interface_64 = std::make_unique(system, ARM_Unicorn::Arch::AArch64); + arm_interface_32 = + std::make_unique(system, interrupt_handler, ARM_Unicorn::Arch::AArch32); + arm_interface_64 = + std::make_unique(system, interrupt_handler, ARM_Unicorn::Arch::AArch64); LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); #endif scheduler = std::make_unique(system, core_index); + guard = std::make_unique(); } PhysicalCore::~PhysicalCore() = default; @@ -47,6 +52,10 @@ void PhysicalCore::Step() { arm_interface->Step(); } +void PhysicalCore::Idle() { + interrupt_handler.AwaitInterrupt(); +} + void PhysicalCore::Stop() { arm_interface->PrepareReschedule(); } @@ -63,4 +72,16 @@ void PhysicalCore::SetIs64Bit(bool is_64_bit) { } } +void PhysicalCore::Interrupt() { + guard->lock(); + interrupt_handler.SetInterrupt(true); + guard->unlock(); +} + +void PhysicalCore::ClearInterrupt() { + guard->lock(); + interrupt_handler.SetInterrupt(false); + guard->unlock(); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 3269166be..c3da30b72 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -7,6 +7,12 @@ #include #include +#include "core/arm/cpu_interrupt_handler.h" + +namespace Common { + class SpinLock; +} + namespace Kernel { class Scheduler; } // namespace Kernel @@ -32,11 +38,24 @@ public: /// Execute current jit state void Run(); + /// Set this core in IdleState. + void Idle(); /// Execute a single instruction in current jit. void Step(); /// Stop JIT execution/exit void Stop(); + /// Interrupt this physical core. + void Interrupt(); + + /// Clear this core's interrupt + void ClearInterrupt(); + + /// Check if this core is interrupted + bool IsInterrupted() const { + return interrupt_handler.IsInterrupted(); + } + // Shutdown this physical core. void Shutdown(); @@ -71,11 +90,13 @@ public: void SetIs64Bit(bool is_64_bit); private: + Core::CPUInterruptHandler interrupt_handler; std::size_t core_index; std::unique_ptr arm_interface_32; std::unique_ptr arm_interface_64; std::unique_ptr scheduler; Core::ARM_Interface* arm_interface{}; + std::unique_ptr guard; }; } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index c4c5199b1..7e26a54f4 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -30,14 +30,15 @@ namespace { /** * Sets up the primary application thread * + * @param system The system instance to create the main thread under. * @param owner_process The parent process for the main thread - * @param kernel The kernel instance to create the main thread under. * @param priority The priority to give the main thread */ -void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority, VAddr stack_top) { +void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); - auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, - owner_process.GetIdealCore(), stack_top, owner_process); + ThreadType type = THREADTYPE_USER; + auto thread_res = Thread::Create(system, type, "main", entry_point, priority, 0, + owner_process.GetIdealCore(), stack_top, &owner_process); std::shared_ptr thread = std::move(thread_res).Unwrap(); @@ -48,8 +49,12 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority, V thread->GetContext32().cpu_registers[1] = thread_handle; thread->GetContext64().cpu_registers[1] = thread_handle; + auto& kernel = system.Kernel(); // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires - thread->ResumeFromWait(); + { + SchedulerLock lock{kernel}; + thread->SetStatus(ThreadStatus::Ready); + } } } // Anonymous namespace @@ -294,7 +299,7 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) { ChangeStatus(ProcessStatus::Running); - SetupMainThread(*this, kernel, main_thread_priority, main_thread_stack_top); + SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); resource_limit->Reserve(ResourceType::Threads, 1); resource_limit->Reserve(ResourceType::PhysicalMemory, main_thread_stack_size); } diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 1140c72a3..5166020a0 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -11,11 +11,15 @@ #include #include "common/assert.h" +#include "common/bit_util.h" +#include "common/fiber.h" #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/cpu_manager.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/time_manager.h" @@ -27,78 +31,108 @@ GlobalScheduler::GlobalScheduler(KernelCore& kernel) : kernel{kernel} {} GlobalScheduler::~GlobalScheduler() = default; void GlobalScheduler::AddThread(std::shared_ptr thread) { + global_list_guard.lock(); thread_list.push_back(std::move(thread)); + global_list_guard.unlock(); } void GlobalScheduler::RemoveThread(std::shared_ptr thread) { + global_list_guard.lock(); thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), thread_list.end()); + global_list_guard.unlock(); } -void GlobalScheduler::UnloadThread(std::size_t core) { - Scheduler& sched = kernel.Scheduler(core); - sched.UnloadThread(); -} - -void GlobalScheduler::SelectThread(std::size_t core) { +u32 GlobalScheduler::SelectThreads() { const auto update_thread = [](Thread* thread, Scheduler& sched) { + sched.guard.lock(); if (thread != sched.selected_thread.get()) { if (thread == nullptr) { ++sched.idle_selection_count; } sched.selected_thread = SharedFrom(thread); } - sched.is_context_switch_pending = sched.selected_thread != sched.current_thread; + const bool reschedule_pending = sched.selected_thread != sched.current_thread; + sched.is_context_switch_pending = reschedule_pending; std::atomic_thread_fence(std::memory_order_seq_cst); + sched.guard.unlock(); + return reschedule_pending; }; - Scheduler& sched = kernel.Scheduler(core); - Thread* current_thread = nullptr; - // Step 1: Get top thread in schedule queue. - current_thread = scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front(); - if (current_thread) { - update_thread(current_thread, sched); - return; + if (!is_reselection_pending.load()) { + return 0; } - // Step 2: Try selecting a suggested thread. - Thread* winner = nullptr; - std::set sug_cores; - for (auto thread : suggested_queue[core]) { - s32 this_core = thread->GetProcessorID(); - Thread* thread_on_core = nullptr; - if (this_core >= 0) { - thread_on_core = scheduled_queue[this_core].front(); - } - if (this_core < 0 || thread != thread_on_core) { - winner = thread; - break; + std::array top_threads{}; + + u32 idle_cores{}; + + // Step 1: Get top thread in schedule queue. + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + Thread* top_thread = + scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front(); + if (top_thread != nullptr) { + // TODO(Blinkhawk): Implement Thread Pinning + } else { + idle_cores |= (1ul << core); } - sug_cores.insert(this_core); + top_threads[core] = top_thread; } - // if we got a suggested thread, select it, else do a second pass. - if (winner && winner->GetPriority() > 2) { - if (winner->IsRunning()) { - UnloadThread(static_cast(winner->GetProcessorID())); + + while (idle_cores != 0) { + u32 core_id = Common::CountTrailingZeroes32(idle_cores); + + if (!suggested_queue[core_id].empty()) { + std::array migration_candidates{}; + std::size_t num_candidates = 0; + auto iter = suggested_queue[core_id].begin(); + Thread* suggested = nullptr; + // Step 2: Try selecting a suggested thread. + while (iter != suggested_queue[core_id].end()) { + suggested = *iter; + iter++; + s32 suggested_core_id = suggested->GetProcessorID(); + Thread* top_thread = + suggested_core_id > 0 ? top_threads[suggested_core_id] : nullptr; + if (top_thread != suggested) { + if (top_thread != nullptr && + top_thread->GetPriority() < THREADPRIO_MAX_CORE_MIGRATION) { + suggested = nullptr; + break; + // There's a too high thread to do core migration, cancel + } + TransferToCore(suggested->GetPriority(), static_cast(core_id), suggested); + break; + } + migration_candidates[num_candidates++] = suggested_core_id; + } + // Step 3: Select a suggested thread from another core + if (suggested == nullptr) { + for (std::size_t i = 0; i < num_candidates; i++) { + s32 candidate_core = migration_candidates[i]; + suggested = top_threads[candidate_core]; + auto it = scheduled_queue[candidate_core].begin(); + it++; + Thread* next = it != scheduled_queue[candidate_core].end() ? *it : nullptr; + if (next != nullptr) { + TransferToCore(suggested->GetPriority(), static_cast(core_id), + suggested); + top_threads[candidate_core] = next; + break; + } + } + } + top_threads[core_id] = suggested; } - TransferToCore(winner->GetPriority(), static_cast(core), winner); - update_thread(winner, sched); - return; + + idle_cores &= ~(1ul << core_id); } - // Step 3: Select a suggested thread from another core - for (auto& src_core : sug_cores) { - auto it = scheduled_queue[src_core].begin(); - it++; - if (it != scheduled_queue[src_core].end()) { - Thread* thread_on_core = scheduled_queue[src_core].front(); - Thread* to_change = *it; - if (thread_on_core->IsRunning() || to_change->IsRunning()) { - UnloadThread(static_cast(src_core)); - } - TransferToCore(thread_on_core->GetPriority(), static_cast(core), thread_on_core); - current_thread = thread_on_core; - break; + u32 cores_needing_context_switch{}; + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + Scheduler& sched = kernel.Scheduler(core); + if (update_thread(top_threads[core], sched)) { + cores_needing_context_switch |= (1ul << core); } } - update_thread(current_thread, sched); + return cores_needing_context_switch; } bool GlobalScheduler::YieldThread(Thread* yielding_thread) { @@ -153,9 +187,6 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { if (winner != nullptr) { if (winner != yielding_thread) { - if (winner->IsRunning()) { - UnloadThread(static_cast(winner->GetProcessorID())); - } TransferToCore(winner->GetPriority(), s32(core_id), winner); } } else { @@ -195,9 +226,6 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread } if (winner != nullptr) { if (winner != yielding_thread) { - if (winner->IsRunning()) { - UnloadThread(static_cast(winner->GetProcessorID())); - } TransferToCore(winner->GetPriority(), static_cast(core_id), winner); } } else { @@ -213,7 +241,9 @@ void GlobalScheduler::PreemptThreads() { const u32 priority = preemption_priorities[core_id]; if (scheduled_queue[core_id].size(priority) > 0) { - scheduled_queue[core_id].front(priority)->IncrementYieldCount(); + if (scheduled_queue[core_id].size(priority) > 1) { + scheduled_queue[core_id].front(priority)->IncrementYieldCount(); + } scheduled_queue[core_id].yield(priority); if (scheduled_queue[core_id].size(priority) > 1) { scheduled_queue[core_id].front(priority)->IncrementYieldCount(); @@ -247,9 +277,6 @@ void GlobalScheduler::PreemptThreads() { } if (winner != nullptr) { - if (winner->IsRunning()) { - UnloadThread(static_cast(winner->GetProcessorID())); - } TransferToCore(winner->GetPriority(), s32(core_id), winner); current_thread = winner->GetPriority() <= current_thread->GetPriority() ? winner : current_thread; @@ -280,9 +307,6 @@ void GlobalScheduler::PreemptThreads() { } if (winner != nullptr) { - if (winner->IsRunning()) { - UnloadThread(static_cast(winner->GetProcessorID())); - } TransferToCore(winner->GetPriority(), s32(core_id), winner); current_thread = winner; } @@ -292,6 +316,28 @@ void GlobalScheduler::PreemptThreads() { } } +void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule, + Core::EmuThreadHandle global_thread) { + u32 current_core = global_thread.host_handle; + bool must_context_switch = global_thread.guest_handle != InvalidHandle && + (current_core < Core::Hardware::NUM_CPU_CORES); + while (cores_pending_reschedule != 0) { + u32 core = Common::CountTrailingZeroes32(cores_pending_reschedule); + ASSERT(core < Core::Hardware::NUM_CPU_CORES); + if (!must_context_switch || core != current_core) { + auto& phys_core = kernel.PhysicalCore(core); + phys_core.Interrupt(); + } else { + must_context_switch = true; + } + cores_pending_reschedule &= ~(1ul << core); + } + if (must_context_switch) { + auto& core_scheduler = kernel.CurrentScheduler(); + core_scheduler.TryDoContextSwitch(); + } +} + void GlobalScheduler::Suggest(u32 priority, std::size_t core, Thread* thread) { suggested_queue[core].add(thread, priority); } @@ -349,6 +395,108 @@ bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, } } +void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { + if (old_flags == thread->scheduling_state) { + return; + } + + if (static_cast(old_flags & static_cast(ThreadSchedMasks::LowMask)) == + ThreadSchedStatus::Runnable) { + // In this case the thread was running, now it's pausing/exitting + if (thread->processor_id >= 0) { + Unschedule(thread->current_priority, static_cast(thread->processor_id), thread); + } + + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + if (core != static_cast(thread->processor_id) && + ((thread->affinity_mask >> core) & 1) != 0) { + Unsuggest(thread->current_priority, core, thread); + } + } + } else if (thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable) { + // The thread is now set to running from being stopped + if (thread->processor_id >= 0) { + Schedule(thread->current_priority, static_cast(thread->processor_id), thread); + } + + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + if (core != static_cast(thread->processor_id) && + ((thread->affinity_mask >> core) & 1) != 0) { + Suggest(thread->current_priority, core, thread); + } + } + } + + SetReselectionPending(); +} + +void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priority) { + if (thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { + return; + } + if (thread->processor_id >= 0) { + Unschedule(old_priority, static_cast(thread->processor_id), thread); + } + + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + if (core != static_cast(thread->processor_id) && + ((thread->affinity_mask >> core) & 1) != 0) { + Unsuggest(old_priority, core, thread); + } + } + + if (thread->processor_id >= 0) { + // TODO(Blinkhawk): compare it with current thread running on current core, instead of + // checking running + if (thread->IsRunning()) { + SchedulePrepend(thread->current_priority, static_cast(thread->processor_id), + thread); + } else { + Schedule(thread->current_priority, static_cast(thread->processor_id), thread); + } + } + + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + if (core != static_cast(thread->processor_id) && + ((thread->affinity_mask >> core) & 1) != 0) { + Suggest(thread->current_priority, core, thread); + } + } + thread->IncrementYieldCount(); + SetReselectionPending(); +} + +void GlobalScheduler::AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinity_mask, + s32 old_core) { + if (thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable || + thread->current_priority >= THREADPRIO_COUNT) { + return; + } + + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + if (((old_affinity_mask >> core) & 1) != 0) { + if (core == static_cast(old_core)) { + Unschedule(thread->current_priority, core, thread); + } else { + Unsuggest(thread->current_priority, core, thread); + } + } + } + + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + if (((thread->affinity_mask >> core) & 1) != 0) { + if (core == static_cast(thread->processor_id)) { + Schedule(thread->current_priority, core, thread); + } else { + Suggest(thread->current_priority, core, thread); + } + } + } + + thread->IncrementYieldCount(); + SetReselectionPending(); +} + void GlobalScheduler::Shutdown() { for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { scheduled_queue[core].clear(); @@ -374,13 +522,12 @@ void GlobalScheduler::Unlock() { ASSERT(scope_lock > 0); return; } - for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - SelectThread(i); - } + u32 cores_pending_reschedule = SelectThreads(); + Core::EmuThreadHandle leaving_thread = current_owner; current_owner = Core::EmuThreadHandle::InvalidHandle(); scope_lock = 1; inner_lock.unlock(); - // TODO(Blinkhawk): Setup the interrupts and change context on current core. + EnableInterruptAndSchedule(cores_pending_reschedule, leaving_thread); } Scheduler::Scheduler(Core::System& system, std::size_t core_id) @@ -393,56 +540,83 @@ bool Scheduler::HaveReadyThreads() const { } Thread* Scheduler::GetCurrentThread() const { - return current_thread.get(); + if (current_thread) { + return current_thread.get(); + } + return idle_thread.get(); } Thread* Scheduler::GetSelectedThread() const { return selected_thread.get(); } -void Scheduler::SelectThreads() { - system.GlobalScheduler().SelectThread(core_id); -} - u64 Scheduler::GetLastContextSwitchTicks() const { return last_context_switch_time; } void Scheduler::TryDoContextSwitch() { + auto& phys_core = system.Kernel().CurrentPhysicalCore(); + if (phys_core.IsInterrupted()) { + phys_core.ClearInterrupt(); + } + guard.lock(); if (is_context_switch_pending) { SwitchContext(); + } else { + guard.unlock(); } } -void Scheduler::UnloadThread() { - Thread* const previous_thread = GetCurrentThread(); - Process* const previous_process = system.Kernel().CurrentProcess(); +void Scheduler::OnThreadStart() { + SwitchContextStep2(); +} - UpdateLastContextSwitchTime(previous_thread, previous_process); +void Scheduler::SwitchContextStep2() { + Thread* previous_thread = current_thread.get(); + Thread* new_thread = selected_thread.get(); - // Save context for previous thread - if (previous_thread) { - system.ArmInterface(core_id).SaveContext(previous_thread->GetContext32()); - system.ArmInterface(core_id).SaveContext(previous_thread->GetContext64()); - // Save the TPIDR_EL0 system register in case it was modified. - previous_thread->SetTPIDR_EL0(system.ArmInterface(core_id).GetTPIDR_EL0()); + // Load context of new thread + Process* const previous_process = + previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; - if (previous_thread->GetStatus() == ThreadStatus::Running) { - // This is only the case when a reschedule is triggered without the current thread - // yielding execution (i.e. an event triggered, system core time-sliced, etc) - previous_thread->SetStatus(ThreadStatus::Ready); + if (new_thread) { + new_thread->context_guard.lock(); + ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), + "Thread must be assigned to this core."); + ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready, + "Thread must be ready to become running."); + + // Cancel any outstanding wakeup events for this thread + current_thread = SharedFrom(new_thread); + new_thread->SetStatus(ThreadStatus::Running); + new_thread->SetIsRunning(true); + + auto* const thread_owner_process = current_thread->GetOwnerProcess(); + if (previous_process != thread_owner_process && thread_owner_process != nullptr) { + system.Kernel().MakeCurrentProcess(thread_owner_process); } - previous_thread->SetIsRunning(false); + if (!new_thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); + cpu_core.LoadContext(new_thread->GetContext32()); + cpu_core.LoadContext(new_thread->GetContext64()); + cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); + cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); + } + } else { + current_thread = nullptr; + // Note: We do not reset the current process and current page table when idling because + // technically we haven't changed processes, our threads are just paused. } - current_thread = nullptr; + guard.unlock(); } void Scheduler::SwitchContext() { - Thread* const previous_thread = GetCurrentThread(); - Thread* const new_thread = GetSelectedThread(); + Thread* previous_thread = current_thread.get(); + Thread* new_thread = selected_thread.get(); is_context_switch_pending = false; if (new_thread == previous_thread) { + guard.unlock(); return; } @@ -452,51 +626,44 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { - system.ArmInterface(core_id).SaveContext(previous_thread->GetContext32()); - system.ArmInterface(core_id).SaveContext(previous_thread->GetContext64()); - // Save the TPIDR_EL0 system register in case it was modified. - previous_thread->SetTPIDR_EL0(system.ArmInterface(core_id).GetTPIDR_EL0()); + if (!previous_thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); + cpu_core.SaveContext(previous_thread->GetContext32()); + cpu_core.SaveContext(previous_thread->GetContext64()); + // Save the TPIDR_EL0 system register in case it was modified. + previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); + } if (previous_thread->GetStatus() == ThreadStatus::Running) { - // This is only the case when a reschedule is triggered without the current thread - // yielding execution (i.e. an event triggered, system core time-sliced, etc) previous_thread->SetStatus(ThreadStatus::Ready); } previous_thread->SetIsRunning(false); + previous_thread->context_guard.unlock(); } - // Load context of new thread - if (new_thread) { - ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), - "Thread must be assigned to this core."); - ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready, - "Thread must be ready to become running."); - - // Cancel any outstanding wakeup events for this thread - new_thread->CancelWakeupTimer(); - current_thread = SharedFrom(new_thread); - new_thread->SetStatus(ThreadStatus::Running); - new_thread->SetIsRunning(true); - - auto* const thread_owner_process = current_thread->GetOwnerProcess(); - if (previous_process != thread_owner_process) { - system.Kernel().MakeCurrentProcess(thread_owner_process); - } + std::shared_ptr old_context; + if (previous_thread != nullptr) { + old_context = previous_thread->GetHostContext(); + } else { + old_context = idle_thread->GetHostContext(); + } - system.ArmInterface(core_id).LoadContext(new_thread->GetContext32()); - system.ArmInterface(core_id).LoadContext(new_thread->GetContext64()); - system.ArmInterface(core_id).SetTlsAddress(new_thread->GetTLSAddress()); - system.ArmInterface(core_id).SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); + std::shared_ptr next_context; + if (new_thread != nullptr) { + next_context = new_thread->GetHostContext(); } else { - current_thread = nullptr; - // Note: We do not reset the current process and current page table when idling because - // technically we haven't changed processes, our threads are just paused. + next_context = idle_thread->GetHostContext(); } + + Common::Fiber::YieldTo(old_context, next_context); + /// When a thread wakes up, the scheduler may have changed to other in another core. + auto& next_scheduler = system.Kernel().CurrentScheduler(); + next_scheduler.SwitchContextStep2(); } void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { const u64 prev_switch_ticks = last_context_switch_time; - const u64 most_recent_switch_ticks = system.CoreTiming().GetTicks(); + const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; if (thread != nullptr) { @@ -510,6 +677,16 @@ void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { last_context_switch_time = most_recent_switch_ticks; } +void Scheduler::Initialize() { + std::string name = "Idle Thread Id:" + std::to_string(core_id); + std::function init_func = system.GetCpuManager().GetIdleThreadStartFunc(); + void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); + ThreadType type = static_cast(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE); + auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast(core_id), 0, + nullptr, std::move(init_func), init_func_parameter); + idle_thread = std::move(thread_res).Unwrap(); +} + void Scheduler::Shutdown() { current_thread = nullptr; selected_thread = nullptr; diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 07df33f9c..16655b03f 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -11,6 +11,7 @@ #include "common/common_types.h" #include "common/multi_level_queue.h" +#include "common/spin_lock.h" #include "core/hardware_properties.h" #include "core/hle/kernel/thread.h" @@ -41,41 +42,17 @@ public: return thread_list; } - /** - * Add a thread to the suggested queue of a cpu core. Suggested threads may be - * picked if no thread is scheduled to run on the core. - */ - void Suggest(u32 priority, std::size_t core, Thread* thread); - - /** - * Remove a thread to the suggested queue of a cpu core. Suggested threads may be - * picked if no thread is scheduled to run on the core. - */ - void Unsuggest(u32 priority, std::size_t core, Thread* thread); - - /** - * Add a thread to the scheduling queue of a cpu core. The thread is added at the - * back the queue in its priority level. - */ - void Schedule(u32 priority, std::size_t core, Thread* thread); + /// Notify the scheduler a thread's status has changed. + void AdjustSchedulingOnStatus(Thread* thread, u32 old_flags); - /** - * Add a thread to the scheduling queue of a cpu core. The thread is added at the - * front the queue in its priority level. - */ - void SchedulePrepend(u32 priority, std::size_t core, Thread* thread); + /// Notify the scheduler a thread's priority has changed. + void AdjustSchedulingOnPriority(Thread* thread, u32 old_priority); - /// Reschedule an already scheduled thread based on a new priority - void Reschedule(u32 priority, std::size_t core, Thread* thread); - - /// Unschedules a thread. - void Unschedule(u32 priority, std::size_t core, Thread* thread); - - /// Selects a core and forces it to unload its current thread's context - void UnloadThread(std::size_t core); + /// Notify the scheduler a thread's core and/or affinity mask has changed. + void AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinity_mask, s32 old_core); /** - * Takes care of selecting the new scheduled thread in three steps: + * Takes care of selecting the new scheduled threads in three steps: * * 1. First a thread is selected from the top of the priority queue. If no thread * is obtained then we move to step two, else we are done. @@ -85,8 +62,10 @@ public: * * 3. Third is no suggested thread is found, we do a second pass and pick a running * thread in another core and swap it with its current thread. + * + * returns the cores needing scheduling. */ - void SelectThread(std::size_t core); + u32 SelectThreads(); bool HaveReadyThreads(std::size_t core_id) const { return !scheduled_queue[core_id].empty(); @@ -149,6 +128,39 @@ private: /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling /// and reschedules current core if needed. void Unlock(); + + void EnableInterruptAndSchedule(u32 cores_pending_reschedule, Core::EmuThreadHandle global_thread); + + /** + * Add a thread to the suggested queue of a cpu core. Suggested threads may be + * picked if no thread is scheduled to run on the core. + */ + void Suggest(u32 priority, std::size_t core, Thread* thread); + + /** + * Remove a thread to the suggested queue of a cpu core. Suggested threads may be + * picked if no thread is scheduled to run on the core. + */ + void Unsuggest(u32 priority, std::size_t core, Thread* thread); + + /** + * Add a thread to the scheduling queue of a cpu core. The thread is added at the + * back the queue in its priority level. + */ + void Schedule(u32 priority, std::size_t core, Thread* thread); + + /** + * Add a thread to the scheduling queue of a cpu core. The thread is added at the + * front the queue in its priority level. + */ + void SchedulePrepend(u32 priority, std::size_t core, Thread* thread); + + /// Reschedule an already scheduled thread based on a new priority + void Reschedule(u32 priority, std::size_t core, Thread* thread); + + /// Unschedules a thread. + void Unschedule(u32 priority, std::size_t core, Thread* thread); + /** * Transfers a thread into an specific core. If the destination_core is -1 * it will be unscheduled from its source code and added into its suggested @@ -174,6 +186,8 @@ private: std::atomic scope_lock{}; Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()}; + Common::SpinLock global_list_guard{}; + /// Lists all thread ids that aren't deleted/etc. std::vector> thread_list; KernelCore& kernel; @@ -190,12 +204,6 @@ public: /// Reschedules to the next available thread (call after current thread is suspended) void TryDoContextSwitch(); - /// Unloads currently running thread - void UnloadThread(); - - /// Select the threads in top of the scheduling multilist. - void SelectThreads(); - /// Gets the current running thread Thread* GetCurrentThread() const; @@ -209,15 +217,22 @@ public: return is_context_switch_pending; } + void Initialize(); + /// Shutdowns the scheduler. void Shutdown(); + void OnThreadStart(); + private: friend class GlobalScheduler; /// Switches the CPU's active thread context to that of the specified thread void SwitchContext(); + /// When a thread wakes up, it must run this through it's new scheduler + void SwitchContextStep2(); + /** * Called on every context switch to update the internal timestamp * This also updates the running time ticks for the given thread and @@ -233,12 +248,15 @@ private: std::shared_ptr current_thread = nullptr; std::shared_ptr selected_thread = nullptr; + std::shared_ptr idle_thread = nullptr; Core::System& system; u64 last_context_switch_time = 0; u64 idle_selection_count = 0; const std::size_t core_id; + Common::SpinLock guard{}; + bool is_context_switch_pending = false; }; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4ae4529f5..d7f0dcabd 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -863,9 +863,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks(); - out_ticks = thread_ticks + (core_timing.GetTicks() - prev_ctx_ticks); + out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { - out_ticks = core_timing.GetTicks() - prev_ctx_ticks; + out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks; } *result = out_ticks; @@ -1428,9 +1428,10 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1)); + ThreadType type = THREADTYPE_USER; CASCADE_RESULT(std::shared_ptr thread, - Thread::Create(kernel, "", entry_point, priority, arg, processor_id, stack_top, - *current_process)); + Thread::Create(system, type, "", entry_point, priority, arg, processor_id, stack_top, + current_process)); const auto new_thread_handle = current_process->GetHandleTable().Create(thread); if (new_thread_handle.Failed()) { @@ -1513,13 +1514,6 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { } else { current_thread->Sleep(nanoseconds); } - - if (is_redundant) { - // If it's redundant, the core is pretty much idle. Some games keep idling - // a core while it's doing nothing, we advance timing to avoid costly continuous - // calls. - system.CoreTiming().AddTicks(2000); - } system.PrepareReschedule(current_thread->GetProcessorID()); } @@ -1725,10 +1719,7 @@ static u64 GetSystemTick(Core::System& system) { auto& core_timing = system.CoreTiming(); // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) - const u64 result{Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks())}; - - // Advance time to defeat dumb games that busy-wait for the frame to end. - core_timing.AddTicks(400); + const u64 result{system.CoreTiming().GetClockTicks()}; return result; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index db7f379ac..8cb3593db 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -9,12 +9,14 @@ #include "common/assert.h" #include "common/common_types.h" +#include "common/fiber.h" #include "common/logging/log.h" #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/cpu_manager.h" #include "core/hardware_properties.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" @@ -23,6 +25,7 @@ #include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/time_manager.h" #include "core/hle/result.h" #include "core/memory.h" @@ -44,6 +47,7 @@ Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {} Thread::~Thread() = default; void Thread::Stop() { + SchedulerLock lock(kernel); // Cancel any outstanding wakeup events for this thread Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), global_handle); @@ -71,9 +75,8 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { // This function might be called from any thread so we have to be cautious and use the // thread-safe version of ScheduleEvent. - const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); Core::System::GetInstance().CoreTiming().ScheduleEvent( - cycles, kernel.ThreadWakeupCallbackEventType(), global_handle); + nanoseconds, kernel.ThreadWakeupCallbackEventType(), global_handle); } void Thread::CancelWakeupTimer() { @@ -125,6 +128,16 @@ void Thread::ResumeFromWait() { SetStatus(ThreadStatus::Ready); } +void Thread::OnWakeUp() { + SchedulerLock lock(kernel); + if (activity == ThreadActivity::Paused) { + SetStatus(ThreadStatus::Paused); + return; + } + + SetStatus(ThreadStatus::Ready); +} + void Thread::CancelWait() { if (GetSchedulingStatus() != ThreadSchedStatus::Paused) { is_sync_cancelled = true; @@ -153,12 +166,29 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, context.fpcr = 0; } -ResultVal> Thread::Create(KernelCore& kernel, std::string name, - VAddr entry_point, u32 priority, u64 arg, - s32 processor_id, VAddr stack_top, - Process& owner_process) { +std::shared_ptr Thread::GetHostContext() const { + return host_context; +} + +ResultVal> Thread::Create(Core::System& system, ThreadType type_flags, + std::string name, VAddr entry_point, u32 priority, + u64 arg, s32 processor_id, VAddr stack_top, + Process* owner_process) { + std::function init_func = system.GetCpuManager().GetGuestThreadStartFunc(); + void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); + return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top, + owner_process, std::move(init_func), init_func_parameter); +} + +ResultVal> Thread::Create(Core::System& system, ThreadType type_flags, + std::string name, VAddr entry_point, u32 priority, + u64 arg, s32 processor_id, VAddr stack_top, + Process* owner_process, + std::function&& thread_start_func, + void* thread_start_parameter) { + auto& kernel = system.Kernel(); // Check if priority is in ranged. Lowest priority -> highest priority id. - if (priority > THREADPRIO_LOWEST) { + if (priority > THREADPRIO_LOWEST && (type_flags & THREADTYPE_IDLE == 0)) { LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); return ERR_INVALID_THREAD_PRIORITY; } @@ -168,11 +198,12 @@ ResultVal> Thread::Create(KernelCore& kernel, std::strin return ERR_INVALID_PROCESSOR_ID; } - auto& system = Core::System::GetInstance(); - if (!system.Memory().IsValidVirtualAddress(owner_process, entry_point)) { - LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); - // TODO (bunnei): Find the correct error code to use here - return RESULT_UNKNOWN; + if (owner_process) { + if (!system.Memory().IsValidVirtualAddress(*owner_process, entry_point)) { + LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); + // TODO (bunnei): Find the correct error code to use here + return RESULT_UNKNOWN; + } } std::shared_ptr thread = std::make_shared(kernel); @@ -183,7 +214,7 @@ ResultVal> Thread::Create(KernelCore& kernel, std::strin thread->stack_top = stack_top; thread->tpidr_el0 = 0; thread->nominal_priority = thread->current_priority = priority; - thread->last_running_ticks = system.CoreTiming().GetTicks(); + thread->last_running_ticks = 0; thread->processor_id = processor_id; thread->ideal_core = processor_id; thread->affinity_mask = 1ULL << processor_id; @@ -193,16 +224,27 @@ ResultVal> Thread::Create(KernelCore& kernel, std::strin thread->wait_handle = 0; thread->name = std::move(name); thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); - thread->owner_process = &owner_process; - auto& scheduler = kernel.GlobalScheduler(); - scheduler.AddThread(thread); - thread->tls_address = thread->owner_process->CreateTLSRegion(); - - thread->owner_process->RegisterThread(thread.get()); - - ResetThreadContext32(thread->context_32, static_cast(stack_top), - static_cast(entry_point), static_cast(arg)); - ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); + thread->owner_process = owner_process; + thread->type = type_flags; + if ((type_flags & THREADTYPE_IDLE) == 0) { + auto& scheduler = kernel.GlobalScheduler(); + scheduler.AddThread(thread); + } + if (owner_process) { + thread->tls_address = thread->owner_process->CreateTLSRegion(); + thread->owner_process->RegisterThread(thread.get()); + } else { + thread->tls_address = 0; + } + // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used + // to initialize the context + if ((type_flags & THREADTYPE_HLE) == 0) { + ResetThreadContext32(thread->context_32, static_cast(stack_top), + static_cast(entry_point), static_cast(arg)); + ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); + } + thread->host_context = + std::make_shared(std::move(thread_start_func), thread_start_parameter); return MakeResult>(std::move(thread)); } @@ -258,7 +300,7 @@ void Thread::SetStatus(ThreadStatus new_status) { } if (status == ThreadStatus::Running) { - last_running_ticks = Core::System::GetInstance().CoreTiming().GetTicks(); + last_running_ticks = Core::System::GetInstance().CoreTiming().GetCPUTicks(); } status = new_status; @@ -375,38 +417,55 @@ void Thread::SetActivity(ThreadActivity value) { } void Thread::Sleep(s64 nanoseconds) { - // Sleep current thread and check for next thread to schedule - SetStatus(ThreadStatus::WaitSleep); + Handle event_handle{}; + { + SchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); + SetStatus(ThreadStatus::WaitSleep); + } - // Create an event to wake the thread up after the specified nanosecond delay has passed - WakeAfterDelay(nanoseconds); + if (event_handle != InvalidHandle) { + auto& time_manager = kernel.TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); + } } bool Thread::YieldSimple() { - auto& scheduler = kernel.GlobalScheduler(); - return scheduler.YieldThread(this); + bool result{}; + { + SchedulerLock lock(kernel); + result = kernel.GlobalScheduler().YieldThread(this); + } + return result; } bool Thread::YieldAndBalanceLoad() { - auto& scheduler = kernel.GlobalScheduler(); - return scheduler.YieldThreadAndBalanceLoad(this); + bool result{}; + { + SchedulerLock lock(kernel); + result = kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this); + } + return result; } bool Thread::YieldAndWaitForLoadBalancing() { - auto& scheduler = kernel.GlobalScheduler(); - return scheduler.YieldThreadAndWaitForLoadBalancing(this); + bool result{}; + { + SchedulerLock lock(kernel); + result = kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this); + } + return result; } void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { const u32 old_flags = scheduling_state; scheduling_state = (scheduling_state & static_cast(ThreadSchedMasks::HighMask)) | static_cast(new_status); - AdjustSchedulingOnStatus(old_flags); + kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_flags); } void Thread::SetCurrentPriority(u32 new_priority) { const u32 old_priority = std::exchange(current_priority, new_priority); - AdjustSchedulingOnPriority(old_priority); + kernel.GlobalScheduler().AdjustSchedulingOnPriority(this, old_priority); } ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { @@ -443,111 +502,12 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { processor_id = ideal_core; } } - AdjustSchedulingOnAffinity(old_affinity_mask, old_core); + kernel.GlobalScheduler().AdjustSchedulingOnAffinity(this, old_affinity_mask, old_core); } } return RESULT_SUCCESS; } -void Thread::AdjustSchedulingOnStatus(u32 old_flags) { - if (old_flags == scheduling_state) { - return; - } - - auto& scheduler = kernel.GlobalScheduler(); - if (static_cast(old_flags & static_cast(ThreadSchedMasks::LowMask)) == - ThreadSchedStatus::Runnable) { - // In this case the thread was running, now it's pausing/exitting - if (processor_id >= 0) { - scheduler.Unschedule(current_priority, static_cast(processor_id), this); - } - - for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - if (core != static_cast(processor_id) && ((affinity_mask >> core) & 1) != 0) { - scheduler.Unsuggest(current_priority, core, this); - } - } - } else if (GetSchedulingStatus() == ThreadSchedStatus::Runnable) { - // The thread is now set to running from being stopped - if (processor_id >= 0) { - scheduler.Schedule(current_priority, static_cast(processor_id), this); - } - - for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - if (core != static_cast(processor_id) && ((affinity_mask >> core) & 1) != 0) { - scheduler.Suggest(current_priority, core, this); - } - } - } - - scheduler.SetReselectionPending(); -} - -void Thread::AdjustSchedulingOnPriority(u32 old_priority) { - if (GetSchedulingStatus() != ThreadSchedStatus::Runnable) { - return; - } - auto& scheduler = kernel.GlobalScheduler(); - if (processor_id >= 0) { - scheduler.Unschedule(old_priority, static_cast(processor_id), this); - } - - for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - if (core != static_cast(processor_id) && ((affinity_mask >> core) & 1) != 0) { - scheduler.Unsuggest(old_priority, core, this); - } - } - - // Add thread to the new priority queues. - Thread* current_thread = GetCurrentThread(); - - if (processor_id >= 0) { - if (current_thread == this) { - scheduler.SchedulePrepend(current_priority, static_cast(processor_id), this); - } else { - scheduler.Schedule(current_priority, static_cast(processor_id), this); - } - } - - for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - if (core != static_cast(processor_id) && ((affinity_mask >> core) & 1) != 0) { - scheduler.Suggest(current_priority, core, this); - } - } - - scheduler.SetReselectionPending(); -} - -void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { - auto& scheduler = kernel.GlobalScheduler(); - if (GetSchedulingStatus() != ThreadSchedStatus::Runnable || - current_priority >= THREADPRIO_COUNT) { - return; - } - - for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - if (((old_affinity_mask >> core) & 1) != 0) { - if (core == static_cast(old_core)) { - scheduler.Unschedule(current_priority, core, this); - } else { - scheduler.Unsuggest(current_priority, core, this); - } - } - } - - for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - if (((affinity_mask >> core) & 1) != 0) { - if (core == static_cast(processor_id)) { - scheduler.Schedule(current_priority, core, this); - } else { - scheduler.Suggest(current_priority, core, this); - } - } - } - - scheduler.SetReselectionPending(); -} - //////////////////////////////////////////////////////////////////////////////////////////////////// /** diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 23fdef8a4..33d340b47 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -9,23 +9,42 @@ #include #include "common/common_types.h" +#include "common/spin_lock.h" #include "core/arm/arm_interface.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/synchronization_object.h" #include "core/hle/result.h" +namespace Common { +class Fiber; +} + +namespace Core { +class System; +} + namespace Kernel { +class GlobalScheduler; class KernelCore; class Process; class Scheduler; enum ThreadPriority : u32 { - THREADPRIO_HIGHEST = 0, ///< Highest thread priority - THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps - THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps - THREADPRIO_LOWEST = 63, ///< Lowest thread priority - THREADPRIO_COUNT = 64, ///< Total number of possible thread priorities. + THREADPRIO_HIGHEST = 0, ///< Highest thread priority + THREADPRIO_MAX_CORE_MIGRATION = 2, ///< Highest priority for a core migration + THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps + THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps + THREADPRIO_LOWEST = 63, ///< Lowest thread priority + THREADPRIO_COUNT = 64, ///< Total number of possible thread priorities. +}; + +enum ThreadType : u32 { + THREADTYPE_USER = 0x1, + THREADTYPE_KERNEL = 0x2, + THREADTYPE_HLE = 0x4, + THREADTYPE_IDLE = 0x8, + THREADTYPE_SUSPEND = 0x10, }; enum ThreadProcessorId : s32 { @@ -111,22 +130,43 @@ public: std::function thread, std::shared_ptr object, std::size_t index)>; + /** + * Creates and returns a new thread. The new thread is immediately scheduled + * @param system The instance of the whole system + * @param name The friendly name desired for the thread + * @param entry_point The address at which the thread should start execution + * @param priority The thread's priority + * @param arg User data to pass to the thread + * @param processor_id The ID(s) of the processors on which the thread is desired to be run + * @param stack_top The address of the thread's stack top + * @param owner_process The parent process for the thread, if null, it's a kernel thread + * @return A shared pointer to the newly created thread + */ + static ResultVal> Create(Core::System& system, ThreadType type_flags, std::string name, + VAddr entry_point, u32 priority, u64 arg, + s32 processor_id, VAddr stack_top, + Process* owner_process); + /** * Creates and returns a new thread. The new thread is immediately scheduled - * @param kernel The kernel instance this thread will be created under. + * @param system The instance of the whole system * @param name The friendly name desired for the thread * @param entry_point The address at which the thread should start execution * @param priority The thread's priority * @param arg User data to pass to the thread * @param processor_id The ID(s) of the processors on which the thread is desired to be run * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread + * @param owner_process The parent process for the thread, if null, it's a kernel thread + * @param thread_start_func The function where the host context will start. + * @param thread_start_parameter The parameter which will passed to host context on init * @return A shared pointer to the newly created thread */ - static ResultVal> Create(KernelCore& kernel, std::string name, + static ResultVal> Create(Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority, u64 arg, s32 processor_id, VAddr stack_top, - Process& owner_process); + Process* owner_process, + std::function&& thread_start_func, + void* thread_start_parameter); std::string GetName() const override { return name; @@ -192,7 +232,9 @@ public: } /// Resumes a thread from waiting - void ResumeFromWait(); + void /* deprecated */ ResumeFromWait(); + + void OnWakeUp(); /// Cancels a waiting operation that this thread may or may not be within. /// @@ -206,10 +248,10 @@ public: * Schedules an event to wake up the specified thread after the specified delay * @param nanoseconds The time this thread will be allowed to sleep for */ - void WakeAfterDelay(s64 nanoseconds); + void /* deprecated */ WakeAfterDelay(s64 nanoseconds); /// Cancel any outstanding wakeup events for this thread - void CancelWakeupTimer(); + void /* deprecated */ CancelWakeupTimer(); /** * Sets the result after the thread awakens (from svcWaitSynchronization) @@ -290,6 +332,12 @@ public: return context_64; } + bool IsHLEThread() const { + return (type & THREADTYPE_HLE) != 0; + } + + std::shared_ptr GetHostContext() const; + ThreadStatus GetStatus() const { return status; } @@ -467,16 +515,19 @@ public: } private: + friend class GlobalScheduler; + friend class Scheduler; + void SetSchedulingStatus(ThreadSchedStatus new_status); void SetCurrentPriority(u32 new_priority); ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); - void AdjustSchedulingOnStatus(u32 old_flags); - void AdjustSchedulingOnPriority(u32 old_priority); void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); ThreadContext32 context_32{}; ThreadContext64 context_64{}; + Common::SpinLock context_guard{}; + std::shared_ptr host_context{}; u64 thread_id = 0; @@ -485,6 +536,8 @@ private: VAddr entry_point = 0; VAddr stack_top = 0; + ThreadType type; + /// Nominal thread priority, as set by the emulated application. /// The nominal priority is the thread priority without priority /// inheritance taken into account. diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 21b290468..0b8f0d993 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -19,7 +19,7 @@ TimeManager::TimeManager(Core::System& system) : system{system} { Handle proper_handle = static_cast(thread_handle); std::shared_ptr thread = this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); - thread->ResumeFromWait(); + thread->OnWakeUp(); }); } -- cgit v1.2.3 From 49ba56399563a87f29b4d89eb04b1178a571eb61 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 12:40:33 -0400 Subject: SVC: Correct CreateThread, StartThread, ExitThread, SleepThread. --- src/core/hle/kernel/svc.cpp | 18 +++++------------- src/core/hle/kernel/thread.cpp | 38 ++++++++++++++++++-------------------- src/core/hle/kernel/thread.h | 12 ++++++++---- 3 files changed, 31 insertions(+), 37 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index d7f0dcabd..dfb032b4b 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1464,13 +1464,7 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { ASSERT(thread->GetStatus() == ThreadStatus::Dormant); - thread->ResumeFromWait(); - - if (thread->GetStatus() == ThreadStatus::Ready) { - system.PrepareReschedule(thread->GetProcessorID()); - } - - return RESULT_SUCCESS; + return thread->Start(); } /// Called when a thread exits @@ -1478,9 +1472,8 @@ static void ExitThread(Core::System& system) { LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); - current_thread->Stop(); system.GlobalScheduler().RemoveThread(SharedFrom(current_thread)); - system.PrepareReschedule(); + current_thread->Stop(); } /// Sleep the current thread @@ -1500,13 +1493,13 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { if (nanoseconds <= 0) { switch (static_cast(nanoseconds)) { case SleepType::YieldWithoutLoadBalancing: - is_redundant = current_thread->YieldSimple(); + current_thread->YieldSimple(); break; case SleepType::YieldWithLoadBalancing: - is_redundant = current_thread->YieldAndBalanceLoad(); + current_thread->YieldAndBalanceLoad(); break; case SleepType::YieldAndWaitForLoadBalancing: - is_redundant = current_thread->YieldAndWaitForLoadBalancing(); + current_thread->YieldAndWaitForLoadBalancing(); break; default: UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); @@ -1514,7 +1507,6 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { } else { current_thread->Sleep(nanoseconds); } - system.PrepareReschedule(current_thread->GetProcessorID()); } /// Wait process wide key atomic diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 8cb3593db..d9e610272 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -56,12 +56,6 @@ void Thread::Stop() { SetStatus(ThreadStatus::Dead); Signal(); - // Clean up any dangling references in objects that this thread was waiting for - for (auto& wait_object : wait_objects) { - wait_object->RemoveWaitingThread(SharedFrom(this)); - } - wait_objects.clear(); - owner_process->UnregisterThread(this); // Mark the TLS slot in the thread's page as free. @@ -138,6 +132,12 @@ void Thread::OnWakeUp() { SetStatus(ThreadStatus::Ready); } +ResultCode Thread::Start() { + SchedulerLock lock(kernel); + SetStatus(ThreadStatus::Ready); + return RESULT_SUCCESS; +} + void Thread::CancelWait() { if (GetSchedulingStatus() != ThreadSchedStatus::Paused) { is_sync_cancelled = true; @@ -188,7 +188,7 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy void* thread_start_parameter) { auto& kernel = system.Kernel(); // Check if priority is in ranged. Lowest priority -> highest priority id. - if (priority > THREADPRIO_LOWEST && (type_flags & THREADTYPE_IDLE == 0)) { + if (priority > THREADPRIO_LOWEST && ((type_flags & THREADTYPE_IDLE) == 0)) { LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); return ERR_INVALID_THREAD_PRIORITY; } @@ -416,7 +416,7 @@ void Thread::SetActivity(ThreadActivity value) { } } -void Thread::Sleep(s64 nanoseconds) { +ResultCode Thread::Sleep(s64 nanoseconds) { Handle event_handle{}; { SchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); @@ -427,33 +427,31 @@ void Thread::Sleep(s64 nanoseconds) { auto& time_manager = kernel.TimeManager(); time_manager.UnscheduleTimeEvent(event_handle); } + return RESULT_SUCCESS; } -bool Thread::YieldSimple() { - bool result{}; +ResultCode Thread::YieldSimple() { { SchedulerLock lock(kernel); - result = kernel.GlobalScheduler().YieldThread(this); + kernel.GlobalScheduler().YieldThread(this); } - return result; + return RESULT_SUCCESS; } -bool Thread::YieldAndBalanceLoad() { - bool result{}; +ResultCode Thread::YieldAndBalanceLoad() { { SchedulerLock lock(kernel); - result = kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this); + kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this); } - return result; + return RESULT_SUCCESS; } -bool Thread::YieldAndWaitForLoadBalancing() { - bool result{}; +ResultCode Thread::YieldAndWaitForLoadBalancing() { { SchedulerLock lock(kernel); - result = kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this); + kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this); } - return result; + return RESULT_SUCCESS; } void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 33d340b47..78a4357b0 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -236,6 +236,8 @@ public: void OnWakeUp(); + ResultCode Start(); + /// Cancels a waiting operation that this thread may or may not be within. /// /// When the thread is within a waiting state, this will set the thread's @@ -470,16 +472,16 @@ public: void SetActivity(ThreadActivity value); /// Sleeps this thread for the given amount of nanoseconds. - void Sleep(s64 nanoseconds); + ResultCode Sleep(s64 nanoseconds); /// Yields this thread without rebalancing loads. - bool YieldSimple(); + ResultCode YieldSimple(); /// Yields this thread and does a load rebalancing. - bool YieldAndBalanceLoad(); + ResultCode YieldAndBalanceLoad(); /// Yields this thread and if the core is left idle, loads are rebalanced - bool YieldAndWaitForLoadBalancing(); + ResultCode YieldAndWaitForLoadBalancing(); void IncrementYieldCount() { yield_count++; @@ -603,6 +605,8 @@ private: bool is_running = false; bool is_sync_cancelled = false; + bool will_be_terminated{}; + std::string name; }; -- cgit v1.2.3 From 589f9cf108d306e8265ff4856b522cd32fbc121f Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 13:22:11 -0400 Subject: SVC: Correct GetThreadPriority, SetThreadPriority, GetThreadCoreMask, SetThreadCoreMask, GetCurrentProcessorNumber --- src/core/hle/kernel/svc.cpp | 17 ++++++++--------- src/core/hle/kernel/thread.cpp | 6 ++---- src/core/hle/kernel/thread.h | 3 +-- 3 files changed, 11 insertions(+), 15 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index dfb032b4b..2a218e294 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -27,6 +27,7 @@ #include "core/hle/kernel/memory/memory_block.h" #include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/mutex.h" +#include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/resource_limit.h" @@ -1071,6 +1072,7 @@ static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const std::shared_ptr thread = handle_table.Get(handle); if (!thread) { + *priority = 0; LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; } @@ -1105,14 +1107,13 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri thread->SetPriority(priority); - system.PrepareReschedule(thread->GetProcessorID()); return RESULT_SUCCESS; } /// Get which CPU core is executing the current thread static u32 GetCurrentProcessorNumber(Core::System& system) { LOG_TRACE(Kernel_SVC, "called"); - return system.CurrentScheduler().GetCurrentThread()->GetProcessorID(); + return static_cast(system.CurrentPhysicalCore().CoreIndex()); } static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, @@ -1430,8 +1431,8 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e ThreadType type = THREADTYPE_USER; CASCADE_RESULT(std::shared_ptr thread, - Thread::Create(system, type, "", entry_point, priority, arg, processor_id, stack_top, - current_process)); + Thread::Create(system, type, "", entry_point, priority, arg, processor_id, + stack_top, current_process)); const auto new_thread_handle = current_process->GetHandleTable().Create(thread); if (new_thread_handle.Failed()) { @@ -1804,6 +1805,8 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); + *core = 0; + *mask = 0; return ERR_INVALID_HANDLE; } @@ -1866,11 +1869,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, return ERR_INVALID_HANDLE; } - system.PrepareReschedule(thread->GetProcessorID()); - thread->ChangeCore(core, affinity_mask); - system.PrepareReschedule(thread->GetProcessorID()); - - return RESULT_SUCCESS; + return thread->SetCoreAndAffinityMask(core, affinity_mask); } static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d9e610272..e6bb7c666 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -250,6 +250,7 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy } void Thread::SetPriority(u32 priority) { + SchedulerLock lock(kernel); ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, "Invalid priority value."); nominal_priority = priority; @@ -383,10 +384,6 @@ void Thread::UpdatePriority() { lock_owner->UpdatePriority(); } -void Thread::ChangeCore(u32 core, u64 mask) { - SetCoreAndAffinityMask(core, mask); -} - bool Thread::AllSynchronizationObjectsReady() const { return std::none_of(wait_objects.begin(), wait_objects.end(), [this](const std::shared_ptr& object) { @@ -467,6 +464,7 @@ void Thread::SetCurrentPriority(u32 new_priority) { } ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { + SchedulerLock lock(kernel); const auto HighestSetCore = [](u64 mask, u32 max_cores) { for (s32 core = static_cast(max_cores - 1); core >= 0; core--) { if (((mask >> core) & 1) != 0) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 78a4357b0..29fe5483b 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -221,7 +221,7 @@ public: void UpdatePriority(); /// Changes the core that the thread is running or scheduled to run on. - void ChangeCore(u32 core, u64 mask); + ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); /** * Gets the thread's thread ID @@ -522,7 +522,6 @@ private: void SetSchedulingStatus(ThreadSchedStatus new_status); void SetCurrentPriority(u32 new_priority); - ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); -- cgit v1.2.3 From ef4afa9760f07bc218256cdb044529ad3a7c08b5 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 13:24:29 -0400 Subject: SVC: Remove global HLE Lock. --- src/core/hle/kernel/svc.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 2a218e294..a071b0c09 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2410,9 +2410,6 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); void Call(Core::System& system, u32 immediate) { MICROPROFILE_SCOPE(Kernel_SVC); - // Lock the global kernel mutex when we enter the kernel HLE. - std::lock_guard lock{HLE::g_hle_lock}; - const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); if (info) { -- cgit v1.2.3 From 3b5b950c895a2db217a3e5c8105cec4498a2534e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 16:38:33 -0400 Subject: SVC: Correct SignalEvent, ClearEvent, ResetSignal, WaitSynchronization, CancelSynchronization, ArbitrateLock --- src/core/hle/kernel/mutex.cpp | 65 +++++++++------ src/core/hle/kernel/process.cpp | 1 + src/core/hle/kernel/readable_event.cpp | 3 + src/core/hle/kernel/svc.cpp | 1 - src/core/hle/kernel/synchronization.cpp | 118 +++++++++++++++------------ src/core/hle/kernel/synchronization_object.h | 5 +- src/core/hle/kernel/thread.cpp | 14 ++-- src/core/hle/kernel/thread.h | 17 +++- 8 files changed, 134 insertions(+), 90 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 7869eb32b..3520c5e49 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -72,42 +72,55 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, return ERR_INVALID_ADDRESS; } - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + auto& kernel = system.Kernel(); std::shared_ptr current_thread = - SharedFrom(system.CurrentScheduler().GetCurrentThread()); - std::shared_ptr holding_thread = handle_table.Get(holding_thread_handle); - std::shared_ptr requesting_thread = handle_table.Get(requesting_thread_handle); + SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); + { + SchedulerLock lock(kernel); + // The mutex address must be 4-byte aligned + if ((address % sizeof(u32)) != 0) { + return ERR_INVALID_ADDRESS; + } - // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another - // thread. - ASSERT(requesting_thread == current_thread); + const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + std::shared_ptr holding_thread = handle_table.Get(holding_thread_handle); + std::shared_ptr requesting_thread = handle_table.Get(requesting_thread_handle); - const u32 addr_value = system.Memory().Read32(address); + // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another + // thread. + ASSERT(requesting_thread == current_thread); - // If the mutex isn't being held, just return success. - if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { - return RESULT_SUCCESS; - } + current_thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); - if (holding_thread == nullptr) { - LOG_ERROR(Kernel, "Holding thread does not exist! thread_handle={:08X}", - holding_thread_handle); - return ERR_INVALID_HANDLE; - } + const u32 addr_value = system.Memory().Read32(address); - // Wait until the mutex is released - current_thread->SetMutexWaitAddress(address); - current_thread->SetWaitHandle(requesting_thread_handle); + // If the mutex isn't being held, just return success. + if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { + return RESULT_SUCCESS; + } - current_thread->SetStatus(ThreadStatus::WaitMutex); - current_thread->InvalidateWakeupCallback(); + if (holding_thread == nullptr) { + return ERR_INVALID_HANDLE; + } - // Update the lock holder thread's priority to prevent priority inversion. - holding_thread->AddMutexWaiter(current_thread); + // Wait until the mutex is released + current_thread->SetMutexWaitAddress(address); + current_thread->SetWaitHandle(requesting_thread_handle); - system.PrepareReschedule(); + current_thread->SetStatus(ThreadStatus::WaitMutex); - return RESULT_SUCCESS; + // Update the lock holder thread's priority to prevent priority inversion. + holding_thread->AddMutexWaiter(current_thread); + } + + { + SchedulerLock lock(kernel); + auto* owner = current_thread->GetLockOwner(); + if (owner != nullptr) { + owner->RemoveMutexWaiter(current_thread); + } + } + return current_thread->GetSignalingResult(); } ResultCode Mutex::Release(VAddr address) { diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 7e26a54f4..cd4b0aa60 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -212,6 +212,7 @@ void Process::UnregisterThread(const Thread* thread) { } ResultCode Process::ClearSignalState() { + SchedulerLock lock(system.Kernel()); if (status == ProcessStatus::Exited) { LOG_ERROR(Kernel, "called on a terminated process instance."); return ERR_INVALID_STATE; diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index ef5e19e63..6e286419e 100644 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp @@ -6,8 +6,10 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/hle/kernel/errors.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" namespace Kernel { @@ -37,6 +39,7 @@ void ReadableEvent::Clear() { } ResultCode ReadableEvent::Reset() { + SchedulerLock lock(kernel); if (!is_signaled) { LOG_TRACE(Kernel, "Handle is not signaled! object_id={}, object_type={}, object_name={}", GetObjectId(), GetTypeName(), GetName()); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index a071b0c09..0d905c0ca 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -448,7 +448,6 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand } thread->CancelWait(); - system.PrepareReschedule(thread->GetProcessorID()); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index dc37fad1a..b36e550a0 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -10,78 +10,88 @@ #include "core/hle/kernel/synchronization.h" #include "core/hle/kernel/synchronization_object.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/time_manager.h" namespace Kernel { -/// Default thread wakeup callback for WaitSynchronization -static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, - std::size_t index) { - ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); - - if (reason == ThreadWakeupReason::Timeout) { - thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); - return true; - } - - ASSERT(reason == ThreadWakeupReason::Signal); - thread->SetWaitSynchronizationResult(RESULT_SUCCESS); - thread->SetWaitSynchronizationOutput(static_cast(index)); - return true; -} - Synchronization::Synchronization(Core::System& system) : system{system} {} void Synchronization::SignalObject(SynchronizationObject& obj) const { + SchedulerLock lock(system.Kernel()); if (obj.IsSignaled()) { - obj.WakeupAllWaitingThreads(); + for (auto thread : obj.GetWaitingThreads()) { + if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { + thread->SetSynchronizationResults(&obj, RESULT_SUCCESS); + thread->ResumeFromWait(); + } + } } } std::pair Synchronization::WaitFor( std::vector>& sync_objects, s64 nano_seconds) { + auto& kernel = system.Kernel(); auto* const thread = system.CurrentScheduler().GetCurrentThread(); - // Find the first object that is acquirable in the provided list of objects - const auto itr = std::find_if(sync_objects.begin(), sync_objects.end(), - [thread](const std::shared_ptr& object) { - return object->IsSignaled(); - }); - - if (itr != sync_objects.end()) { - // We found a ready object, acquire it and set the result value - SynchronizationObject* object = itr->get(); - object->Acquire(thread); - const u32 index = static_cast(std::distance(sync_objects.begin(), itr)); - return {RESULT_SUCCESS, index}; + Handle event_handle = InvalidHandle; + { + SchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds); + const auto itr = + std::find_if(sync_objects.begin(), sync_objects.end(), + [thread](const std::shared_ptr& object) { + return object->IsSignaled(); + }); + + if (itr != sync_objects.end()) { + // We found a ready object, acquire it and set the result value + SynchronizationObject* object = itr->get(); + object->Acquire(thread); + const u32 index = static_cast(std::distance(sync_objects.begin(), itr)); + lock.CancelSleep(); + return {RESULT_SUCCESS, index}; + } + + if (nano_seconds == 0) { + lock.CancelSleep(); + return {RESULT_TIMEOUT, InvalidHandle}; + } + + /// TODO(Blinkhawk): Check for termination pending + + if (thread->IsSyncCancelled()) { + thread->SetSyncCancelled(false); + lock.CancelSleep(); + return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle}; + } + + for (auto& object : sync_objects) { + object->AddWaitingThread(SharedFrom(thread)); + } + thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + thread->SetStatus(ThreadStatus::WaitSynch); } - // No objects were ready to be acquired, prepare to suspend the thread. - - // If a timeout value of 0 was provided, just return the Timeout error code instead of - // suspending the thread. - if (nano_seconds == 0) { - return {RESULT_TIMEOUT, InvalidHandle}; + if (event_handle != InvalidHandle) { + auto& time_manager = kernel.TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); } - if (thread->IsSyncCancelled()) { - thread->SetSyncCancelled(false); - return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle}; + { + SchedulerLock lock(kernel); + ResultCode signaling_result = thread->GetSignalingResult(); + SynchronizationObject* signaling_object = thread->GetSignalingObject(); + if (signaling_result == RESULT_SUCCESS) { + const auto itr = std::find_if( + sync_objects.begin(), sync_objects.end(), + [signaling_object](const std::shared_ptr& object) { + return object.get() == signaling_object; + }); + ASSERT(itr != sync_objects.end()); + signaling_object->Acquire(thread); + const u32 index = static_cast(std::distance(sync_objects.begin(), itr)); + return {RESULT_SUCCESS, index}; + } + return {signaling_result, -1}; } - - for (auto& object : sync_objects) { - object->AddWaitingThread(SharedFrom(thread)); - } - - thread->SetSynchronizationObjects(std::move(sync_objects)); - thread->SetStatus(ThreadStatus::WaitSynch); - - // Create an event to wake the thread up after the specified nanosecond delay has passed - thread->WakeAfterDelay(nano_seconds); - thread->SetWakeupCallback(DefaultThreadWakeupCallback); - - system.PrepareReschedule(thread->GetProcessorID()); - - return {RESULT_TIMEOUT, InvalidHandle}; } } // namespace Kernel diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h index 741c31faf..0a0d069e0 100644 --- a/src/core/hle/kernel/synchronization_object.h +++ b/src/core/hle/kernel/synchronization_object.h @@ -12,6 +12,7 @@ namespace Kernel { class KernelCore; +class Synchronization; class Thread; /// Class that represents a Kernel object that a thread can be waiting on @@ -53,7 +54,7 @@ public: * Wake up all threads waiting on this object that can be awoken, in priority order, * and set the synchronization result and output of the thread. */ - void WakeupAllWaitingThreads(); + void /* deprecated */ WakeupAllWaitingThreads(); /** * Wakes up a single thread waiting on this object. @@ -62,7 +63,7 @@ public: void WakeupWaitingThread(std::shared_ptr thread); /// Obtains the highest priority thread that is ready to run from this object's waiting list. - std::shared_ptr GetHighestPriorityReadyThread() const; + std::shared_ptr /* deprecated */ GetHighestPriorityReadyThread() const; /// Get a const reference to the waiting threads list for debug use const std::vector>& GetWaitingThreads() const; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index e6bb7c666..5fef3945b 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -139,12 +139,13 @@ ResultCode Thread::Start() { } void Thread::CancelWait() { + SchedulerLock lock(kernel); if (GetSchedulingStatus() != ThreadSchedStatus::Paused) { is_sync_cancelled = true; return; } is_sync_cancelled = false; - SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); + SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); ResumeFromWait(); } @@ -258,13 +259,16 @@ void Thread::SetPriority(u32 priority) { } void Thread::SetWaitSynchronizationResult(ResultCode result) { - context_32.cpu_registers[0] = result.raw; - context_64.cpu_registers[0] = result.raw; + UNREACHABLE(); } void Thread::SetWaitSynchronizationOutput(s32 output) { - context_32.cpu_registers[1] = output; - context_64.cpu_registers[1] = output; + UNREACHABLE(); +} + +void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode result) { + signaling_object = object; + signaling_result = result; } s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr object) const { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 29fe5483b..a8ae1a66f 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -259,13 +259,23 @@ public: * Sets the result after the thread awakens (from svcWaitSynchronization) * @param result Value to set to the returned result */ - void SetWaitSynchronizationResult(ResultCode result); + void /*deprecated*/ SetWaitSynchronizationResult(ResultCode result); /** * Sets the output parameter value after the thread awakens (from svcWaitSynchronization) * @param output Value to set to the output parameter */ - void SetWaitSynchronizationOutput(s32 output); + void /*deprecated*/ SetWaitSynchronizationOutput(s32 output); + + void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); + + SynchronizationObject* GetSignalingObject() const { + return signaling_object; + } + + ResultCode GetSignalingResult() const { + return signaling_result; + } /** * Retrieves the index that this particular object occupies in the list of objects @@ -565,6 +575,9 @@ private: /// passed to WaitSynchronization. ThreadSynchronizationObjects wait_objects; + SynchronizationObject* signaling_object; + ResultCode signaling_result{RESULT_SUCCESS}; + /// List of threads that are waiting for a mutex that is held by this thread. MutexWaitingThreads wait_mutex_threads; -- cgit v1.2.3 From 203e706302c24f278eec7d0bd2362ce73b0e2612 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 17:37:12 -0400 Subject: SVC: Correct ArbitrateUnlock --- src/core/hle/kernel/mutex.cpp | 65 +++++++++++++++++++++--------------------- src/core/hle/kernel/mutex.h | 3 ++ src/core/hle/kernel/thread.cpp | 2 +- 3 files changed, 37 insertions(+), 33 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 3520c5e49..18325db57 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -84,10 +84,11 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); std::shared_ptr holding_thread = handle_table.Get(holding_thread_handle); - std::shared_ptr requesting_thread = handle_table.Get(requesting_thread_handle); + std::shared_ptr requesting_thread = + handle_table.Get(requesting_thread_handle); - // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another - // thread. + // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of + // another thread. ASSERT(requesting_thread == current_thread); current_thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); @@ -123,47 +124,47 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, return current_thread->GetSignalingResult(); } -ResultCode Mutex::Release(VAddr address) { - // The mutex address must be 4-byte aligned - if ((address % sizeof(u32)) != 0) { - LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); - return ERR_INVALID_ADDRESS; - } - - std::shared_ptr current_thread = - SharedFrom(system.CurrentScheduler().GetCurrentThread()); - auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(current_thread, address); +std::pair> Mutex::Unlock(std::shared_ptr owner, + VAddr address) { + // The mutex address must be 4-byte aligned + if ((address % sizeof(u32)) != 0) { + LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); + return {ERR_INVALID_ADDRESS, nullptr}; + } - // There are no more threads waiting for the mutex, release it completely. - if (thread == nullptr) { + auto [new_owner, num_waiters] = GetHighestPriorityMutexWaitingThread(owner, address); + if (new_owner == nullptr) { system.Memory().Write32(address, 0); - return RESULT_SUCCESS; + return {RESULT_SUCCESS, nullptr}; } - // Transfer the ownership of the mutex from the previous owner to the new one. - TransferMutexOwnership(address, current_thread, thread); - - u32 mutex_value = thread->GetWaitHandle(); - + TransferMutexOwnership(address, owner, new_owner); + u32 mutex_value = new_owner->GetWaitHandle(); if (num_waiters >= 2) { // Notify the guest that there are still some threads waiting for the mutex mutex_value |= Mutex::MutexHasWaitersFlag; } - - // Grant the mutex to the next waiting thread and resume it. + new_owner->SetSynchronizationResults(nullptr, RESULT_SUCCESS); + new_owner->ResumeFromWait(); + new_owner->SetLockOwner(nullptr); system.Memory().Write32(address, mutex_value); + return {RESULT_SUCCESS, new_owner}; +} + +ResultCode Mutex::Release(VAddr address) { + auto& kernel = system.Kernel(); + SchedulerLock lock(kernel); - ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); - thread->ResumeFromWait(); + std::shared_ptr current_thread = + SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); - thread->SetLockOwner(nullptr); - thread->SetCondVarWaitAddress(0); - thread->SetMutexWaitAddress(0); - thread->SetWaitHandle(0); - thread->SetWaitSynchronizationResult(RESULT_SUCCESS); + auto [result, new_owner] = Unlock(current_thread, address); - system.PrepareReschedule(); + if (result != RESULT_SUCCESS && new_owner != nullptr) { + new_owner->SetSynchronizationResults(nullptr, result); + } - return RESULT_SUCCESS; + return result; } + } // namespace Kernel diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index b904de2e8..bce06ecea 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -28,6 +28,9 @@ public: ResultCode TryAcquire(VAddr address, Handle holding_thread_handle, Handle requesting_thread_handle); + /// Unlocks a mutex for owner at address + std::pair> Unlock(std::shared_ptr owner, VAddr address); + /// Releases the mutex at the specified address. ResultCode Release(VAddr address); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 5fef3945b..f100ffc70 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -80,7 +80,7 @@ void Thread::CancelWakeupTimer() { void Thread::ResumeFromWait() { ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); - + SchedulerLock lock(kernel); switch (status) { case ThreadStatus::Paused: case ThreadStatus::WaitSynch: -- cgit v1.2.3 From 15a79eb0d7abe752a9a55d0cfa7ea220e17318b7 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 19:43:28 -0400 Subject: SVC: Correct SendSyncRequest. --- src/core/hle/kernel/hle_ipc.cpp | 24 +++++----- src/core/hle/kernel/scheduler.cpp | 9 ++++ src/core/hle/kernel/scheduler.h | 2 + src/core/hle/kernel/server_session.cpp | 15 ++++--- src/core/hle/kernel/svc.cpp | 21 +++++++-- src/core/hle/kernel/thread.cpp | 14 ++++-- src/core/hle/kernel/thread.h | 82 ++++++++++++++++++++++------------ 7 files changed, 115 insertions(+), 52 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 0d01a7047..955d5fe1c 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -14,6 +14,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/kernel.h" @@ -21,7 +22,9 @@ #include "core/hle/kernel/process.h" #include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/time_manager.h" #include "core/hle/kernel/writable_event.h" #include "core/memory.h" @@ -46,11 +49,10 @@ std::shared_ptr HLERequestContext::SleepClientThread( const std::string& reason, u64 timeout, WakeupCallback&& callback, std::shared_ptr writable_event) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->SetWakeupCallback( + thread->SetHLECallback( [context = *this, callback](ThreadWakeupReason reason, std::shared_ptr thread, std::shared_ptr object, std::size_t index) mutable -> bool { - ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent); callback(thread, context, reason); context.WriteToOutgoingCommandBuffer(*thread); return true; @@ -62,14 +64,16 @@ std::shared_ptr HLERequestContext::SleepClientThread( writable_event = pair.writable; } - const auto readable_event{writable_event->GetReadableEvent()}; - writable_event->Clear(); - thread->SetStatus(ThreadStatus::WaitHLEEvent); - thread->SetSynchronizationObjects({readable_event}); - readable_event->AddWaitingThread(thread); - - if (timeout > 0) { - thread->WakeAfterDelay(timeout); + { + Handle event_handle = InvalidHandle; + SchedulerLockAndSleep lock(kernel, event_handle, thread.get(), timeout); + const auto readable_event{writable_event->GetReadableEvent()}; + writable_event->Clear(); + thread->SetStatus(ThreadStatus::WaitHLEEvent); + thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + readable_event->AddWaitingThread(thread); + lock.Release(); + thread->SetHLETimeEvent(event_handle); } is_thread_waiting = true; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 5166020a0..0e85ee69e 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -715,4 +715,13 @@ SchedulerLockAndSleep::~SchedulerLockAndSleep() { time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds); } +void SchedulerLockAndSleep::Release() { + if (sleep_cancelled) { + return; + } + auto& time_manager = kernel.TimeManager(); + time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds); + sleep_cancelled = true; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 16655b03f..f5f64338f 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -279,6 +279,8 @@ public: sleep_cancelled = true; } + void Release(); + private: Handle& event_handle; Thread* time_task; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 25438b86b..05516a453 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -19,6 +19,7 @@ #include "core/hle/kernel/process.h" #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" #include "core/memory.h" @@ -168,9 +169,12 @@ ResultCode ServerSession::CompleteSyncRequest() { } // Some service requests require the thread to block - if (!context.IsThreadWaiting()) { - context.GetThread().ResumeFromWait(); - context.GetThread().SetWaitSynchronizationResult(result); + { + SchedulerLock lock(kernel); + if (!context.IsThreadWaiting()) { + context.GetThread().ResumeFromWait(); + context.GetThread().SetSynchronizationResults(nullptr, result); + } } request_queue.Pop(); @@ -180,8 +184,9 @@ ResultCode ServerSession::CompleteSyncRequest() { ResultCode ServerSession::HandleSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory) { - Core::System::GetInstance().CoreTiming().ScheduleEvent(20000, request_event, {}); - return QueueSyncRequest(std::move(thread), memory); + ResultCode result = QueueSyncRequest(std::move(thread), memory); + Core::System::GetInstance().CoreTiming().ScheduleEvent(0, request_event, {}); + return result; } } // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 0d905c0ca..768d72b92 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -38,6 +38,7 @@ #include "core/hle/kernel/svc_wrap.h" #include "core/hle/kernel/synchronization.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/time_manager.h" #include "core/hle/kernel/transfer_memory.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/lock.h" @@ -318,11 +319,23 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); auto thread = system.CurrentScheduler().GetCurrentThread(); - thread->InvalidateWakeupCallback(); - thread->SetStatus(ThreadStatus::WaitIPC); - system.PrepareReschedule(thread->GetProcessorID()); + { + SchedulerLock lock(system.Kernel()); + thread->InvalidateHLECallback(); + thread->SetStatus(ThreadStatus::WaitIPC); + session->SendSyncRequest(SharedFrom(thread), system.Memory()); + } + ResultCode result = thread->GetSignalingResult(); + if (thread->HasHLECallback()) { + Handle event_handle = thread->GetHLETimeEvent(); + if (event_handle != InvalidHandle) { + auto& time_manager = system.Kernel().TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); + } + thread->InvokeHLECallback(ThreadWakeupReason::Timeout, SharedFrom(thread), nullptr, 0); + } - return session->SendSyncRequest(SharedFrom(thread), system.Memory()); + return result; } static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index f100ffc70..fb97535a3 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -96,7 +96,7 @@ void Thread::ResumeFromWait() { case ThreadStatus::Ready: // The thread's wakeup callback must have already been cleared when the thread was first // awoken. - ASSERT(wakeup_callback == nullptr); + ASSERT(hle_callback == nullptr); // If the thread is waiting on multiple wait objects, it might be awoken more than once // before actually resuming. We can ignore subsequent wakeups if the thread status has // already been set to ThreadStatus::Ready. @@ -112,7 +112,7 @@ void Thread::ResumeFromWait() { return; } - wakeup_callback = nullptr; + hle_callback = nullptr; if (activity == ThreadActivity::Paused) { SetStatus(ThreadStatus::Paused); @@ -398,8 +398,14 @@ bool Thread::AllSynchronizationObjectsReady() const { bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, std::shared_ptr object, std::size_t index) { - ASSERT(wakeup_callback); - return wakeup_callback(reason, std::move(thread), std::move(object), index); + ASSERT(hle_callback); + return hle_callback(reason, std::move(thread), std::move(object), index); +} + +bool Thread::InvokeHLECallback(ThreadWakeupReason reason, std::shared_ptr thread, + std::shared_ptr object, std::size_t index) { + ASSERT(hle_callback); + return hle_callback(reason, std::move(thread), std::move(object), index); } void Thread::SetActivity(ThreadActivity value) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index a8ae1a66f..04496f96e 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -31,12 +31,12 @@ class Process; class Scheduler; enum ThreadPriority : u32 { - THREADPRIO_HIGHEST = 0, ///< Highest thread priority - THREADPRIO_MAX_CORE_MIGRATION = 2, ///< Highest priority for a core migration - THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps - THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps - THREADPRIO_LOWEST = 63, ///< Lowest thread priority - THREADPRIO_COUNT = 64, ///< Total number of possible thread priorities. + THREADPRIO_HIGHEST = 0, ///< Highest thread priority + THREADPRIO_MAX_CORE_MIGRATION = 2, ///< Highest priority for a core migration + THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps + THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps + THREADPRIO_LOWEST = 63, ///< Lowest thread priority + THREADPRIO_COUNT = 64, ///< Total number of possible thread priorities. }; enum ThreadType : u32 { @@ -129,23 +129,24 @@ public: using WakeupCallback = std::function thread, std::shared_ptr object, std::size_t index)>; + using HLECallback = std::function thread)>; - /** - * Creates and returns a new thread. The new thread is immediately scheduled - * @param system The instance of the whole system - * @param name The friendly name desired for the thread - * @param entry_point The address at which the thread should start execution - * @param priority The thread's priority - * @param arg User data to pass to the thread - * @param processor_id The ID(s) of the processors on which the thread is desired to be run - * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread, if null, it's a kernel thread - * @return A shared pointer to the newly created thread - */ - static ResultVal> Create(Core::System& system, ThreadType type_flags, std::string name, - VAddr entry_point, u32 priority, u64 arg, - s32 processor_id, VAddr stack_top, - Process* owner_process); + /** + * Creates and returns a new thread. The new thread is immediately scheduled + * @param system The instance of the whole system + * @param name The friendly name desired for the thread + * @param entry_point The address at which the thread should start execution + * @param priority The thread's priority + * @param arg User data to pass to the thread + * @param processor_id The ID(s) of the processors on which the thread is desired to be run + * @param stack_top The address of the thread's stack top + * @param owner_process The parent process for the thread, if null, it's a kernel thread + * @return A shared pointer to the newly created thread + */ + static ResultVal> Create(Core::System& system, ThreadType type_flags, + std::string name, VAddr entry_point, + u32 priority, u64 arg, s32 processor_id, + VAddr stack_top, Process* owner_process); /** * Creates and returns a new thread. The new thread is immediately scheduled @@ -161,10 +162,10 @@ public: * @param thread_start_parameter The parameter which will passed to host context on init * @return A shared pointer to the newly created thread */ - static ResultVal> Create(Core::System& system, ThreadType type_flags, std::string name, - VAddr entry_point, u32 priority, u64 arg, - s32 processor_id, VAddr stack_top, - Process* owner_process, + static ResultVal> Create(Core::System& system, ThreadType type_flags, + std::string name, VAddr entry_point, + u32 priority, u64 arg, s32 processor_id, + VAddr stack_top, Process* owner_process, std::function&& thread_start_func, void* thread_start_parameter); @@ -447,17 +448,37 @@ public: } bool HasWakeupCallback() const { - return wakeup_callback != nullptr; + return hle_callback != nullptr; + } + + bool HasHLECallback() const { + return hle_callback != nullptr; } void SetWakeupCallback(WakeupCallback callback) { - wakeup_callback = std::move(callback); + hle_callback = std::move(callback); + } + + void SetHLECallback(WakeupCallback callback) { + hle_callback = std::move(callback); + } + + void SetHLETimeEvent(Handle time_event) { + hle_time_event = time_event; + } + + Handle GetHLETimeEvent() const { + return hle_time_event; } void InvalidateWakeupCallback() { SetWakeupCallback(nullptr); } + void InvalidateHLECallback() { + SetHLECallback(nullptr); + } + /** * Invokes the thread's wakeup callback. * @@ -466,6 +487,8 @@ public: */ bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, std::shared_ptr object, std::size_t index); + bool InvokeHLECallback(ThreadWakeupReason reason, std::shared_ptr thread, + std::shared_ptr object, std::size_t index); u32 GetIdealCore() const { return ideal_core; @@ -600,7 +623,8 @@ private: /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread /// was waiting via WaitSynchronization then the object will be the last object that became /// available. In case of a timeout, the object will be nullptr. - WakeupCallback wakeup_callback; + WakeupCallback hle_callback; + Handle hle_time_event; Scheduler* scheduler = nullptr; -- cgit v1.2.3 From 3d9fbb8226e9bf7dce99568f6e616e7361d43c41 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 26 Feb 2020 10:44:21 -0400 Subject: CPU_Manager: Reconfigre guest threads for dynamrmic downsides --- src/core/hle/kernel/physical_core.cpp | 3 +++ src/core/hle/kernel/physical_core.h | 2 ++ 2 files changed, 5 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 69202540b..ff14fcb42 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -45,6 +45,9 @@ PhysicalCore::~PhysicalCore() = default; void PhysicalCore::Run() { arm_interface->Run(); +} + +void PhysicalCore::ClearExclusive() { arm_interface->ClearExclusiveState(); } diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index c3da30b72..cd2e42fc3 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -38,6 +38,8 @@ public: /// Execute current jit state void Run(); + /// Clear Exclusive state. + void ClearExclusive(); /// Set this core in IdleState. void Idle(); /// Execute a single instruction in current jit. -- cgit v1.2.3 From 5b6a67f849d0d78d6f71ccb7d93f48a97760a901 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 26 Feb 2020 18:55:11 -0400 Subject: SVC: Cleanup old methods. --- src/core/hle/kernel/svc.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 768d72b92..8634d3feb 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -622,7 +622,6 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { // Kill the current thread current_thread->Stop(); - system.PrepareReschedule(); } } @@ -1004,6 +1003,7 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size /// Sets the thread activity static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); + UNIMPLEMENTED(); if (activity > static_cast(ThreadActivity::Paused)) { return ERR_INVALID_ENUM_VALUE; } @@ -1032,7 +1032,6 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act thread->SetActivity(static_cast(activity)); - system.PrepareReschedule(thread->GetProcessorID()); return RESULT_SUCCESS; } @@ -1385,6 +1384,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha /// Exits the current process static void ExitProcess(Core::System& system) { auto* current_process = system.Kernel().CurrentProcess(); + UNIMPLEMENTED(); LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID()); ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running, @@ -1394,8 +1394,6 @@ static void ExitProcess(Core::System& system) { // Kill the current thread system.CurrentScheduler().GetCurrentThread()->Stop(); - - system.PrepareReschedule(); } /// Creates a new thread @@ -1458,8 +1456,6 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e thread->SetName( fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); - system.PrepareReschedule(thread->GetProcessorID()); - return RESULT_SUCCESS; } @@ -1545,6 +1541,8 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add return ERR_INVALID_ADDRESS; } + UNIMPLEMENTED(); + ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); auto* const current_process = system.Kernel().CurrentProcess(); @@ -1569,7 +1567,6 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add // Note: Deliberately don't attempt to inherit the lock owner's priority. - system.PrepareReschedule(current_thread->GetProcessorID()); return RESULT_SUCCESS; } @@ -1580,6 +1577,8 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); + UNIMPLEMENTED(); + // Retrieve a list of all threads that are waiting for this condition variable. auto* const current_process = system.Kernel().CurrentProcess(); std::vector> waiting_threads = @@ -1634,7 +1633,6 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ thread->SetMutexWaitAddress(0); thread->SetWaitHandle(0); thread->SetWaitSynchronizationResult(RESULT_SUCCESS); - system.PrepareReschedule(thread->GetProcessorID()); } else { // The mutex is already owned by some other thread, make this thread wait on it. const Handle owner_handle = static_cast(mutex_val & Mutex::MutexOwnerMask); @@ -1646,7 +1644,6 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ thread->SetStatus(ThreadStatus::WaitMutex); owner->AddMutexWaiter(thread); - system.PrepareReschedule(thread->GetProcessorID()); } } } @@ -1661,6 +1658,7 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}", address, type, value, timeout); + UNIMPLEMENTED(); // If the passed address is a kernel virtual address, return invalid memory state. if (Core::Memory::IsKernelVirtualAddress(address)) { LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); @@ -1677,9 +1675,6 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, auto& address_arbiter = system.Kernel().CurrentProcess()->GetAddressArbiter(); const ResultCode result = address_arbiter.WaitForAddress(address, arbitration_type, value, timeout); - if (result == RESULT_SUCCESS) { - system.PrepareReschedule(); - } return result; } @@ -1689,6 +1684,8 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}", address, type, value, num_to_wake); + UNIMPLEMENTED(); + // If the passed address is a kernel virtual address, return invalid memory state. if (Core::Memory::IsKernelVirtualAddress(address)) { LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); @@ -1945,7 +1942,6 @@ static ResultCode SignalEvent(Core::System& system, Handle handle) { } writable_event->Signal(); - system.PrepareReschedule(); return RESULT_SUCCESS; } -- cgit v1.2.3 From d4ebb510a05d29befde6556e632413e5b35b9ab5 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 26 Feb 2020 22:26:53 -0400 Subject: SVC: Correct WaitSynchronization, WaitProcessWideKey, SignalProcessWideKey. --- src/core/hle/kernel/process.cpp | 1 - src/core/hle/kernel/scheduler.cpp | 2 +- src/core/hle/kernel/svc.cpp | 75 ++++++++++++++++---------- src/core/hle/kernel/synchronization.cpp | 8 ++- src/core/hle/kernel/synchronization_object.cpp | 4 ++ src/core/hle/kernel/synchronization_object.h | 2 + src/core/hle/kernel/thread.cpp | 2 +- src/core/hle/kernel/time_manager.cpp | 18 ++++++- src/core/hle/kernel/time_manager.h | 5 ++ 9 files changed, 84 insertions(+), 33 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index cd4b0aa60..ea5fe5b29 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -187,7 +187,6 @@ void Process::RemoveConditionVariableThread(std::shared_ptr thread) { } ++it; } - UNREACHABLE(); } std::vector> Process::GetConditionVariableThreads( diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 0e85ee69e..758fa8188 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -632,7 +632,7 @@ void Scheduler::SwitchContext() { cpu_core.SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); - + cpu_core.ClearExclusiveState(); } if (previous_thread->GetStatus() == ThreadStatus::Running) { previous_thread->SetStatus(ThreadStatus::Ready); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 8634d3feb..a5193063b 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1541,33 +1541,50 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add return ERR_INVALID_ADDRESS; } - UNIMPLEMENTED(); - ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); - + auto& kernel = system.Kernel(); + Handle event_handle; + Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); auto* const current_process = system.Kernel().CurrentProcess(); - const auto& handle_table = current_process->GetHandleTable(); - std::shared_ptr thread = handle_table.Get(thread_handle); - ASSERT(thread); + { + SchedulerLockAndSleep lock(kernel, event_handle, current_thread, nano_seconds); + const auto& handle_table = current_process->GetHandleTable(); + std::shared_ptr thread = handle_table.Get(thread_handle); + ASSERT(thread); + + current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + + const auto release_result = current_process->GetMutex().Release(mutex_addr); + if (release_result.IsError()) { + lock.CancelSleep(); + return release_result; + } - const auto release_result = current_process->GetMutex().Release(mutex_addr); - if (release_result.IsError()) { - return release_result; + if (nano_seconds == 0) { + lock.CancelSleep(); + return RESULT_TIMEOUT; + } + + current_thread->SetCondVarWaitAddress(condition_variable_addr); + current_thread->SetMutexWaitAddress(mutex_addr); + current_thread->SetWaitHandle(thread_handle); + current_thread->SetStatus(ThreadStatus::WaitCondVar); + current_process->InsertConditionVariableThread(SharedFrom(current_thread)); } - Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); - current_thread->SetCondVarWaitAddress(condition_variable_addr); - current_thread->SetMutexWaitAddress(mutex_addr); - current_thread->SetWaitHandle(thread_handle); - current_thread->SetStatus(ThreadStatus::WaitCondVar); - current_thread->InvalidateWakeupCallback(); - current_process->InsertConditionVariableThread(SharedFrom(current_thread)); + if (event_handle != InvalidHandle) { + auto& time_manager = kernel.TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); + } - current_thread->WakeAfterDelay(nano_seconds); + { + SchedulerLock lock(kernel); + current_process->RemoveConditionVariableThread(SharedFrom(current_thread)); + } // Note: Deliberately don't attempt to inherit the lock owner's priority. - return RESULT_SUCCESS; + return current_thread->GetSignalingResult(); } /// Signal process wide key @@ -1577,10 +1594,10 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); - UNIMPLEMENTED(); - // Retrieve a list of all threads that are waiting for this condition variable. - auto* const current_process = system.Kernel().CurrentProcess(); + auto& kernel = system.Kernel(); + SchedulerLock lock(kernel); + auto* const current_process = kernel.CurrentProcess(); std::vector> waiting_threads = current_process->GetConditionVariableThreads(condition_variable_addr); @@ -1589,10 +1606,18 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ std::size_t last = waiting_threads.size(); if (target > 0) last = std::min(waiting_threads.size(), static_cast(target)); - + auto& time_manager = kernel.TimeManager(); for (std::size_t index = 0; index < last; ++index) { auto& thread = waiting_threads[index]; + if (thread->GetStatus() != ThreadStatus::WaitCondVar) { + last++; + last = std::min(waiting_threads.size(), last); + continue; + } + + time_manager.CancelTimeEvent(thread.get()); + ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr); // liberate Cond Var Thread. @@ -1630,17 +1655,13 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ } thread->SetLockOwner(nullptr); - thread->SetMutexWaitAddress(0); - thread->SetWaitHandle(0); - thread->SetWaitSynchronizationResult(RESULT_SUCCESS); + thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); } else { // The mutex is already owned by some other thread, make this thread wait on it. const Handle owner_handle = static_cast(mutex_val & Mutex::MutexOwnerMask); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); auto owner = handle_table.Get(owner_handle); ASSERT(owner); - ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); - thread->InvalidateWakeupCallback(); thread->SetStatus(ThreadStatus::WaitMutex); owner->AddMutexWaiter(thread); diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index b36e550a0..c60c5bb42 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -17,12 +17,15 @@ namespace Kernel { Synchronization::Synchronization(Core::System& system) : system{system} {} void Synchronization::SignalObject(SynchronizationObject& obj) const { - SchedulerLock lock(system.Kernel()); + auto& kernel = system.Kernel(); + SchedulerLock lock(kernel); + auto& time_manager = kernel.TimeManager(); if (obj.IsSignaled()) { for (auto thread : obj.GetWaitingThreads()) { if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { thread->SetSynchronizationResults(&obj, RESULT_SUCCESS); thread->ResumeFromWait(); + time_manager.CancelTimeEvent(thread.get()); } } } @@ -79,6 +82,9 @@ std::pair Synchronization::WaitFor( SchedulerLock lock(kernel); ResultCode signaling_result = thread->GetSignalingResult(); SynchronizationObject* signaling_object = thread->GetSignalingObject(); + for (auto& obj : sync_objects) { + obj->RemoveWaitingThread(SharedFrom(thread)); + } if (signaling_result == RESULT_SUCCESS) { const auto itr = std::find_if( sync_objects.begin(), sync_objects.end(), diff --git a/src/core/hle/kernel/synchronization_object.cpp b/src/core/hle/kernel/synchronization_object.cpp index 43f3eef18..be9e09106 100644 --- a/src/core/hle/kernel/synchronization_object.cpp +++ b/src/core/hle/kernel/synchronization_object.cpp @@ -102,6 +102,10 @@ void SynchronizationObject::WakeupAllWaitingThreads() { } } +void SynchronizationObject::ClearWaitingThreads() { + waiting_threads.clear(); +} + const std::vector>& SynchronizationObject::GetWaitingThreads() const { return waiting_threads; } diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h index 0a0d069e0..a35544ac1 100644 --- a/src/core/hle/kernel/synchronization_object.h +++ b/src/core/hle/kernel/synchronization_object.h @@ -68,6 +68,8 @@ public: /// Get a const reference to the waiting threads list for debug use const std::vector>& GetWaitingThreads() const; + void ClearWaitingThreads(); + protected: bool is_signaled{}; // Tells if this sync object is signalled; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index fb97535a3..a645ee3a2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -49,12 +49,12 @@ Thread::~Thread() = default; void Thread::Stop() { SchedulerLock lock(kernel); // Cancel any outstanding wakeup events for this thread + Signal(); Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), global_handle); kernel.GlobalHandleTable().Close(global_handle); global_handle = 0; SetStatus(ThreadStatus::Dead); - Signal(); owner_process->UnregisterThread(this); diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 0b8f0d993..dab5fc4c6 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -8,15 +8,21 @@ #include "core/core_timing_util.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/time_manager.h" namespace Kernel { -TimeManager::TimeManager(Core::System& system) : system{system} { +TimeManager::TimeManager(Core::System& system_) : system{system_} { time_manager_event_type = Core::Timing::CreateEvent( "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) { + SchedulerLock lock(system.Kernel()); Handle proper_handle = static_cast(thread_handle); + if (cancelled_events[proper_handle]) { + return; + } + event_fired[proper_handle] = true; std::shared_ptr thread = this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); thread->OnWakeUp(); @@ -24,14 +30,16 @@ TimeManager::TimeManager(Core::System& system) : system{system} { } void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) { + event_handle = timetask->GetGlobalHandle(); if (nanoseconds > 0) { ASSERT(timetask); - event_handle = timetask->GetGlobalHandle(); const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); system.CoreTiming().ScheduleEvent(cycles, time_manager_event_type, event_handle); } else { event_handle = InvalidHandle; } + cancelled_events[event_handle] = false; + event_fired[event_handle] = false; } void TimeManager::UnscheduleTimeEvent(Handle event_handle) { @@ -39,6 +47,12 @@ void TimeManager::UnscheduleTimeEvent(Handle event_handle) { return; } system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle); + cancelled_events[event_handle] = true; +} + +void TimeManager::CancelTimeEvent(Thread* time_task) { + Handle event_handle = time_task->GetGlobalHandle(); + UnscheduleTimeEvent(event_handle); } } // namespace Kernel diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h index eaec486d1..3080ac838 100644 --- a/src/core/hle/kernel/time_manager.h +++ b/src/core/hle/kernel/time_manager.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "core/hle/kernel/object.h" @@ -35,9 +36,13 @@ public: /// Unschedule an existing time event void UnscheduleTimeEvent(Handle event_handle); + void CancelTimeEvent(Thread* time_task); + private: Core::System& system; std::shared_ptr time_manager_event_type; + std::unordered_map cancelled_events; + std::unordered_map event_fired; }; } // namespace Kernel -- cgit v1.2.3 From 3902067008abed4ca748e2f6d4ad582748f9ed52 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 27 Feb 2020 10:28:44 -0400 Subject: SVC: Add locks to the memory management. --- src/core/hle/kernel/svc.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index a5193063b..279fe5888 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -135,6 +135,7 @@ enum class ResourceLimitValueType { ResultVal RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, u32 resource_type, ResourceLimitValueType value_type) { + std::lock_guard lock{HLE::g_hle_lock}; const auto type = static_cast(resource_type); if (!IsValidResourceType(type)) { LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); @@ -162,6 +163,7 @@ ResultVal RetrieveResourceLimitValue(Core::System& system, Handle resource_ /// Set the process heap to a given Size. It can both extend and shrink the heap. static ResultCode SetHeapSize(Core::System& system, VAddr* heap_addr, u64 heap_size) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB. @@ -192,6 +194,7 @@ static ResultCode SetHeapSize32(Core::System& system, u32* heap_addr, u32 heap_s static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, u32 attribute) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address, size, mask, attribute); @@ -230,6 +233,7 @@ static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 si /// Maps a memory range into a different range. static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); @@ -245,6 +249,7 @@ static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr /// Unmaps a region that was previously mapped with svcMapMemory static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); @@ -261,6 +266,7 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad /// Connect to an OS service given the port name, returns the handle to the port to out static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, VAddr port_name_address) { + std::lock_guard lock{HLE::g_hle_lock}; auto& memory = system.Memory(); if (!memory.IsValidVirtualAddress(port_name_address)) { @@ -309,6 +315,7 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Core::System& system, Handle handle) { + std::lock_guard lock{HLE::g_hle_lock}; const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); std::shared_ptr session = handle_table.Get(handle); if (!session) { @@ -639,6 +646,7 @@ static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr addre /// Gets system/memory information for the current process static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 handle, u64 info_sub_id) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, info_sub_id, handle); @@ -904,6 +912,7 @@ static ResultCode GetInfo32(Core::System& system, u32* result_low, u32* result_h /// Maps memory at a desired address static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); if (!Common::Is4KBAligned(addr)) { @@ -953,6 +962,7 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) /// Unmaps memory previously mapped via MapPhysicalMemory static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); if (!Common::Is4KBAligned(addr)) { @@ -1129,6 +1139,7 @@ static u32 GetCurrentProcessorNumber(Core::System& system) { static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, u64 size, u32 permissions) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", shared_memory_handle, addr, size, permissions); @@ -1202,6 +1213,7 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, VAddr page_info_address, Handle process_handle, VAddr address) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); std::shared_ptr process = handle_table.Get(process_handle); @@ -1782,6 +1794,7 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) { /// Creates a TransferMemory object static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size, u32 permissions) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, permissions); @@ -1993,6 +2006,7 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_ } static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_DEBUG(Kernel_SVC, "called"); auto& kernel = system.Kernel(); @@ -2439,6 +2453,13 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); void Call(Core::System& system, u32 immediate) { MICROPROFILE_SCOPE(Kernel_SVC); + auto& physical_core = system.CurrentPhysicalCore(); + if (physical_core.IsInterrupted()) { + auto& sched = physical_core.Scheduler(); + sched.TryDoContextSwitch(); + } + physical_core.ClearExclusive(); + const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); if (info) { -- cgit v1.2.3 From bd36eaf15d88c3875aba7032fe5124fbb150bd5d Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 27 Feb 2020 11:25:42 -0400 Subject: SVC: Correct races on physical core switching. --- src/core/hle/kernel/svc.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 279fe5888..1e6c60d78 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2454,11 +2454,6 @@ void Call(Core::System& system, u32 immediate) { MICROPROFILE_SCOPE(Kernel_SVC); auto& physical_core = system.CurrentPhysicalCore(); - if (physical_core.IsInterrupted()) { - auto& sched = physical_core.Scheduler(); - sched.TryDoContextSwitch(); - } - physical_core.ClearExclusive(); const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); @@ -2471,6 +2466,10 @@ void Call(Core::System& system, u32 immediate) { } else { LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); } + auto& physical_core_2 = system.CurrentPhysicalCore(); + if (physical_core.CoreIndex() != physical_core_2.CoreIndex()) { + physical_core.Stop(); + } } } // namespace Kernel::Svc -- cgit v1.2.3 From 04e0f8776c26930d7dc8015e53914b11bf1929c1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 27 Feb 2020 19:12:41 -0400 Subject: General: Add better safety for JIT use. --- src/core/hle/kernel/scheduler.cpp | 3 +++ src/core/hle/kernel/svc.cpp | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 758fa8188..727d2e6cc 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -581,6 +581,7 @@ void Scheduler::SwitchContextStep2() { if (new_thread) { new_thread->context_guard.lock(); + cpu_core.Lock(); ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), "Thread must be assigned to this core."); ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready, @@ -601,6 +602,7 @@ void Scheduler::SwitchContextStep2() { cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); + cpu_core.ClearExclusiveState(); } } else { current_thread = nullptr; @@ -639,6 +641,7 @@ void Scheduler::SwitchContext() { } previous_thread->SetIsRunning(false); previous_thread->context_guard.unlock(); + cpu_core.Unlock(); } std::shared_ptr old_context; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 1e6c60d78..b535593c7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -10,6 +10,7 @@ #include "common/alignment.h" #include "common/assert.h" +#include "common/fiber.h" #include "common/logging/log.h" #include "common/microprofile.h" #include "common/string_util.h" @@ -2468,7 +2469,10 @@ void Call(Core::System& system, u32 immediate) { } auto& physical_core_2 = system.CurrentPhysicalCore(); if (physical_core.CoreIndex() != physical_core_2.CoreIndex()) { - physical_core.Stop(); + LOG_CRITICAL(Kernel_SVC, "Rewinding"); + auto* thread = physical_core_2.Scheduler().GetCurrentThread(); + auto* host_context = thread->GetHostContext().get(); + host_context->Rewind(); } } -- cgit v1.2.3 From 2a8837ff51a9cf5a0123489dba5f7ab48373c2d3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 28 Feb 2020 09:42:06 -0400 Subject: General: Add Asserts --- src/core/hle/kernel/scheduler.cpp | 18 ++++++++++++++++++ src/core/hle/kernel/scheduler.h | 1 + src/core/hle/kernel/svc.cpp | 1 + 3 files changed, 20 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 727d2e6cc..d67d3c5cd 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -44,6 +44,7 @@ void GlobalScheduler::RemoveThread(std::shared_ptr thread) { } u32 GlobalScheduler::SelectThreads() { + ASSERT(is_locked); const auto update_thread = [](Thread* thread, Scheduler& sched) { sched.guard.lock(); if (thread != sched.selected_thread.get()) { @@ -136,6 +137,7 @@ u32 GlobalScheduler::SelectThreads() { } bool GlobalScheduler::YieldThread(Thread* yielding_thread) { + ASSERT(is_locked); // Note: caller should use critical section, etc. const u32 core_id = static_cast(yielding_thread->GetProcessorID()); const u32 priority = yielding_thread->GetPriority(); @@ -149,6 +151,7 @@ bool GlobalScheduler::YieldThread(Thread* yielding_thread) { } bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { + ASSERT(is_locked); // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. const u32 core_id = static_cast(yielding_thread->GetProcessorID()); @@ -197,6 +200,7 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { } bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread) { + ASSERT(is_locked); // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. Thread* winner = nullptr; @@ -237,6 +241,7 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread } void GlobalScheduler::PreemptThreads() { + ASSERT(is_locked); for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { const u32 priority = preemption_priorities[core_id]; @@ -339,33 +344,40 @@ void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule, } void GlobalScheduler::Suggest(u32 priority, std::size_t core, Thread* thread) { + ASSERT(is_locked); suggested_queue[core].add(thread, priority); } void GlobalScheduler::Unsuggest(u32 priority, std::size_t core, Thread* thread) { + ASSERT(is_locked); suggested_queue[core].remove(thread, priority); } void GlobalScheduler::Schedule(u32 priority, std::size_t core, Thread* thread) { + ASSERT(is_locked); ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core."); scheduled_queue[core].add(thread, priority); } void GlobalScheduler::SchedulePrepend(u32 priority, std::size_t core, Thread* thread) { + ASSERT(is_locked); ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core."); scheduled_queue[core].add(thread, priority, false); } void GlobalScheduler::Reschedule(u32 priority, std::size_t core, Thread* thread) { + ASSERT(is_locked); scheduled_queue[core].remove(thread, priority); scheduled_queue[core].add(thread, priority); } void GlobalScheduler::Unschedule(u32 priority, std::size_t core, Thread* thread) { + ASSERT(is_locked); scheduled_queue[core].remove(thread, priority); } void GlobalScheduler::TransferToCore(u32 priority, s32 destination_core, Thread* thread) { + ASSERT(is_locked); const bool schedulable = thread->GetPriority() < THREADPRIO_COUNT; const s32 source_core = thread->GetProcessorID(); if (source_core == destination_core || !schedulable) { @@ -399,6 +411,7 @@ void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { if (old_flags == thread->scheduling_state) { return; } + ASSERT(is_locked); if (static_cast(old_flags & static_cast(ThreadSchedMasks::LowMask)) == ThreadSchedStatus::Runnable) { @@ -434,6 +447,7 @@ void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priorit if (thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { return; } + ASSERT(is_locked); if (thread->processor_id >= 0) { Unschedule(old_priority, static_cast(thread->processor_id), thread); } @@ -472,6 +486,7 @@ void GlobalScheduler::AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinit thread->current_priority >= THREADPRIO_COUNT) { return; } + ASSERT(is_locked); for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (((old_affinity_mask >> core) & 1) != 0) { @@ -507,10 +522,12 @@ void GlobalScheduler::Shutdown() { void GlobalScheduler::Lock() { Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadID(); + ASSERT(!current_thread.IsInvalid()); if (current_thread == current_owner) { ++scope_lock; } else { inner_lock.lock(); + is_locked = true; current_owner = current_thread; ASSERT(current_owner != Core::EmuThreadHandle::InvalidHandle()); scope_lock = 1; @@ -526,6 +543,7 @@ void GlobalScheduler::Unlock() { Core::EmuThreadHandle leaving_thread = current_owner; current_owner = Core::EmuThreadHandle::InvalidHandle(); scope_lock = 1; + is_locked = false; inner_lock.unlock(); EnableInterruptAndSchedule(cores_pending_reschedule, leaving_thread); } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index f5f64338f..f26a554f5 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -182,6 +182,7 @@ private: std::array preemption_priorities = {59, 59, 59, 62}; /// Scheduler lock mechanisms. + bool is_locked{}; std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock std::atomic scope_lock{}; Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()}; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b535593c7..4c1040a3b 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1657,6 +1657,7 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ update_val = thread->GetWaitHandle(); } } while (!monitor.ExclusiveWrite32(current_core, mutex_address, update_val)); + monitor.ClearExclusive(); if (mutex_val == 0) { // We were able to acquire the mutex, resume this thread. ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); -- cgit v1.2.3 From de5b521c0900bbd4d7012ffa3dfd63cc8f3d4371 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 3 Mar 2020 11:04:37 -0400 Subject: Process: Protect TLS region and Modules. --- src/core/hle/kernel/process.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index ea5fe5b29..f9d7c024d 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -22,6 +22,7 @@ #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" +#include "core/hle/lock.h" #include "core/memory.h" #include "core/settings.h" @@ -345,6 +346,7 @@ static auto FindTLSPageWithAvailableSlots(std::vector& tls_pages) { } VAddr Process::CreateTLSRegion() { + SchedulerLock lock(system.Kernel()); if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)}; tls_page_iter != tls_pages.cend()) { return *tls_page_iter->ReserveSlot(); @@ -375,6 +377,7 @@ VAddr Process::CreateTLSRegion() { } void Process::FreeTLSRegion(VAddr tls_address) { + SchedulerLock lock(system.Kernel()); const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE); auto iter = std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) { @@ -389,6 +392,7 @@ void Process::FreeTLSRegion(VAddr tls_address) { } void Process::LoadModule(CodeSet code_set, VAddr base_addr) { + std::lock_guard lock{HLE::g_hle_lock}; const auto ReprotectSegment = [&](const CodeSet::Segment& segment, Memory::MemoryPermission permission) { page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission); -- cgit v1.2.3 From 75e10578f12cf64bd734388ba80b5f5a46ca6133 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 3 Mar 2020 13:02:50 -0400 Subject: Core: Correct HLE Event Callbacks and other issues. --- src/core/hle/kernel/hle_ipc.cpp | 19 +++++++++--------- src/core/hle/kernel/svc.cpp | 5 ++--- src/core/hle/kernel/synchronization.cpp | 1 + src/core/hle/kernel/thread.cpp | 35 ++++++++++++++++----------------- src/core/hle/kernel/thread.h | 16 ++++++++------- 5 files changed, 39 insertions(+), 37 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 955d5fe1c..e74d91670 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -21,8 +21,8 @@ #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/readable_event.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/scheduler.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/time_manager.h" #include "core/hle/kernel/writable_event.h" @@ -49,14 +49,6 @@ std::shared_ptr HLERequestContext::SleepClientThread( const std::string& reason, u64 timeout, WakeupCallback&& callback, std::shared_ptr writable_event) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->SetHLECallback( - [context = *this, callback](ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, - std::size_t index) mutable -> bool { - callback(thread, context, reason); - context.WriteToOutgoingCommandBuffer(*thread); - return true; - }); if (!writable_event) { // Create event if not provided @@ -67,6 +59,15 @@ std::shared_ptr HLERequestContext::SleepClientThread( { Handle event_handle = InvalidHandle; SchedulerLockAndSleep lock(kernel, event_handle, thread.get(), timeout); + thread->SetHLECallback( + [context = *this, callback](std::shared_ptr thread) mutable -> bool { + ThreadWakeupReason reason = thread->GetSignalingResult() == RESULT_TIMEOUT + ? ThreadWakeupReason::Timeout + : ThreadWakeupReason::Signal; + callback(thread, context, reason); + context.WriteToOutgoingCommandBuffer(*thread); + return true; + }); const auto readable_event{writable_event->GetReadableEvent()}; writable_event->Clear(); thread->SetStatus(ThreadStatus::WaitHLEEvent); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4c1040a3b..9f46a1758 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -333,17 +333,16 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { thread->SetStatus(ThreadStatus::WaitIPC); session->SendSyncRequest(SharedFrom(thread), system.Memory()); } - ResultCode result = thread->GetSignalingResult(); if (thread->HasHLECallback()) { Handle event_handle = thread->GetHLETimeEvent(); if (event_handle != InvalidHandle) { auto& time_manager = system.Kernel().TimeManager(); time_manager.UnscheduleTimeEvent(event_handle); } - thread->InvokeHLECallback(ThreadWakeupReason::Timeout, SharedFrom(thread), nullptr, 0); + thread->InvokeHLECallback(SharedFrom(thread)); } - return result; + return RESULT_SUCCESS; } static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index c60c5bb42..4ee7ad93c 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -28,6 +28,7 @@ void Synchronization::SignalObject(SynchronizationObject& obj) const { time_manager.CancelTimeEvent(thread.get()); } } + obj.ClearWaitingThreads(); } } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index a645ee3a2..16babe71a 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -47,19 +47,21 @@ Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {} Thread::~Thread() = default; void Thread::Stop() { - SchedulerLock lock(kernel); - // Cancel any outstanding wakeup events for this thread - Signal(); - Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - global_handle); - kernel.GlobalHandleTable().Close(global_handle); - global_handle = 0; - SetStatus(ThreadStatus::Dead); + { + SchedulerLock lock(kernel); + // Cancel any outstanding wakeup events for this thread + Signal(); + Core::System::GetInstance().CoreTiming().UnscheduleEvent( + kernel.ThreadWakeupCallbackEventType(), global_handle); + kernel.GlobalHandleTable().Close(global_handle); + SetStatus(ThreadStatus::Dead); - owner_process->UnregisterThread(this); + owner_process->UnregisterThread(this); - // Mark the TLS slot in the thread's page as free. - owner_process->FreeTLSRegion(tls_address); + // Mark the TLS slot in the thread's page as free. + owner_process->FreeTLSRegion(tls_address); + } + global_handle = 0; } void Thread::WakeAfterDelay(s64 nanoseconds) { @@ -112,8 +114,6 @@ void Thread::ResumeFromWait() { return; } - hle_callback = nullptr; - if (activity == ThreadActivity::Paused) { SetStatus(ThreadStatus::Paused); return; @@ -398,14 +398,13 @@ bool Thread::AllSynchronizationObjectsReady() const { bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, std::shared_ptr object, std::size_t index) { - ASSERT(hle_callback); - return hle_callback(reason, std::move(thread), std::move(object), index); + ASSERT(wakeup_callback); + return wakeup_callback(reason, std::move(thread), std::move(object), index); } -bool Thread::InvokeHLECallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, std::size_t index) { +bool Thread::InvokeHLECallback(std::shared_ptr thread) { ASSERT(hle_callback); - return hle_callback(reason, std::move(thread), std::move(object), index); + return hle_callback(std::move(thread)); } void Thread::SetActivity(ThreadActivity value) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 04496f96e..c4c9d69ec 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -448,7 +448,7 @@ public: } bool HasWakeupCallback() const { - return hle_callback != nullptr; + return wakeup_callback != nullptr; } bool HasHLECallback() const { @@ -456,10 +456,10 @@ public: } void SetWakeupCallback(WakeupCallback callback) { - hle_callback = std::move(callback); + wakeup_callback = std::move(callback); } - void SetHLECallback(WakeupCallback callback) { + void SetHLECallback(HLECallback callback) { hle_callback = std::move(callback); } @@ -487,8 +487,7 @@ public: */ bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, std::shared_ptr object, std::size_t index); - bool InvokeHLECallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, std::size_t index); + bool InvokeHLECallback(std::shared_ptr thread); u32 GetIdealCore() const { return ideal_core; @@ -622,8 +621,11 @@ private: /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread /// was waiting via WaitSynchronization then the object will be the last object that became - /// available. In case of a timeout, the object will be nullptr. - WakeupCallback hle_callback; + /// available. In case of a timeout, the object will be nullptr. DEPRECATED + WakeupCallback wakeup_callback; + + /// Callback for HLE Events + HLECallback hle_callback; Handle hle_time_event; Scheduler* scheduler = nullptr; -- cgit v1.2.3 From b4dc01f16affe4baa9a7ab5ac4b240e03c03ae67 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 3 Mar 2020 13:37:11 -0400 Subject: Kernel: Correct Signal on Thread Death and Setup Sync Objects on Thread for Debugging --- src/core/hle/kernel/synchronization.cpp | 3 +++ src/core/hle/kernel/thread.cpp | 15 +++++++-------- src/core/hle/kernel/thread.h | 14 +++++++------- 3 files changed, 17 insertions(+), 15 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index 4ee7ad93c..ac43a7094 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -70,6 +70,8 @@ std::pair Synchronization::WaitFor( for (auto& object : sync_objects) { object->AddWaitingThread(SharedFrom(thread)); } + + thread->SetSynchronizationObjects(&sync_objects); thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); thread->SetStatus(ThreadStatus::WaitSynch); } @@ -83,6 +85,7 @@ std::pair Synchronization::WaitFor( SchedulerLock lock(kernel); ResultCode signaling_result = thread->GetSignalingResult(); SynchronizationObject* signaling_object = thread->GetSignalingObject(); + thread->SetSynchronizationObjects(nullptr); for (auto& obj : sync_objects) { obj->RemoveWaitingThread(SharedFrom(thread)); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 16babe71a..fb1751860 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -50,11 +50,11 @@ void Thread::Stop() { { SchedulerLock lock(kernel); // Cancel any outstanding wakeup events for this thread - Signal(); Core::System::GetInstance().CoreTiming().UnscheduleEvent( kernel.ThreadWakeupCallbackEventType(), global_handle); - kernel.GlobalHandleTable().Close(global_handle); SetStatus(ThreadStatus::Dead); + Signal(); + kernel.GlobalHandleTable().Close(global_handle); owner_process->UnregisterThread(this); @@ -81,7 +81,6 @@ void Thread::CancelWakeupTimer() { } void Thread::ResumeFromWait() { - ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); SchedulerLock lock(kernel); switch (status) { case ThreadStatus::Paused: @@ -219,7 +218,7 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy thread->processor_id = processor_id; thread->ideal_core = processor_id; thread->affinity_mask = 1ULL << processor_id; - thread->wait_objects.clear(); + thread->wait_objects = nullptr; thread->mutex_wait_address = 0; thread->condvar_wait_address = 0; thread->wait_handle = 0; @@ -272,9 +271,9 @@ void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode } s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr object) const { - ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything"); - const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); - return static_cast(std::distance(match, wait_objects.rend()) - 1); + ASSERT_MSG(!wait_objects->empty(), "Thread is not waiting for anything"); + const auto match = std::find(wait_objects->rbegin(), wait_objects->rend(), object); + return static_cast(std::distance(match, wait_objects->rend()) - 1); } VAddr Thread::GetCommandBufferAddress() const { @@ -389,7 +388,7 @@ void Thread::UpdatePriority() { } bool Thread::AllSynchronizationObjectsReady() const { - return std::none_of(wait_objects.begin(), wait_objects.end(), + return std::none_of(wait_objects->begin(), wait_objects->end(), [this](const std::shared_ptr& object) { return object->ShouldWait(this); }); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index c4c9d69ec..7b6d1b4ec 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -21,7 +21,7 @@ class Fiber; namespace Core { class System; -} +} // namespace Core namespace Kernel { @@ -386,18 +386,18 @@ public: } const ThreadSynchronizationObjects& GetSynchronizationObjects() const { - return wait_objects; + return *wait_objects; } - void SetSynchronizationObjects(ThreadSynchronizationObjects objects) { - wait_objects = std::move(objects); + void SetSynchronizationObjects(ThreadSynchronizationObjects* objects) { + wait_objects = objects; } void ClearSynchronizationObjects() { - for (const auto& waiting_object : wait_objects) { + for (const auto& waiting_object : *wait_objects) { waiting_object->RemoveWaitingThread(SharedFrom(this)); } - wait_objects.clear(); + wait_objects->clear(); } /// Determines whether all the objects this thread is waiting on are ready. @@ -595,7 +595,7 @@ private: /// Objects that the thread is waiting on, in the same order as they were /// passed to WaitSynchronization. - ThreadSynchronizationObjects wait_objects; + ThreadSynchronizationObjects* wait_objects; SynchronizationObject* signaling_object; ResultCode signaling_result{RESULT_SUCCESS}; -- cgit v1.2.3 From 07993ac8c8c66bbf638dddc7750106f6dfb0e09b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 3 Mar 2020 15:50:38 -0400 Subject: Kernel: Corrections to Scheduling. --- src/core/hle/kernel/scheduler.cpp | 26 +++++++++++++------------- src/core/hle/kernel/scheduler.h | 2 ++ src/core/hle/kernel/svc.cpp | 1 - 3 files changed, 15 insertions(+), 14 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index d67d3c5cd..da77967dd 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -47,13 +47,13 @@ u32 GlobalScheduler::SelectThreads() { ASSERT(is_locked); const auto update_thread = [](Thread* thread, Scheduler& sched) { sched.guard.lock(); - if (thread != sched.selected_thread.get()) { + if (thread != sched.selected_thread_set.get()) { if (thread == nullptr) { ++sched.idle_selection_count; } - sched.selected_thread = SharedFrom(thread); + sched.selected_thread_set = SharedFrom(thread); } - const bool reschedule_pending = sched.selected_thread != sched.current_thread; + const bool reschedule_pending = sched.selected_thread_set != sched.current_thread; sched.is_context_switch_pending = reschedule_pending; std::atomic_thread_fence(std::memory_order_seq_cst); sched.guard.unlock(); @@ -118,6 +118,8 @@ u32 GlobalScheduler::SelectThreads() { suggested); top_threads[candidate_core] = next; break; + } else { + suggested = nullptr; } } } @@ -590,7 +592,7 @@ void Scheduler::OnThreadStart() { } void Scheduler::SwitchContextStep2() { - Thread* previous_thread = current_thread.get(); + Thread* previous_thread = current_thread_prev.get(); Thread* new_thread = selected_thread.get(); // Load context of new thread @@ -606,8 +608,6 @@ void Scheduler::SwitchContextStep2() { "Thread must be ready to become running."); // Cancel any outstanding wakeup events for this thread - current_thread = SharedFrom(new_thread); - new_thread->SetStatus(ThreadStatus::Running); new_thread->SetIsRunning(true); auto* const thread_owner_process = current_thread->GetOwnerProcess(); @@ -622,21 +622,21 @@ void Scheduler::SwitchContextStep2() { cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); cpu_core.ClearExclusiveState(); } - } else { - current_thread = nullptr; - // Note: We do not reset the current process and current page table when idling because - // technically we haven't changed processes, our threads are just paused. } - guard.unlock(); + + TryDoContextSwitch(); } void Scheduler::SwitchContext() { - Thread* previous_thread = current_thread.get(); + current_thread_prev = current_thread; + selected_thread = selected_thread_set; + Thread* previous_thread = current_thread_prev.get(); Thread* new_thread = selected_thread.get(); + current_thread = selected_thread; is_context_switch_pending = false; + guard.unlock(); if (new_thread == previous_thread) { - guard.unlock(); return; } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index f26a554f5..f73ca777e 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -249,6 +249,8 @@ private: std::shared_ptr current_thread = nullptr; std::shared_ptr selected_thread = nullptr; + std::shared_ptr current_thread_prev = nullptr; + std::shared_ptr selected_thread_set = nullptr; std::shared_ptr idle_thread = nullptr; Core::System& system; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9f46a1758..5e9dd43bf 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -316,7 +316,6 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Core::System& system, Handle handle) { - std::lock_guard lock{HLE::g_hle_lock}; const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); std::shared_ptr session = handle_table.Get(handle); if (!session) { -- cgit v1.2.3 From 1e987dbe8d9b5fbe778637c0b35cbc51b1a0956b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 3 Mar 2020 15:59:09 -0400 Subject: Scheduler: Correct Select Threads Step 2. --- src/core/hle/kernel/scheduler.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index da77967dd..9329202c6 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -103,6 +103,7 @@ u32 GlobalScheduler::SelectThreads() { TransferToCore(suggested->GetPriority(), static_cast(core_id), suggested); break; } + suggested = nullptr; migration_candidates[num_candidates++] = suggested_core_id; } // Step 3: Select a suggested thread from another core -- cgit v1.2.3 From e4b175ade205095e7cc89e0f60c902c708d7d767 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 3 Mar 2020 17:19:44 -0400 Subject: SVC: Correct svcWaitForAddress and svcSignalToAddress. --- src/core/hle/kernel/address_arbiter.cpp | 214 +++++++++++++++++++++++--------- src/core/hle/kernel/address_arbiter.h | 3 - src/core/hle/kernel/svc.cpp | 3 - src/core/hle/kernel/thread.h | 9 ++ 4 files changed, 161 insertions(+), 68 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 8475b698c..ebabde921 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -7,11 +7,15 @@ #include "common/assert.h" #include "common/common_types.h" +#include "core/arm/exclusive_monitor.h" #include "core/core.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/errors.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/time_manager.h" #include "core/hle/result.h" #include "core/memory.h" @@ -20,6 +24,7 @@ namespace Kernel { // Wake up num_to_wake (or all) threads in a vector. void AddressArbiter::WakeThreads(const std::vector>& waiting_threads, s32 num_to_wake) { + auto& time_manager = system.Kernel().TimeManager(); // Only process up to 'target' threads, unless 'target' is <= 0, in which case process // them all. std::size_t last = waiting_threads.size(); @@ -29,12 +34,20 @@ void AddressArbiter::WakeThreads(const std::vector>& wai // Signal the waiting threads. for (std::size_t i = 0; i < last; i++) { + if (waiting_threads[i]->GetStatus() != ThreadStatus::WaitArb) { + last++; + last = std::min(waiting_threads.size(), last); + continue; + } + + time_manager.CancelTimeEvent(waiting_threads[i].get()); + ASSERT(waiting_threads[i]->GetStatus() == ThreadStatus::WaitArb); - waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS); + waiting_threads[i]->SetSynchronizationResults(nullptr, RESULT_SUCCESS); RemoveThread(waiting_threads[i]); + waiting_threads[i]->WaitForArbitration(false); waiting_threads[i]->SetArbiterWaitAddress(0); waiting_threads[i]->ResumeFromWait(); - system.PrepareReschedule(waiting_threads[i]->GetProcessorID()); } } @@ -56,6 +69,7 @@ ResultCode AddressArbiter::SignalToAddress(VAddr address, SignalType type, s32 v } ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { + SchedulerLock lock(system.Kernel()); const std::vector> waiting_threads = GetThreadsWaitingOnAddress(address); WakeThreads(waiting_threads, num_to_wake); @@ -64,6 +78,7 @@ ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + SchedulerLock lock(system.Kernel()); auto& memory = system.Memory(); // Ensure that we can write to the address. @@ -71,16 +86,25 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 return ERR_INVALID_ADDRESS_STATE; } - if (static_cast(memory.Read32(address)) != value) { - return ERR_INVALID_STATE; - } + const std::size_t current_core = system.CurrentCoreIndex(); + auto& monitor = system.Monitor(); + u32 current_value; + do { + monitor.SetExclusive(current_core, address); + current_value = memory.Read32(address); + + if (current_value != value) { + return ERR_INVALID_STATE; + } + current_value++; + } while (!monitor.ExclusiveWrite32(current_core, address, current_value)); - memory.Write32(address, static_cast(value + 1)); return SignalToAddressOnly(address, num_to_wake); } ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + SchedulerLock lock(system.Kernel()); auto& memory = system.Memory(); // Ensure that we can write to the address. @@ -92,29 +116,34 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a const std::vector> waiting_threads = GetThreadsWaitingOnAddress(address); - // Determine the modified value depending on the waiting count. + const std::size_t current_core = system.CurrentCoreIndex(); + auto& monitor = system.Monitor(); s32 updated_value; - if (num_to_wake <= 0) { - if (waiting_threads.empty()) { - updated_value = value + 1; - } else { - updated_value = value - 1; + do { + monitor.SetExclusive(current_core, address); + updated_value = memory.Read32(address); + + if (updated_value != value) { + return ERR_INVALID_STATE; } - } else { - if (waiting_threads.empty()) { - updated_value = value + 1; - } else if (waiting_threads.size() <= static_cast(num_to_wake)) { - updated_value = value - 1; + // Determine the modified value depending on the waiting count. + if (num_to_wake <= 0) { + if (waiting_threads.empty()) { + updated_value = value + 1; + } else { + updated_value = value - 1; + } } else { - updated_value = value; + if (waiting_threads.empty()) { + updated_value = value + 1; + } else if (waiting_threads.size() <= static_cast(num_to_wake)) { + updated_value = value - 1; + } else { + updated_value = value; + } } - } + } while (!monitor.ExclusiveWrite32(current_core, address, updated_value)); - if (static_cast(memory.Read32(address)) != value) { - return ERR_INVALID_STATE; - } - - memory.Write32(address, static_cast(updated_value)); WakeThreads(waiting_threads, num_to_wake); return RESULT_SUCCESS; } @@ -136,60 +165,121 @@ ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { auto& memory = system.Memory(); + auto& kernel = system.Kernel(); + Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); - // Ensure that we can read the address. - if (!memory.IsValidVirtualAddress(address)) { - return ERR_INVALID_ADDRESS_STATE; - } + Handle event_handle = InvalidHandle; + { + SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); + + // Ensure that we can read the address. + if (!memory.IsValidVirtualAddress(address)) { + lock.CancelSleep(); + return ERR_INVALID_ADDRESS_STATE; + } + + /// TODO(Blinkhawk): Check termination pending. + + s32 current_value = static_cast(memory.Read32(address)); + if (current_value >= value) { + lock.CancelSleep(); + return ERR_INVALID_STATE; + } - const s32 cur_value = static_cast(memory.Read32(address)); - if (cur_value >= value) { - return ERR_INVALID_STATE; + s32 decrement_value; + + const std::size_t current_core = system.CurrentCoreIndex(); + auto& monitor = system.Monitor(); + do { + monitor.SetExclusive(current_core, address); + current_value = static_cast(memory.Read32(address)); + if (should_decrement) { + decrement_value = current_value - 1; + } else { + decrement_value = current_value; + } + } while ( + !monitor.ExclusiveWrite32(current_core, address, static_cast(decrement_value))); + + // Short-circuit without rescheduling, if timeout is zero. + if (timeout == 0) { + lock.CancelSleep(); + return RESULT_TIMEOUT; + } + + current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + current_thread->SetArbiterWaitAddress(address); + InsertThread(SharedFrom(current_thread)); + current_thread->SetStatus(ThreadStatus::WaitArb); + current_thread->WaitForArbitration(true); } - if (should_decrement) { - memory.Write32(address, static_cast(cur_value - 1)); + if (event_handle != InvalidHandle) { + auto& time_manager = kernel.TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); } - // Short-circuit without rescheduling, if timeout is zero. - if (timeout == 0) { - return RESULT_TIMEOUT; + { + SchedulerLock lock(kernel); + if (current_thread->IsWaitingForArbitration()) { + RemoveThread(SharedFrom(current_thread)); + current_thread->WaitForArbitration(false); + } } - return WaitForAddressImpl(address, timeout); + return current_thread->GetSignalingResult(); } ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { auto& memory = system.Memory(); + auto& kernel = system.Kernel(); + Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); - // Ensure that we can read the address. - if (!memory.IsValidVirtualAddress(address)) { - return ERR_INVALID_ADDRESS_STATE; - } + Handle event_handle = InvalidHandle; + { + SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); + + // Ensure that we can read the address. + if (!memory.IsValidVirtualAddress(address)) { + lock.CancelSleep(); + return ERR_INVALID_ADDRESS_STATE; + } + + /// TODO(Blinkhawk): Check termination pending. - // Only wait for the address if equal. - if (static_cast(memory.Read32(address)) != value) { - return ERR_INVALID_STATE; + s32 current_value = static_cast(memory.Read32(address)); + if (current_value != value) { + lock.CancelSleep(); + return ERR_INVALID_STATE; + } + + // Short-circuit without rescheduling, if timeout is zero. + if (timeout == 0) { + lock.CancelSleep(); + return RESULT_TIMEOUT; + } + + current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + current_thread->SetArbiterWaitAddress(address); + InsertThread(SharedFrom(current_thread)); + current_thread->SetStatus(ThreadStatus::WaitArb); + current_thread->WaitForArbitration(true); } - // Short-circuit without rescheduling if timeout is zero. - if (timeout == 0) { - return RESULT_TIMEOUT; + if (event_handle != InvalidHandle) { + auto& time_manager = kernel.TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); } - return WaitForAddressImpl(address, timeout); -} + { + SchedulerLock lock(kernel); + if (current_thread->IsWaitingForArbitration()) { + RemoveThread(SharedFrom(current_thread)); + current_thread->WaitForArbitration(false); + } + } -ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) { - Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); - current_thread->SetArbiterWaitAddress(address); - InsertThread(SharedFrom(current_thread)); - current_thread->SetStatus(ThreadStatus::WaitArb); - current_thread->InvalidateWakeupCallback(); - current_thread->WakeAfterDelay(timeout); - - system.PrepareReschedule(current_thread->GetProcessorID()); - return RESULT_TIMEOUT; + return current_thread->GetSignalingResult(); } void AddressArbiter::HandleWakeupThread(std::shared_ptr thread) { @@ -221,9 +311,9 @@ void AddressArbiter::RemoveThread(std::shared_ptr thread) { const auto iter = std::find_if(thread_list.cbegin(), thread_list.cend(), [&thread](const auto& entry) { return thread == entry; }); - ASSERT(iter != thread_list.cend()); - - thread_list.erase(iter); + if (iter != thread_list.cend()) { + thread_list.erase(iter); + } } std::vector> AddressArbiter::GetThreadsWaitingOnAddress( diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index f958eee5a..0b05d533c 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -73,9 +73,6 @@ private: /// Waits on an address if the value passed is equal to the argument value. ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); - // Waits on the given address with a timeout in nanoseconds - ResultCode WaitForAddressImpl(VAddr address, s64 timeout); - /// Wake up num_to_wake (or all) threads in a vector. void WakeThreads(const std::vector>& waiting_threads, s32 num_to_wake); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 5e9dd43bf..718462b2b 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1691,7 +1691,6 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}", address, type, value, timeout); - UNIMPLEMENTED(); // If the passed address is a kernel virtual address, return invalid memory state. if (Core::Memory::IsKernelVirtualAddress(address)) { LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); @@ -1717,8 +1716,6 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}", address, type, value, num_to_wake); - UNIMPLEMENTED(); - // If the passed address is a kernel virtual address, return invalid memory state. if (Core::Memory::IsKernelVirtualAddress(address)) { LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 7b6d1b4ec..e8355bbd1 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -548,6 +548,14 @@ public: return global_handle; } + bool IsWaitingForArbitration() const { + return waiting_for_arbitration; + } + + void WaitForArbitration(bool set) { + waiting_for_arbitration = set; + } + private: friend class GlobalScheduler; friend class Scheduler; @@ -615,6 +623,7 @@ private: /// If waiting for an AddressArbiter, this is the address being waited on. VAddr arb_wait_address{0}; + bool waiting_for_arbitration{}; /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. Handle global_handle = 0; -- cgit v1.2.3 From a6bce296ad3fa8e7da66df3d32cd148448ac0abb Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 4 Mar 2020 22:46:22 -0400 Subject: Mutex: Correct Result writting to clear exclusivity. --- src/core/hle/kernel/mutex.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 18325db57..ebe3f6050 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -9,6 +9,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/arm/exclusive_monitor.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -133,8 +134,12 @@ std::pair> Mutex::Unlock(std::shared_ptr> Mutex::Unlock(std::shared_ptrSetSynchronizationResults(nullptr, RESULT_SUCCESS); - new_owner->ResumeFromWait(); new_owner->SetLockOwner(nullptr); - system.Memory().Write32(address, mutex_value); + new_owner->ResumeFromWait(); + + do { + monitor.SetExclusive(current_core, address); + } while (!monitor.ExclusiveWrite32(current_core, address, mutex_value)); return {RESULT_SUCCESS, new_owner}; } -- cgit v1.2.3 From 1c672128c421ea3141a74f9c6695ecc83231ca30 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 09:52:24 -0400 Subject: Scheduler: Release old thread fiber before trying to switch to the next thread fiber. --- src/core/hle/kernel/scheduler.cpp | 37 ++++++++++++++++++++++++++----------- src/core/hle/kernel/scheduler.h | 9 +++++++++ 2 files changed, 35 insertions(+), 11 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 9329202c6..aa1f1a305 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -53,7 +53,8 @@ u32 GlobalScheduler::SelectThreads() { } sched.selected_thread_set = SharedFrom(thread); } - const bool reschedule_pending = sched.selected_thread_set != sched.current_thread; + const bool reschedule_pending = + sched.is_context_switch_pending || (sched.selected_thread_set != sched.current_thread); sched.is_context_switch_pending = reschedule_pending; std::atomic_thread_fence(std::memory_order_seq_cst); sched.guard.unlock(); @@ -552,7 +553,9 @@ void GlobalScheduler::Unlock() { } Scheduler::Scheduler(Core::System& system, std::size_t core_id) - : system{system}, core_id{core_id} {} + : system(system), core_id(core_id) { + switch_fiber = std::make_shared(std::function(OnSwitch), this); +} Scheduler::~Scheduler() = default; @@ -636,8 +639,9 @@ void Scheduler::SwitchContext() { current_thread = selected_thread; is_context_switch_pending = false; - guard.unlock(); + if (new_thread == previous_thread) { + guard.unlock(); return; } @@ -669,20 +673,31 @@ void Scheduler::SwitchContext() { } else { old_context = idle_thread->GetHostContext(); } + guard.unlock(); - std::shared_ptr next_context; - if (new_thread != nullptr) { - next_context = new_thread->GetHostContext(); - } else { - next_context = idle_thread->GetHostContext(); - } - - Common::Fiber::YieldTo(old_context, next_context); + Common::Fiber::YieldTo(old_context, switch_fiber); /// When a thread wakes up, the scheduler may have changed to other in another core. auto& next_scheduler = system.Kernel().CurrentScheduler(); next_scheduler.SwitchContextStep2(); } +void Scheduler::OnSwitch(void* this_scheduler) { + Scheduler* sched = static_cast(this_scheduler); + sched->SwitchToCurrent(); +} + +void Scheduler::SwitchToCurrent() { + while (true) { + std::shared_ptr next_context; + if (current_thread != nullptr) { + next_context = current_thread->GetHostContext(); + } else { + next_context = idle_thread->GetHostContext(); + } + Common::Fiber::YieldTo(switch_fiber, next_context); + } +} + void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { const u64 prev_switch_ticks = last_context_switch_time; const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index f73ca777e..728cca802 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -15,6 +15,10 @@ #include "core/hardware_properties.h" #include "core/hle/kernel/thread.h" +namespace Common { + class Fiber; +} + namespace Core { class ARM_Interface; class System; @@ -247,12 +251,17 @@ private: */ void UpdateLastContextSwitchTime(Thread* thread, Process* process); + static void OnSwitch(void* this_scheduler); + void SwitchToCurrent(); + std::shared_ptr current_thread = nullptr; std::shared_ptr selected_thread = nullptr; std::shared_ptr current_thread_prev = nullptr; std::shared_ptr selected_thread_set = nullptr; std::shared_ptr idle_thread = nullptr; + std::shared_ptr switch_fiber = nullptr; + Core::System& system; u64 last_context_switch_time = 0; u64 idle_selection_count = 0; -- cgit v1.2.3 From a33fbaddec5d516328d7cd179114dcf0b93cfb69 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 14:56:05 -0400 Subject: Core: Correct rebase. --- src/core/hle/kernel/scheduler.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index aa1f1a305..ae89e908f 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -552,8 +552,7 @@ void GlobalScheduler::Unlock() { EnableInterruptAndSchedule(cores_pending_reschedule, leaving_thread); } -Scheduler::Scheduler(Core::System& system, std::size_t core_id) - : system(system), core_id(core_id) { +Scheduler::Scheduler(Core::System& system, std::size_t core_id) : system(system), core_id(core_id) { switch_fiber = std::make_shared(std::function(OnSwitch), this); } @@ -601,9 +600,10 @@ void Scheduler::SwitchContextStep2() { // Load context of new thread Process* const previous_process = - previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; + previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; if (new_thread) { + auto& cpu_core = system.ArmInterface(core_id); new_thread->context_guard.lock(); cpu_core.Lock(); ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), @@ -619,7 +619,6 @@ void Scheduler::SwitchContextStep2() { system.Kernel().MakeCurrentProcess(thread_owner_process); } if (!new_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); cpu_core.LoadContext(new_thread->GetContext32()); cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); @@ -651,12 +650,12 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { + auto& cpu_core = system.ArmInterface(core_id); if (!previous_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); cpu_core.SaveContext(previous_thread->GetContext32()); cpu_core.SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. - previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); + previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); cpu_core.ClearExclusiveState(); } if (previous_thread->GetStatus() == ThreadStatus::Running) { -- cgit v1.2.3 From 19847d4d42e061a24086fe90d62382a1ff198322 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 19:30:37 -0400 Subject: Scheduler: Correct assert. --- src/core/hle/kernel/scheduler.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index ae89e908f..4e2a5adf3 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -606,10 +606,8 @@ void Scheduler::SwitchContextStep2() { auto& cpu_core = system.ArmInterface(core_id); new_thread->context_guard.lock(); cpu_core.Lock(); - ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), - "Thread must be assigned to this core."); - ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready, - "Thread must be ready to become running."); + ASSERT_MSG(new_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, + "Thread must be runnable."); // Cancel any outstanding wakeup events for this thread new_thread->SetIsRunning(true); -- cgit v1.2.3 From 3de33348e41ab824eb13f202eccc29d5be2a6d42 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 20:20:36 -0400 Subject: Scheduler: Protect on closed threads. --- src/core/hle/kernel/scheduler.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 4e2a5adf3..74d3731fc 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -604,7 +604,6 @@ void Scheduler::SwitchContextStep2() { if (new_thread) { auto& cpu_core = system.ArmInterface(core_id); - new_thread->context_guard.lock(); cpu_core.Lock(); ASSERT_MSG(new_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, "Thread must be runnable."); @@ -685,13 +684,24 @@ void Scheduler::OnSwitch(void* this_scheduler) { void Scheduler::SwitchToCurrent() { while (true) { - std::shared_ptr next_context; - if (current_thread != nullptr) { - next_context = current_thread->GetHostContext(); - } else { - next_context = idle_thread->GetHostContext(); + guard.lock(); + selected_thread = selected_thread_set; + current_thread = selected_thread; + guard.unlock(); + while (!is_context_switch_pending) { + current_thread->context_guard.lock(); + if (current_thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { + current_thread->context_guard.unlock(); + break; + } + std::shared_ptr next_context; + if (current_thread != nullptr) { + next_context = current_thread->GetHostContext(); + } else { + next_context = idle_thread->GetHostContext(); + } + Common::Fiber::YieldTo(switch_fiber, next_context); } - Common::Fiber::YieldTo(switch_fiber, next_context); } } -- cgit v1.2.3 From 6ed28e15fa9f4c727cf24990c35b13a35547d943 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 20:36:05 -0400 Subject: Scheduler: Fix HLE Threads on guard --- src/core/hle/kernel/scheduler.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 74d3731fc..d7529360c 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -689,10 +689,12 @@ void Scheduler::SwitchToCurrent() { current_thread = selected_thread; guard.unlock(); while (!is_context_switch_pending) { - current_thread->context_guard.lock(); - if (current_thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { - current_thread->context_guard.unlock(); - break; + if (current_thread != nullptr) { + current_thread->context_guard.lock(); + if (current_thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { + current_thread->context_guard.unlock(); + break; + } } std::shared_ptr next_context; if (current_thread != nullptr) { -- cgit v1.2.3 From 44cb9997b3bf3b1e16b05c2b115c7c4ad5e37dd1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 22:58:56 -0400 Subject: Scheduler: Correct locking for hle threads. --- src/core/hle/kernel/scheduler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index d7529360c..f020438fb 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -687,9 +687,10 @@ void Scheduler::SwitchToCurrent() { guard.lock(); selected_thread = selected_thread_set; current_thread = selected_thread; + is_context_switch_pending = false; guard.unlock(); while (!is_context_switch_pending) { - if (current_thread != nullptr) { + if (current_thread != nullptr && !current_thread->IsHLEThread()) { current_thread->context_guard.lock(); if (current_thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { current_thread->context_guard.unlock(); -- cgit v1.2.3 From a66c61ca2de61e3a46fa857cf8afea359b2fb8eb Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 10:24:46 -0400 Subject: SCC: Small corrections to CancelSynchronization --- src/core/hle/kernel/synchronization.cpp | 2 ++ src/core/hle/kernel/thread.cpp | 5 +++-- src/core/hle/kernel/thread.h | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index ac43a7094..a7e3fbe92 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -74,7 +74,9 @@ std::pair Synchronization::WaitFor( thread->SetSynchronizationObjects(&sync_objects); thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); thread->SetStatus(ThreadStatus::WaitSynch); + thread->SetWaitingSync(true); } + thread->SetWaitingSync(false); if (event_handle != InvalidHandle) { auto& time_manager = kernel.TimeManager(); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index fb1751860..e8962a0d8 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -139,13 +139,14 @@ ResultCode Thread::Start() { void Thread::CancelWait() { SchedulerLock lock(kernel); - if (GetSchedulingStatus() != ThreadSchedStatus::Paused) { + if (GetSchedulingStatus() != ThreadSchedStatus::Paused || !is_waiting_on_sync) { is_sync_cancelled = true; return; } + //TODO(Blinkhawk): Implement cancel of server session is_sync_cancelled = false; SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); - ResumeFromWait(); + SetStatus(ThreadStatus::Ready); } static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index e8355bbd1..d8a983200 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -556,6 +556,14 @@ public: waiting_for_arbitration = set; } + bool IsWaitingSync() const { + return is_waiting_on_sync; + } + + void SetWaitingSync(bool is_waiting) { + is_waiting_on_sync = is_waiting; + } + private: friend class GlobalScheduler; friend class Scheduler; @@ -650,6 +658,7 @@ private: u32 scheduling_state = 0; bool is_running = false; + bool is_waiting_on_sync = false; bool is_sync_cancelled = false; bool will_be_terminated{}; -- cgit v1.2.3 From 83c7ba1ef700eff17f30b6c2782db77710dc322e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 12:44:35 -0400 Subject: SVC: Correct SetThreadActivity. --- src/core/hle/kernel/scheduler.cpp | 9 +++--- src/core/hle/kernel/svc.cpp | 5 +--- src/core/hle/kernel/thread.cpp | 61 +++++++++++++++++++++++++-------------- src/core/hle/kernel/thread.h | 22 +++++++++----- 4 files changed, 59 insertions(+), 38 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index f020438fb..a37b992ec 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -417,8 +417,7 @@ void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { } ASSERT(is_locked); - if (static_cast(old_flags & static_cast(ThreadSchedMasks::LowMask)) == - ThreadSchedStatus::Runnable) { + if (old_flags == static_cast(ThreadSchedStatus::Runnable)) { // In this case the thread was running, now it's pausing/exitting if (thread->processor_id >= 0) { Unschedule(thread->current_priority, static_cast(thread->processor_id), thread); @@ -430,7 +429,7 @@ void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { Unsuggest(thread->current_priority, core, thread); } } - } else if (thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable) { + } else if (thread->scheduling_state == static_cast(ThreadSchedStatus::Runnable)) { // The thread is now set to running from being stopped if (thread->processor_id >= 0) { Schedule(thread->current_priority, static_cast(thread->processor_id), thread); @@ -448,7 +447,7 @@ void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { } void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priority) { - if (thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { + if (thread->scheduling_state != static_cast(ThreadSchedStatus::Runnable)) { return; } ASSERT(is_locked); @@ -486,7 +485,7 @@ void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priorit void GlobalScheduler::AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinity_mask, s32 old_core) { - if (thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable || + if (thread->scheduling_state != static_cast(ThreadSchedStatus::Runnable) || thread->current_priority >= THREADPRIO_COUNT) { return; } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 718462b2b..da2f90a1d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1012,7 +1012,6 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size /// Sets the thread activity static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); - UNIMPLEMENTED(); if (activity > static_cast(ThreadActivity::Paused)) { return ERR_INVALID_ENUM_VALUE; } @@ -1039,9 +1038,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act return ERR_BUSY; } - thread->SetActivity(static_cast(activity)); - - return RESULT_SUCCESS; + return thread->SetActivity(static_cast(activity)); } /// Gets the thread context diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index e8962a0d8..b99e3b7a5 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -113,20 +113,11 @@ void Thread::ResumeFromWait() { return; } - if (activity == ThreadActivity::Paused) { - SetStatus(ThreadStatus::Paused); - return; - } - SetStatus(ThreadStatus::Ready); } void Thread::OnWakeUp() { SchedulerLock lock(kernel); - if (activity == ThreadActivity::Paused) { - SetStatus(ThreadStatus::Paused); - return; - } SetStatus(ThreadStatus::Ready); } @@ -143,7 +134,7 @@ void Thread::CancelWait() { is_sync_cancelled = true; return; } - //TODO(Blinkhawk): Implement cancel of server session + // TODO(Blinkhawk): Implement cancel of server session is_sync_cancelled = false; SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); SetStatus(ThreadStatus::Ready); @@ -407,19 +398,31 @@ bool Thread::InvokeHLECallback(std::shared_ptr thread) { return hle_callback(std::move(thread)); } -void Thread::SetActivity(ThreadActivity value) { - activity = value; +ResultCode Thread::SetActivity(ThreadActivity value) { + SchedulerLock lock(kernel); + + auto sched_status = GetSchedulingStatus(); + + if (sched_status != ThreadSchedStatus::Runnable && sched_status != ThreadSchedStatus::Paused) { + return ERR_INVALID_STATE; + } + + if (IsPendingTermination()) { + return RESULT_SUCCESS; + } if (value == ThreadActivity::Paused) { - // Set status if not waiting - if (status == ThreadStatus::Ready || status == ThreadStatus::Running) { - SetStatus(ThreadStatus::Paused); - kernel.PrepareReschedule(processor_id); + if (pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag) != 0) { + return ERR_INVALID_STATE; } - } else if (status == ThreadStatus::Paused) { - // Ready to reschedule - ResumeFromWait(); + AddSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); + } else { + if (pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag) == 0) { + return ERR_INVALID_STATE; + } + RemoveSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); } + return RESULT_SUCCESS; } ResultCode Thread::Sleep(s64 nanoseconds) { @@ -460,11 +463,27 @@ ResultCode Thread::YieldAndWaitForLoadBalancing() { return RESULT_SUCCESS; } +void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { + const u32 old_state = scheduling_state; + pausing_state |= static_cast(flag); + const u32 base_scheduling = static_cast(GetSchedulingStatus()); + scheduling_state = base_scheduling | pausing_state; + kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); +} + +void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { + const u32 old_state = scheduling_state; + pausing_state &= ~static_cast(flag); + const u32 base_scheduling = static_cast(GetSchedulingStatus()); + scheduling_state = base_scheduling | pausing_state; + kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); +} + void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { - const u32 old_flags = scheduling_state; + const u32 old_state = scheduling_state; scheduling_state = (scheduling_state & static_cast(ThreadSchedMasks::HighMask)) | static_cast(new_status); - kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_flags); + kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); } void Thread::SetCurrentPriority(u32 new_priority) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index d8a983200..0a8f7bb65 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -497,11 +497,7 @@ public: return affinity_mask; } - ThreadActivity GetActivity() const { - return activity; - } - - void SetActivity(ThreadActivity value); + ResultCode SetActivity(ThreadActivity value); /// Sleeps this thread for the given amount of nanoseconds. ResultCode Sleep(s64 nanoseconds); @@ -564,11 +560,22 @@ public: is_waiting_on_sync = is_waiting; } + bool IsPendingTermination() const { + return will_be_terminated || GetSchedulingStatus() == ThreadSchedStatus::Exited; + } + + bool IsPaused() const { + return pausing_state != 0; + } + private: friend class GlobalScheduler; friend class Scheduler; void SetSchedulingStatus(ThreadSchedStatus new_status); + void AddSchedulingFlag(ThreadSchedFlags flag); + void RemoveSchedulingFlag(ThreadSchedFlags flag); + void SetCurrentPriority(u32 new_priority); void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); @@ -650,18 +657,17 @@ private: u32 ideal_core{0xFFFFFFFF}; u64 affinity_mask{0x1}; - ThreadActivity activity = ThreadActivity::Normal; - s32 ideal_core_override = -1; u64 affinity_mask_override = 0x1; u32 affinity_override_count = 0; u32 scheduling_state = 0; + u32 pausing_state = 0; bool is_running = false; bool is_waiting_on_sync = false; bool is_sync_cancelled = false; - bool will_be_terminated{}; + bool will_be_terminated = false; std::string name; }; -- cgit v1.2.3 From 725bac14044b2645b9ce912d1b1e2c9c2a96818b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 13:27:27 -0400 Subject: Scheduler: Remove arm_interface lock and a few corrections. --- src/core/hle/kernel/scheduler.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index a37b992ec..affc2fbed 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -463,9 +463,7 @@ void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priorit } if (thread->processor_id >= 0) { - // TODO(Blinkhawk): compare it with current thread running on current core, instead of - // checking running - if (thread->IsRunning()) { + if (thread == kernel.CurrentScheduler().GetCurrentThread()) { SchedulePrepend(thread->current_priority, static_cast(thread->processor_id), thread); } else { @@ -602,8 +600,6 @@ void Scheduler::SwitchContextStep2() { previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; if (new_thread) { - auto& cpu_core = system.ArmInterface(core_id); - cpu_core.Lock(); ASSERT_MSG(new_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, "Thread must be runnable."); @@ -615,6 +611,7 @@ void Scheduler::SwitchContextStep2() { system.Kernel().MakeCurrentProcess(thread_owner_process); } if (!new_thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); cpu_core.LoadContext(new_thread->GetContext32()); cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); @@ -646,8 +643,8 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { - auto& cpu_core = system.ArmInterface(core_id); if (!previous_thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); cpu_core.SaveContext(previous_thread->GetContext32()); cpu_core.SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. @@ -659,7 +656,6 @@ void Scheduler::SwitchContext() { } previous_thread->SetIsRunning(false); previous_thread->context_guard.unlock(); - cpu_core.Unlock(); } std::shared_ptr old_context; -- cgit v1.2.3 From 535c542d84ea56b5710bf84af3fba6272913f48e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 13:37:47 -0400 Subject: SVC: WaitSynchronization add Termination Pending Result. --- src/core/hle/kernel/errors.h | 1 + src/core/hle/kernel/synchronization.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 29bfa3621..d4e5d88cf 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -12,6 +12,7 @@ namespace Kernel { constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7}; constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14}; +constexpr ResultCode ERR_THREAD_TERMINATING{ErrorModule::Kernel, 59}; constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101}; constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102}; constexpr ResultCode ERR_OUT_OF_RESOURCES{ErrorModule::Kernel, 103}; diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index a7e3fbe92..4323fc120 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -59,7 +59,10 @@ std::pair Synchronization::WaitFor( return {RESULT_TIMEOUT, InvalidHandle}; } - /// TODO(Blinkhawk): Check for termination pending + if (thread->IsPendingTermination()) { + lock.CancelSleep(); + return {ERR_THREAD_TERMINATING, InvalidHandle}; + } if (thread->IsSyncCancelled()) { thread->SetSyncCancelled(false); -- cgit v1.2.3 From cd1c38be8d15d3caf52f566a9e8dc20504c61068 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 18:59:42 -0400 Subject: ARM/Memory: Correct Exclusive Monitor and Implement Exclusive Memory Writes. --- src/core/hle/kernel/address_arbiter.cpp | 6 +++--- src/core/hle/kernel/mutex.cpp | 5 +++-- src/core/hle/kernel/svc.cpp | 2 +- src/core/hle/kernel/thread.cpp | 6 +++--- 4 files changed, 10 insertions(+), 9 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index ebabde921..07acabc1d 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -90,7 +90,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 auto& monitor = system.Monitor(); u32 current_value; do { - monitor.SetExclusive(current_core, address); + monitor.SetExclusive32(current_core, address); current_value = memory.Read32(address); if (current_value != value) { @@ -120,7 +120,7 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a auto& monitor = system.Monitor(); s32 updated_value; do { - monitor.SetExclusive(current_core, address); + monitor.SetExclusive32(current_core, address); updated_value = memory.Read32(address); if (updated_value != value) { @@ -191,7 +191,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 const std::size_t current_core = system.CurrentCoreIndex(); auto& monitor = system.Monitor(); do { - monitor.SetExclusive(current_core, address); + monitor.SetExclusive32(current_core, address); current_value = static_cast(memory.Read32(address)); if (should_decrement) { decrement_value = current_value - 1; diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index ebe3f6050..16c95782a 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -10,6 +10,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/arm/exclusive_monitor.h" +#include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -138,7 +139,7 @@ std::pair> Mutex::Unlock(std::shared_ptr> Mutex::Unlock(std::shared_ptrResumeFromWait(); do { - monitor.SetExclusive(current_core, address); + monitor.SetExclusive32(current_core, address); } while (!monitor.ExclusiveWrite32(current_core, address, mutex_value)); return {RESULT_SUCCESS, new_owner}; } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index da2f90a1d..371beed0d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1641,7 +1641,7 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ u32 update_val = 0; const VAddr mutex_address = thread->GetMutexWaitAddress(); do { - monitor.SetExclusive(current_core, mutex_address); + monitor.SetExclusive32(current_core, mutex_address); // If the mutex is not yet acquired, acquire it. mutex_val = memory.Read32(mutex_address); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index b99e3b7a5..51cc5dcca 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -236,7 +236,7 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); } thread->host_context = - std::make_shared(std::move(thread_start_func), thread_start_parameter); + std::make_shared(std::move(thread_start_func), thread_start_parameter); return MakeResult>(std::move(thread)); } @@ -412,12 +412,12 @@ ResultCode Thread::SetActivity(ThreadActivity value) { } if (value == ThreadActivity::Paused) { - if (pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag) != 0) { + if ((pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag)) != 0) { return ERR_INVALID_STATE; } AddSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); } else { - if (pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag) == 0) { + if ((pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag)) == 0) { return ERR_INVALID_STATE; } RemoveSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); -- cgit v1.2.3 From 445b4342b3db8ab447aaa9e5422d2a7a3a45e5ac Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 19:04:02 -0400 Subject: Mutex: Revert workaround due to poor exclusive memory. --- src/core/hle/kernel/mutex.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 16c95782a..5a96d5e90 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -9,7 +9,6 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/arm/exclusive_monitor.h" #include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" @@ -135,12 +134,8 @@ std::pair> Mutex::Unlock(std::shared_ptr> Mutex::Unlock(std::shared_ptrSetLockOwner(nullptr); new_owner->ResumeFromWait(); - do { - monitor.SetExclusive32(current_core, address); - } while (!monitor.ExclusiveWrite32(current_core, address, mutex_value)); + system.Memory().Write32(address, mutex_value); return {RESULT_SUCCESS, new_owner}; } -- cgit v1.2.3 From 4217e58a103049675df27f404171f73fa0be8537 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 8 Mar 2020 11:25:50 -0400 Subject: Scheduler: Correct yields. --- src/core/hle/kernel/scheduler.cpp | 28 +++++++++++++++++++++------- src/core/hle/kernel/thread.h | 4 ++++ 2 files changed, 25 insertions(+), 7 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index affc2fbed..ab17204bb 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -147,9 +147,11 @@ bool GlobalScheduler::YieldThread(Thread* yielding_thread) { const u32 priority = yielding_thread->GetPriority(); // Yield the thread - const Thread* const winner = scheduled_queue[core_id].front(priority); - ASSERT_MSG(yielding_thread == winner, "Thread yielding without being in front"); - scheduled_queue[core_id].yield(priority); + Reschedule(priority, core_id, yielding_thread); + const Thread* const winner = scheduled_queue[core_id].front(); + if (kernel.GetCurrentHostThreadID() != core_id) { + is_reselection_pending.store(true, std::memory_order_release); + } return AskForReselectionOrMarkRedundant(yielding_thread, winner); } @@ -162,9 +164,7 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { const u32 priority = yielding_thread->GetPriority(); // Yield the thread - ASSERT_MSG(yielding_thread == scheduled_queue[core_id].front(priority), - "Thread yielding without being in front"); - scheduled_queue[core_id].yield(priority); + Reschedule(priority, core_id, yielding_thread); std::array current_threads; for (std::size_t i = 0; i < current_threads.size(); i++) { @@ -200,6 +200,10 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { winner = next_thread; } + if (kernel.GetCurrentHostThreadID() != core_id) { + is_reselection_pending.store(true, std::memory_order_release); + } + return AskForReselectionOrMarkRedundant(yielding_thread, winner); } @@ -239,6 +243,12 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread } else { winner = yielding_thread; } + } else { + winner = scheduled_queue[i].front(); + } + + if (kernel.GetCurrentHostThreadID() != core_id) { + is_reselection_pending.store(true, std::memory_order_release); } return AskForReselectionOrMarkRedundant(yielding_thread, winner); @@ -687,7 +697,11 @@ void Scheduler::SwitchToCurrent() { while (!is_context_switch_pending) { if (current_thread != nullptr && !current_thread->IsHLEThread()) { current_thread->context_guard.lock(); - if (current_thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { + if (!current_thread->IsRunnable()) { + current_thread->context_guard.unlock(); + break; + } + if (current_thread->GetProcessorID() != core_id) { current_thread->context_guard.unlock(); break; } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 0a8f7bb65..953b023b5 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -524,6 +524,10 @@ public: static_cast(ThreadSchedMasks::LowMask)); } + bool IsRunnable() const { + return scheduling_state == static_cast(ThreadSchedStatus::Runnable); + } + bool IsRunning() const { return is_running; } -- cgit v1.2.3 From 6515c6e8c699584528486341579cf3a8dde3eea4 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 8 Mar 2020 12:51:24 -0400 Subject: Kernel: Fixes, corrections and asserts to scheduler and different svcs. --- src/core/hle/kernel/address_arbiter.cpp | 27 ++++++++++++--------------- src/core/hle/kernel/kernel.cpp | 1 + src/core/hle/kernel/scheduler.cpp | 3 ++- src/core/hle/kernel/scheduler.h | 5 +++-- src/core/hle/kernel/svc.cpp | 27 ++++++++++++++------------- src/core/hle/kernel/synchronization.cpp | 10 ++++++---- src/core/hle/kernel/time_manager.cpp | 2 -- src/core/hle/kernel/time_manager.h | 1 - 8 files changed, 38 insertions(+), 38 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 07acabc1d..e8f22b598 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -34,19 +34,9 @@ void AddressArbiter::WakeThreads(const std::vector>& wai // Signal the waiting threads. for (std::size_t i = 0; i < last; i++) { - if (waiting_threads[i]->GetStatus() != ThreadStatus::WaitArb) { - last++; - last = std::min(waiting_threads.size(), last); - continue; - } - - time_manager.CancelTimeEvent(waiting_threads[i].get()); - - ASSERT(waiting_threads[i]->GetStatus() == ThreadStatus::WaitArb); waiting_threads[i]->SetSynchronizationResults(nullptr, RESULT_SUCCESS); RemoveThread(waiting_threads[i]); waiting_threads[i]->WaitForArbitration(false); - waiting_threads[i]->SetArbiterWaitAddress(0); waiting_threads[i]->ResumeFromWait(); } } @@ -172,20 +162,25 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 { SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); + if (current_thread->IsPendingTermination()) { + lock.CancelSleep(); + return ERR_THREAD_TERMINATING; + } + // Ensure that we can read the address. if (!memory.IsValidVirtualAddress(address)) { lock.CancelSleep(); return ERR_INVALID_ADDRESS_STATE; } - /// TODO(Blinkhawk): Check termination pending. - s32 current_value = static_cast(memory.Read32(address)); if (current_value >= value) { lock.CancelSleep(); return ERR_INVALID_STATE; } + current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + s32 decrement_value; const std::size_t current_core = system.CurrentCoreIndex(); @@ -207,7 +202,6 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 return RESULT_TIMEOUT; } - current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); current_thread->SetArbiterWaitAddress(address); InsertThread(SharedFrom(current_thread)); current_thread->SetStatus(ThreadStatus::WaitArb); @@ -239,14 +233,17 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t { SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); + if (current_thread->IsPendingTermination()) { + lock.CancelSleep(); + return ERR_THREAD_TERMINATING; + } + // Ensure that we can read the address. if (!memory.IsValidVirtualAddress(address)) { lock.CancelSleep(); return ERR_INVALID_ADDRESS_STATE; } - /// TODO(Blinkhawk): Check termination pending. - s32 current_value = static_cast(memory.Read32(address)); if (current_value != value) { lock.CancelSleep(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index ba051a7d8..721ab1e70 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -49,6 +49,7 @@ namespace Kernel { * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time */ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_late) { + UNREACHABLE(); const auto proper_handle = static_cast(thread_handle); const auto& system = Core::System::GetInstance(); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index ab17204bb..5322f0aae 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -133,6 +133,7 @@ u32 GlobalScheduler::SelectThreads() { u32 cores_needing_context_switch{}; for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { Scheduler& sched = kernel.Scheduler(core); + ASSERT(top_threads[core] == nullptr || top_threads[core]->GetProcessorID() == core); if (update_thread(top_threads[core], sched)) { cores_needing_context_switch |= (1ul << core); } @@ -244,7 +245,7 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread winner = yielding_thread; } } else { - winner = scheduled_queue[i].front(); + winner = scheduled_queue[core_id].front(); } if (kernel.GetCurrentHostThreadID() != core_id) { diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 728cca802..5e062bf59 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -16,7 +16,7 @@ #include "core/hle/kernel/thread.h" namespace Common { - class Fiber; +class Fiber; } namespace Core { @@ -133,7 +133,8 @@ private: /// and reschedules current core if needed. void Unlock(); - void EnableInterruptAndSchedule(u32 cores_pending_reschedule, Core::EmuThreadHandle global_thread); + void EnableInterruptAndSchedule(u32 cores_pending_reschedule, + Core::EmuThreadHandle global_thread); /** * Add a thread to the suggested queue of a cpu core. Suggested threads may be diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 371beed0d..aad2ac549 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1562,6 +1562,11 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + if (thread->IsPendingTermination()) { + lock.CancelSleep(); + return ERR_THREAD_TERMINATING; + } + const auto release_result = current_process->GetMutex().Release(mutex_addr); if (release_result.IsError()) { lock.CancelSleep(); @@ -1588,6 +1593,11 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add { SchedulerLock lock(kernel); + auto* owner = current_thread->GetLockOwner(); + if (owner != nullptr) { + owner->RemoveMutexWaiter(SharedFrom(current_thread)); + } + current_process->RemoveConditionVariableThread(SharedFrom(current_thread)); } // Note: Deliberately don't attempt to inherit the lock owner's priority. @@ -1618,19 +1628,10 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ for (std::size_t index = 0; index < last; ++index) { auto& thread = waiting_threads[index]; - if (thread->GetStatus() != ThreadStatus::WaitCondVar) { - last++; - last = std::min(waiting_threads.size(), last); - continue; - } - - time_manager.CancelTimeEvent(thread.get()); - ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr); // liberate Cond Var Thread. current_process->RemoveConditionVariableThread(thread); - thread->SetCondVarWaitAddress(0); const std::size_t current_core = system.CurrentCoreIndex(); auto& monitor = system.Monitor(); @@ -1655,9 +1656,6 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ monitor.ClearExclusive(); if (mutex_val == 0) { // We were able to acquire the mutex, resume this thread. - ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); - thread->ResumeFromWait(); - auto* const lock_owner = thread->GetLockOwner(); if (lock_owner != nullptr) { lock_owner->RemoveMutexWaiter(thread); @@ -1665,13 +1663,16 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ thread->SetLockOwner(nullptr); thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); + thread->ResumeFromWait(); } else { // The mutex is already owned by some other thread, make this thread wait on it. const Handle owner_handle = static_cast(mutex_val & Mutex::MutexOwnerMask); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); auto owner = handle_table.Get(owner_handle); ASSERT(owner); - thread->SetStatus(ThreadStatus::WaitMutex); + if (thread->GetStatus() == ThreadStatus::WaitCondVar) { + thread->SetStatus(ThreadStatus::WaitMutex); + } owner->AddMutexWaiter(thread); } diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index 4323fc120..275bf11cc 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -23,9 +23,10 @@ void Synchronization::SignalObject(SynchronizationObject& obj) const { if (obj.IsSignaled()) { for (auto thread : obj.GetWaitingThreads()) { if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { + ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); + ASSERT(thread->IsWaitingSync()); thread->SetSynchronizationResults(&obj, RESULT_SUCCESS); thread->ResumeFromWait(); - time_manager.CancelTimeEvent(thread.get()); } } obj.ClearWaitingThreads(); @@ -91,10 +92,11 @@ std::pair Synchronization::WaitFor( ResultCode signaling_result = thread->GetSignalingResult(); SynchronizationObject* signaling_object = thread->GetSignalingObject(); thread->SetSynchronizationObjects(nullptr); + auto shared_thread = SharedFrom(thread); for (auto& obj : sync_objects) { - obj->RemoveWaitingThread(SharedFrom(thread)); + obj->RemoveWaitingThread(shared_thread); } - if (signaling_result == RESULT_SUCCESS) { + if (signaling_object != nullptr) { const auto itr = std::find_if( sync_objects.begin(), sync_objects.end(), [signaling_object](const std::shared_ptr& object) { @@ -103,7 +105,7 @@ std::pair Synchronization::WaitFor( ASSERT(itr != sync_objects.end()); signaling_object->Acquire(thread); const u32 index = static_cast(std::distance(sync_objects.begin(), itr)); - return {RESULT_SUCCESS, index}; + return {signaling_result, index}; } return {signaling_result, -1}; } diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index dab5fc4c6..cc228f5f7 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -22,7 +22,6 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} { if (cancelled_events[proper_handle]) { return; } - event_fired[proper_handle] = true; std::shared_ptr thread = this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); thread->OnWakeUp(); @@ -39,7 +38,6 @@ void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 event_handle = InvalidHandle; } cancelled_events[event_handle] = false; - event_fired[event_handle] = false; } void TimeManager::UnscheduleTimeEvent(Handle event_handle) { diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h index 3080ac838..307a18765 100644 --- a/src/core/hle/kernel/time_manager.h +++ b/src/core/hle/kernel/time_manager.h @@ -42,7 +42,6 @@ private: Core::System& system; std::shared_ptr time_manager_event_type; std::unordered_map cancelled_events; - std::unordered_map event_fired; }; } // namespace Kernel -- cgit v1.2.3 From 9e9c287f8b24ce9a932490cc35b3d0b5f58bb7a3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 8 Mar 2020 16:20:05 -0400 Subject: Kernel: Corrections to TimeManager, Scheduler and Mutex. --- src/core/hle/kernel/mutex.cpp | 3 +-- src/core/hle/kernel/scheduler.cpp | 2 +- src/core/hle/kernel/time_manager.cpp | 5 +++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 5a96d5e90..32dc1ffae 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -35,8 +35,6 @@ static std::pair, u32> GetHighestPriorityMutexWaitingThr if (thread->GetMutexWaitAddress() != mutex_addr) continue; - ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); - ++num_waiters; if (highest_priority_thread == nullptr || thread->GetPriority() < highest_priority_thread->GetPriority()) { @@ -50,6 +48,7 @@ static std::pair, u32> GetHighestPriorityMutexWaitingThr /// Update the mutex owner field of all threads waiting on the mutex to point to the new owner. static void TransferMutexOwnership(VAddr mutex_addr, std::shared_ptr current_thread, std::shared_ptr new_owner) { + current_thread->RemoveMutexWaiter(new_owner); const auto threads = current_thread->GetMutexWaitingThreads(); for (const auto& thread : threads) { if (thread->GetMutexWaitAddress() != mutex_addr) diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 5322f0aae..98fbb8fe5 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -93,7 +93,7 @@ u32 GlobalScheduler::SelectThreads() { iter++; s32 suggested_core_id = suggested->GetProcessorID(); Thread* top_thread = - suggested_core_id > 0 ? top_threads[suggested_core_id] : nullptr; + suggested_core_id >= 0 ? top_threads[suggested_core_id] : nullptr; if (top_thread != suggested) { if (top_thread != nullptr && top_thread->GetPriority() < THREADPRIO_MAX_CORE_MIGRATION) { diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index cc228f5f7..941305e8e 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -32,8 +32,9 @@ void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 event_handle = timetask->GetGlobalHandle(); if (nanoseconds > 0) { ASSERT(timetask); - const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); - system.CoreTiming().ScheduleEvent(cycles, time_manager_event_type, event_handle); + ASSERT(timetask->GetStatus() != ThreadStatus::Ready); + ASSERT(timetask->GetStatus() != ThreadStatus::WaitMutex); + system.CoreTiming().ScheduleEvent(nanoseconds, time_manager_event_type, event_handle); } else { event_handle = InvalidHandle; } -- cgit v1.2.3 From 391f5f360d4144c21d65b998dd4e467b56533f78 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 8 Mar 2020 21:13:18 -0400 Subject: Scheduler: Set last running time on thread. --- src/core/hle/kernel/scheduler.cpp | 2 ++ src/core/hle/kernel/thread.cpp | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 98fbb8fe5..d68d86cdf 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -616,6 +616,7 @@ void Scheduler::SwitchContextStep2() { // Cancel any outstanding wakeup events for this thread new_thread->SetIsRunning(true); + new_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); auto* const thread_owner_process = current_thread->GetOwnerProcess(); if (previous_process != thread_owner_process && thread_owner_process != nullptr) { @@ -654,6 +655,7 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { + previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); if (!previous_thread->IsHLEThread()) { auto& cpu_core = system.ArmInterface(core_id); cpu_core.SaveContext(previous_thread->GetContext32()); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 51cc5dcca..fc6c0bc85 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -295,10 +295,6 @@ void Thread::SetStatus(ThreadStatus new_status) { break; } - if (status == ThreadStatus::Running) { - last_running_ticks = Core::System::GetInstance().CoreTiming().GetCPUTicks(); - } - status = new_status; } -- cgit v1.2.3 From ab9aae28bf5daa5fa7105bb4ef41b6d0b3c9cdc1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 8 Mar 2020 22:39:41 -0400 Subject: General: Initial Setup for Single Core. --- src/core/hle/kernel/kernel.cpp | 19 +++++++++++++++++++ src/core/hle/kernel/kernel.h | 3 +++ 2 files changed, 22 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 721ab1e70..4a091ea38 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -113,6 +113,10 @@ struct KernelCore::Impl { explicit Impl(Core::System& system, KernelCore& kernel) : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {} + void SetMulticore(bool is_multicore) { + this->is_multicore = is_multicore; + } + void Initialize(KernelCore& kernel) { Shutdown(); @@ -237,6 +241,9 @@ struct KernelCore::Impl { void RegisterCoreThread(std::size_t core_id) { std::unique_lock lock{register_thread_mutex}; + if (!is_multicore) { + single_core_thread_id = std::this_thread::get_id(); + } const std::thread::id this_id = std::this_thread::get_id(); const auto it = host_thread_ids.find(this_id); ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); @@ -258,6 +265,11 @@ struct KernelCore::Impl { u32 GetCurrentHostThreadID() const { const std::thread::id this_id = std::this_thread::get_id(); + if (!is_multicore) { + if (single_core_thread_id == this_id) { + return static_cast(system.GetCpuManager().CurrentCore()); + } + } const auto it = host_thread_ids.find(this_id); if (it == host_thread_ids.end()) { return Core::INVALID_HOST_THREAD_ID; @@ -378,6 +390,9 @@ struct KernelCore::Impl { std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; + bool is_multicore{}; + std::thread::id single_core_thread_id{}; + // System context Core::System& system; }; @@ -387,6 +402,10 @@ KernelCore::~KernelCore() { Shutdown(); } +void KernelCore::SetMulticore(bool is_multicore) { + impl->SetMulticore(is_multicore); +} + void KernelCore::Initialize() { impl->Initialize(*this); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 5d32a8329..162bbd2f8 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -65,6 +65,9 @@ public: KernelCore(KernelCore&&) = delete; KernelCore& operator=(KernelCore&&) = delete; + /// Sets if emulation is multicore or single core, must be set before Initialize + void SetMulticore(bool is_multicore); + /// Resets the kernel to a clean slate for use. void Initialize(); -- cgit v1.2.3 From 8a78fc25802b8f69d073b703728a3501c98bf5e8 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 9 Mar 2020 10:51:05 -0400 Subject: Synchronization: Correct wide Assertion. --- src/core/hle/kernel/synchronization.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index 275bf11cc..851b702a5 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -23,8 +23,10 @@ void Synchronization::SignalObject(SynchronizationObject& obj) const { if (obj.IsSignaled()) { for (auto thread : obj.GetWaitingThreads()) { if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { - ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); - ASSERT(thread->IsWaitingSync()); + if (thread->GetStatus() != ThreadStatus::WaitHLEEvent) { + ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); + ASSERT(thread->IsWaitingSync()); + } thread->SetSynchronizationResults(&obj, RESULT_SUCCESS); thread->ResumeFromWait(); } -- cgit v1.2.3 From a439cdf22ea50f0e39cb51f6dff15fee3b495d16 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 10 Mar 2020 11:50:33 -0400 Subject: CPU_Manager: Unload/Reload threads on preemption on SingleCore --- src/core/hle/kernel/scheduler.cpp | 42 +++++++++++++++++++++++++++++++++++++++ src/core/hle/kernel/scheduler.h | 10 ++++++++++ 2 files changed, 52 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index d68d86cdf..00322d997 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -602,6 +602,48 @@ void Scheduler::OnThreadStart() { SwitchContextStep2(); } +void Scheduler::Unload() { + Thread* thread = current_thread.get(); + if (thread) { + thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); + thread->SetIsRunning(false); + if (!thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); + cpu_core.SaveContext(thread->GetContext32()); + cpu_core.SaveContext(thread->GetContext64()); + // Save the TPIDR_EL0 system register in case it was modified. + thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); + cpu_core.ClearExclusiveState(); + } + thread->context_guard.unlock(); + } +} + +void Scheduler::Reload() { + Thread* thread = current_thread.get(); + if (thread) { + ASSERT_MSG(thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, + "Thread must be runnable."); + + // Cancel any outstanding wakeup events for this thread + thread->SetIsRunning(true); + thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); + + auto* const thread_owner_process = thread->GetOwnerProcess(); + if (thread_owner_process != nullptr) { + system.Kernel().MakeCurrentProcess(thread_owner_process); + } + if (!thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); + cpu_core.LoadContext(thread->GetContext32()); + cpu_core.LoadContext(thread->GetContext64()); + cpu_core.SetTlsAddress(thread->GetTLSAddress()); + cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); + cpu_core.ClearExclusiveState(); + } + } +} + void Scheduler::SwitchContextStep2() { Thread* previous_thread = current_thread_prev.get(); Thread* new_thread = selected_thread.get(); diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 5e062bf59..f63cc5085 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -210,6 +210,12 @@ public: /// Reschedules to the next available thread (call after current thread is suspended) void TryDoContextSwitch(); + /// The next two are for SingleCore Only. + /// Unload current thread before preempting core. + void Unload(); + /// Reload current thread after core preemption. + void Reload(); + /// Gets the current running thread Thread* GetCurrentThread() const; @@ -230,6 +236,10 @@ public: void OnThreadStart(); + std::shared_ptr ControlContext() { + return switch_fiber; + } + private: friend class GlobalScheduler; -- cgit v1.2.3 From d494b074e8afd3aff7b65afc7b977496be06ccc9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 10 Mar 2020 13:13:39 -0400 Subject: Kernel: Preempt Single core on redudant yields. --- src/core/hle/kernel/kernel.cpp | 4 ++++ src/core/hle/kernel/kernel.h | 2 ++ src/core/hle/kernel/svc.cpp | 23 +++++++++++++++++------ src/core/hle/kernel/thread.cpp | 21 ++++++++++++--------- src/core/hle/kernel/thread.h | 9 +++++---- 5 files changed, 40 insertions(+), 19 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 4a091ea38..2a1b91752 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -642,6 +642,10 @@ void KernelCore::Suspend(bool in_suspention) { } } +bool KernelCore::IsMulticore() const { + return impl->is_multicore; +} + void KernelCore::ExceptionalExit() { exception_exited = true; Suspend(true); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 162bbd2f8..50eeb50ec 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -212,6 +212,8 @@ public: /// Exceptional exit the OS. void ExceptionalExit(); + bool IsMulticore() const; + private: friend class Object; friend class Process; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index aad2ac549..eca92b356 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -19,6 +19,7 @@ #include "core/core_manager.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/cpu_manager.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" @@ -1509,21 +1510,31 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { if (nanoseconds <= 0) { switch (static_cast(nanoseconds)) { - case SleepType::YieldWithoutLoadBalancing: - current_thread->YieldSimple(); + case SleepType::YieldWithoutLoadBalancing: { + auto pair = current_thread->YieldSimple(); + is_redundant = pair.second; break; - case SleepType::YieldWithLoadBalancing: - current_thread->YieldAndBalanceLoad(); + } + case SleepType::YieldWithLoadBalancing: { + auto pair = current_thread->YieldAndBalanceLoad(); + is_redundant = pair.second; break; - case SleepType::YieldAndWaitForLoadBalancing: - current_thread->YieldAndWaitForLoadBalancing(); + } + case SleepType::YieldAndWaitForLoadBalancing: { + auto pair = current_thread->YieldAndWaitForLoadBalancing(); + is_redundant = pair.second; break; + } default: UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); } } else { current_thread->Sleep(nanoseconds); } + + if (is_redundant && !system.Kernel().IsMulticore()) { + system.GetCpuManager().PreemptSingleCore(); + } } /// Wait process wide key atomic diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index fc6c0bc85..1c32552b1 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -435,28 +435,31 @@ ResultCode Thread::Sleep(s64 nanoseconds) { return RESULT_SUCCESS; } -ResultCode Thread::YieldSimple() { +std::pair Thread::YieldSimple() { + bool is_redundant = false; { SchedulerLock lock(kernel); - kernel.GlobalScheduler().YieldThread(this); + is_redundant = kernel.GlobalScheduler().YieldThread(this); } - return RESULT_SUCCESS; + return {RESULT_SUCCESS, is_redundant}; } -ResultCode Thread::YieldAndBalanceLoad() { +std::pair Thread::YieldAndBalanceLoad() { + bool is_redundant = false; { SchedulerLock lock(kernel); - kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this); + is_redundant = kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this); } - return RESULT_SUCCESS; + return {RESULT_SUCCESS, is_redundant}; } -ResultCode Thread::YieldAndWaitForLoadBalancing() { +std::pair Thread::YieldAndWaitForLoadBalancing() { + bool is_redundant = false; { SchedulerLock lock(kernel); - kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this); + is_redundant = kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this); } - return RESULT_SUCCESS; + return {RESULT_SUCCESS, is_redundant}; } void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 953b023b5..9a29875ac 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -6,6 +6,7 @@ #include #include +#include #include #include "common/common_types.h" @@ -503,13 +504,13 @@ public: ResultCode Sleep(s64 nanoseconds); /// Yields this thread without rebalancing loads. - ResultCode YieldSimple(); + std::pair YieldSimple(); /// Yields this thread and does a load rebalancing. - ResultCode YieldAndBalanceLoad(); + std::pair YieldAndBalanceLoad(); /// Yields this thread and if the core is left idle, loads are rebalanced - ResultCode YieldAndWaitForLoadBalancing(); + std::pair YieldAndWaitForLoadBalancing(); void IncrementYieldCount() { yield_count++; @@ -587,7 +588,7 @@ private: ThreadContext32 context_32{}; ThreadContext64 context_64{}; Common::SpinLock context_guard{}; - std::shared_ptr host_context{}; + std::shared_ptr host_context{}; u64 thread_id = 0; -- cgit v1.2.3 From f370de84b16f9d668b7d5dcc0fd851264e2e6144 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 10 Mar 2020 18:41:11 -0400 Subject: Kernel: Rewind on SVC change. --- src/core/hle/kernel/scheduler.cpp | 2 ++ src/core/hle/kernel/svc.cpp | 9 ++++----- src/core/hle/kernel/thread.h | 10 ++++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 00322d997..25fc8a3e8 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -605,6 +605,7 @@ void Scheduler::OnThreadStart() { void Scheduler::Unload() { Thread* thread = current_thread.get(); if (thread) { + thread->SetContinuousOnSVC(false); thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); thread->SetIsRunning(false); if (!thread->IsHLEThread()) { @@ -697,6 +698,7 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { + previous_thread->SetContinuousOnSVC(false); previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); if (!previous_thread->IsHLEThread()) { auto& cpu_core = system.ArmInterface(core_id); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index eca92b356..d3d4e7bf9 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2459,7 +2459,8 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); void Call(Core::System& system, u32 immediate) { MICROPROFILE_SCOPE(Kernel_SVC); - auto& physical_core = system.CurrentPhysicalCore(); + auto* thread = system.CurrentScheduler().GetCurrentThread(); + thread->SetContinuousOnSVC(true); const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); @@ -2472,10 +2473,8 @@ void Call(Core::System& system, u32 immediate) { } else { LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); } - auto& physical_core_2 = system.CurrentPhysicalCore(); - if (physical_core.CoreIndex() != physical_core_2.CoreIndex()) { - LOG_CRITICAL(Kernel_SVC, "Rewinding"); - auto* thread = physical_core_2.Scheduler().GetCurrentThread(); + + if (!thread->IsContinuousOnSVC()) { auto* host_context = thread->GetHostContext().get(); host_context->Rewind(); } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9a29875ac..168828ab0 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -573,6 +573,14 @@ public: return pausing_state != 0; } + bool IsContinuousOnSVC() const { + return is_continuous_on_svc; + } + + void SetContinuousOnSVC(bool is_continuous) { + is_continuous_on_svc = is_continuous; + } + private: friend class GlobalScheduler; friend class Scheduler; @@ -672,6 +680,8 @@ private: bool is_waiting_on_sync = false; bool is_sync_cancelled = false; + bool is_continuous_on_svc = false; + bool will_be_terminated = false; std::string name; -- cgit v1.2.3 From e6f8bde74b9476dced103c6c54ab81616d34b97e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 11 Mar 2020 20:44:53 -0400 Subject: General: Fix Stop function --- src/core/hle/kernel/kernel.cpp | 15 +++++++++++++++ src/core/hle/kernel/thread.cpp | 8 +++++--- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 2a1b91752..24da4367e 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -119,6 +119,7 @@ struct KernelCore::Impl { void Initialize(KernelCore& kernel) { Shutdown(); + RegisterHostThread(); InitializePhysicalCores(); InitializeSystemResourceLimit(kernel); @@ -135,6 +136,19 @@ struct KernelCore::Impl { next_user_process_id = Process::ProcessIDMin; next_thread_id = 1; + for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + if (suspend_threads[i]) { + suspend_threads[i].reset(); + } + } + + for (std::size_t i = 0; i < cores.size(); i++) { + cores[i].Shutdown(); + } + cores.clear(); + + registered_core_threads.reset(); + process_list.clear(); current_process = nullptr; @@ -154,6 +168,7 @@ struct KernelCore::Impl { cores.clear(); exclusive_monitor.reset(); + host_thread_ids.clear(); } void InitializePhysicalCores() { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 1c32552b1..6f8e7a070 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -56,10 +56,12 @@ void Thread::Stop() { Signal(); kernel.GlobalHandleTable().Close(global_handle); - owner_process->UnregisterThread(this); + if (owner_process) { + owner_process->UnregisterThread(this); - // Mark the TLS slot in the thread's page as free. - owner_process->FreeTLSRegion(tls_address); + // Mark the TLS slot in the thread's page as free. + owner_process->FreeTLSRegion(tls_address); + } } global_handle = 0; } -- cgit v1.2.3 From 7020d498c5aef7c1180bfc57031cdd7fbfecdf0f Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 12 Mar 2020 16:48:43 -0400 Subject: General: Fix microprofile on dynarmic/svc, fix wait tree showing which threads were running. --- src/core/hle/kernel/kernel.cpp | 15 +++++++++++++++ src/core/hle/kernel/kernel.h | 4 ++++ src/core/hle/kernel/scheduler.cpp | 7 +++++++ src/core/hle/kernel/svc.cpp | 10 +++++++--- src/core/hle/kernel/thread.h | 18 ++++++++++++++++++ 5 files changed, 51 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 24da4367e..d2f5f9bf2 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -13,6 +13,7 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "common/microprofile.h" #include "common/thread.h" #include "core/arm/arm_interface.h" #include "core/arm/exclusive_monitor.h" @@ -41,6 +42,8 @@ #include "core/hle/result.h" #include "core/memory.h" +MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); + namespace Kernel { /** @@ -408,6 +411,8 @@ struct KernelCore::Impl { bool is_multicore{}; std::thread::id single_core_thread_id{}; + std::array svc_ticks{}; + // System context Core::System& system; }; @@ -666,4 +671,14 @@ void KernelCore::ExceptionalExit() { Suspend(true); } +void KernelCore::EnterSVCProfile() { + std::size_t core = impl->GetCurrentHostThreadID(); + impl->svc_ticks[core] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC)); +} + +void KernelCore::ExitSVCProfile() { + std::size_t core = impl->GetCurrentHostThreadID(); + MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 50eeb50ec..1eb6ede73 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -214,6 +214,10 @@ public: bool IsMulticore() const; + void EnterSVCProfile(); + + void ExitSVCProfile(); + private: friend class Object; friend class Process; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 25fc8a3e8..2ad380b17 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -354,7 +354,9 @@ void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule, } if (must_context_switch) { auto& core_scheduler = kernel.CurrentScheduler(); + kernel.ExitSVCProfile(); core_scheduler.TryDoContextSwitch(); + kernel.EnterSVCProfile(); } } @@ -628,6 +630,7 @@ void Scheduler::Reload() { // Cancel any outstanding wakeup events for this thread thread->SetIsRunning(true); + thread->SetWasRunning(false); thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); auto* const thread_owner_process = thread->GetOwnerProcess(); @@ -660,6 +663,7 @@ void Scheduler::SwitchContextStep2() { // Cancel any outstanding wakeup events for this thread new_thread->SetIsRunning(true); new_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); + new_thread->SetWasRunning(false); auto* const thread_owner_process = current_thread->GetOwnerProcess(); if (previous_process != thread_owner_process && thread_owner_process != nullptr) { @@ -698,6 +702,9 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { + if (new_thread != nullptr && new_thread->IsSuspendThread()) { + previous_thread->SetWasRunning(true); + } previous_thread->SetContinuousOnSVC(false); previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); if (!previous_thread->IsHLEThread()) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index d3d4e7bf9..9b9f9402e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2454,10 +2454,10 @@ static const FunctionDef* GetSVCInfo64(u32 func_num) { return &SVC_Table_64[func_num]; } -MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); - void Call(Core::System& system, u32 immediate) { - MICROPROFILE_SCOPE(Kernel_SVC); + system.ExitDynarmicProfile(); + auto& kernel = system.Kernel(); + kernel.EnterSVCProfile(); auto* thread = system.CurrentScheduler().GetCurrentThread(); thread->SetContinuousOnSVC(true); @@ -2474,10 +2474,14 @@ void Call(Core::System& system, u32 immediate) { LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); } + kernel.ExitSVCProfile(); + if (!thread->IsContinuousOnSVC()) { auto* host_context = thread->GetHostContext().get(); host_context->Rewind(); } + + system.EnterDynarmicProfile(); } } // namespace Kernel::Svc diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 168828ab0..f42d7bd13 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -350,6 +350,22 @@ public: return (type & THREADTYPE_HLE) != 0; } + bool IsSuspendThread() const { + return (type & THREADTYPE_SUSPEND) != 0; + } + + bool IsIdleThread() const { + return (type & THREADTYPE_IDLE) != 0; + } + + bool WasRunning() const { + return was_running; + } + + void SetWasRunning(bool value) { + was_running = value; + } + std::shared_ptr GetHostContext() const; ThreadStatus GetStatus() const { @@ -684,6 +700,8 @@ private: bool will_be_terminated = false; + bool was_running = false; + std::string name; }; -- cgit v1.2.3 From db68fba4a634ab6127ed485f55c41b5e1a05bc10 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 12 Mar 2020 19:53:54 -0400 Subject: Scheduler: Correct yielding interaction with SetThreadActivity. --- src/core/hle/kernel/scheduler.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 2ad380b17..8d56b49ce 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -144,6 +144,11 @@ u32 GlobalScheduler::SelectThreads() { bool GlobalScheduler::YieldThread(Thread* yielding_thread) { ASSERT(is_locked); // Note: caller should use critical section, etc. + if (!yielding_thread->IsRunnable()) { + // Normally this case shouldn't happen except for SetThreadActivity. + is_reselection_pending.store(true, std::memory_order_release); + return false; + } const u32 core_id = static_cast(yielding_thread->GetProcessorID()); const u32 priority = yielding_thread->GetPriority(); @@ -161,6 +166,11 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { ASSERT(is_locked); // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. + if (!yielding_thread->IsRunnable()) { + // Normally this case shouldn't happen except for SetThreadActivity. + is_reselection_pending.store(true, std::memory_order_release); + return false; + } const u32 core_id = static_cast(yielding_thread->GetProcessorID()); const u32 priority = yielding_thread->GetPriority(); @@ -212,6 +222,11 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread ASSERT(is_locked); // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. + if (!yielding_thread->IsRunnable()) { + // Normally this case shouldn't happen except for SetThreadActivity. + is_reselection_pending.store(true, std::memory_order_release); + return false; + } Thread* winner = nullptr; const u32 core_id = static_cast(yielding_thread->GetProcessorID()); -- cgit v1.2.3 From 25565dffd588006aace7530486e71ff318dc5550 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 15 Mar 2020 15:54:40 -0400 Subject: ARM: Addapt to new Exclusive Monitor Interface. --- src/core/hle/kernel/address_arbiter.cpp | 9 +++------ src/core/hle/kernel/svc.cpp | 4 +--- 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index e8f22b598..4d2a9b35d 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -80,8 +80,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 auto& monitor = system.Monitor(); u32 current_value; do { - monitor.SetExclusive32(current_core, address); - current_value = memory.Read32(address); + current_value = monitor.ExclusiveRead32(current_core, address); if (current_value != value) { return ERR_INVALID_STATE; @@ -110,8 +109,7 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a auto& monitor = system.Monitor(); s32 updated_value; do { - monitor.SetExclusive32(current_core, address); - updated_value = memory.Read32(address); + updated_value = monitor.ExclusiveRead32(current_core, address); if (updated_value != value) { return ERR_INVALID_STATE; @@ -186,8 +184,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 const std::size_t current_core = system.CurrentCoreIndex(); auto& monitor = system.Monitor(); do { - monitor.SetExclusive32(current_core, address); - current_value = static_cast(memory.Read32(address)); + current_value = static_cast(monitor.ExclusiveRead32(current_core, address)); if (should_decrement) { decrement_value = current_value - 1; } else { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9b9f9402e..36e9c48f9 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1653,10 +1653,8 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ u32 update_val = 0; const VAddr mutex_address = thread->GetMutexWaitAddress(); do { - monitor.SetExclusive32(current_core, mutex_address); - // If the mutex is not yet acquired, acquire it. - mutex_val = memory.Read32(mutex_address); + mutex_val = monitor.ExclusiveRead32(current_core, mutex_address); if (mutex_val != 0) { update_val = mutex_val | Mutex::MutexHasWaitersFlag; -- cgit v1.2.3 From f2ade343e2492c213ac93680a55e9bed712dac9a Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 19 Mar 2020 13:09:32 -0400 Subject: SingleCore: Move Host Timing from a sepparate thread to main cpu thread. --- src/core/hle/kernel/kernel.cpp | 2 +- src/core/hle/kernel/thread.h | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index d2f5f9bf2..a19cd7a1f 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -303,7 +303,7 @@ struct KernelCore::Impl { } const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler(); const Kernel::Thread* current = sched.GetCurrentThread(); - if (current != nullptr) { + if (current != nullptr && !current->IsPhantomMode()) { result.guest_handle = current->GetGlobalHandle(); } else { result.guest_handle = InvalidHandle; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index f42d7bd13..f998890c4 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -597,6 +597,14 @@ public: is_continuous_on_svc = is_continuous; } + bool IsPhantomMode() const { + return is_phantom_mode; + } + + void SetPhantomMode(bool phantom) { + is_phantom_mode = phantom; + } + private: friend class GlobalScheduler; friend class Scheduler; @@ -699,6 +707,7 @@ private: bool is_continuous_on_svc = false; bool will_be_terminated = false; + bool is_phantom_mode = false; bool was_running = false; -- cgit v1.2.3 From 87c49aa7be4b7277f8ae929058633827d339a052 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 20 Mar 2020 12:36:01 -0400 Subject: SVC/ARM: Correct svcSendSyncRequest and cache ticks on arm interface. --- src/core/hle/kernel/svc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 36e9c48f9..f08745226 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -342,7 +342,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { thread->InvokeHLECallback(SharedFrom(thread)); } - return RESULT_SUCCESS; + return thread->GetSignalingResult(); } static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { -- cgit v1.2.3 From 1b82ccec2220a69711ba75cf51ee98cbcfe6a510 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 29 Feb 2020 13:58:50 -0400 Subject: Core: Refactor ARM Interface. --- src/core/hle/kernel/kernel.cpp | 28 +++++++++++++++++++++++++++- src/core/hle/kernel/physical_core.cpp | 25 ++++++++----------------- src/core/hle/kernel/physical_core.h | 14 ++++++++------ 3 files changed, 43 insertions(+), 24 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index a19cd7a1f..e33ef5323 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include #include @@ -16,7 +17,9 @@ #include "common/microprofile.h" #include "common/thread.h" #include "core/arm/arm_interface.h" +#include "core/arm/cpu_interrupt_handler.h" #include "core/arm/exclusive_monitor.h" +#include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -42,6 +45,11 @@ #include "core/hle/result.h" #include "core/memory.h" +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#endif + MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); namespace Kernel { @@ -178,7 +186,20 @@ struct KernelCore::Impl { exclusive_monitor = Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - cores.emplace_back(system, i, *exclusive_monitor); +#ifdef ARCHITECTURE_x86_64 + arm_interfaces_32[i] = + std::make_unique(system, interrupts, *exclusive_monitor, i); + arm_interfaces_64[i] = + std::make_unique(system, interrupts, *exclusive_monitor, i); +#else + arm_interfaces_32[i] = std::make_shared( + system, interrupts, ARM_Unicorn::Arch::AArch32, i); + arm_interfaces_64[i] = std::make_shared( + system, interrupts, ARM_Unicorn::Arch::AArch64, i); + LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); +#endif + cores.emplace_back(system, i, *exclusive_monitor, interrupts[i], *arm_interfaces_32[i], + *arm_interfaces_64[i]); } } @@ -407,6 +428,11 @@ struct KernelCore::Impl { std::shared_ptr time_shared_mem; std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; + std::array interrupts{}; + std::array, Core::Hardware::NUM_CPU_CORES> + arm_interfaces_32{}; + std::array, Core::Hardware::NUM_CPU_CORES> + arm_interfaces_64{}; bool is_multicore{}; std::thread::id single_core_thread_id{}; diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index ff14fcb42..9146b331d 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -21,21 +21,12 @@ namespace Kernel { PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, - Core::ExclusiveMonitor& exclusive_monitor) - : interrupt_handler{}, core_index{id} { -#ifdef ARCHITECTURE_x86_64 - arm_interface_32 = std::make_unique(system, interrupt_handler, - exclusive_monitor, core_index); - arm_interface_64 = std::make_unique(system, interrupt_handler, - exclusive_monitor, core_index); -#else - using Core::ARM_Unicorn; - arm_interface_32 = - std::make_unique(system, interrupt_handler, ARM_Unicorn::Arch::AArch32); - arm_interface_64 = - std::make_unique(system, interrupt_handler, ARM_Unicorn::Arch::AArch64); - LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); -#endif + Core::ExclusiveMonitor& exclusive_monitor, + Core::CPUInterruptHandler& interrupt_handler, + Core::ARM_Interface& arm_interface32, + Core::ARM_Interface& arm_interface64) + : interrupt_handler{interrupt_handler}, core_index{id}, arm_interface_32{arm_interface32}, + arm_interface_64{arm_interface64} { scheduler = std::make_unique(system, core_index); guard = std::make_unique(); @@ -69,9 +60,9 @@ void PhysicalCore::Shutdown() { void PhysicalCore::SetIs64Bit(bool is_64_bit) { if (is_64_bit) { - arm_interface = arm_interface_64.get(); + arm_interface = &arm_interface_64; } else { - arm_interface = arm_interface_32.get(); + arm_interface = &arm_interface_32; } } diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index cd2e42fc3..2673d90f2 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -10,7 +10,7 @@ #include "core/arm/cpu_interrupt_handler.h" namespace Common { - class SpinLock; +class SpinLock; } namespace Kernel { @@ -27,7 +27,9 @@ namespace Kernel { class PhysicalCore { public: - PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor); + PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor, + Core::CPUInterruptHandler& interrupt_handler, Core::ARM_Interface& arm_interface32, + Core::ARM_Interface& arm_interface64); ~PhysicalCore(); PhysicalCore(const PhysicalCore&) = delete; @@ -92,13 +94,13 @@ public: void SetIs64Bit(bool is_64_bit); private: - Core::CPUInterruptHandler interrupt_handler; + Core::CPUInterruptHandler& interrupt_handler; std::size_t core_index; - std::unique_ptr arm_interface_32; - std::unique_ptr arm_interface_64; + Core::ARM_Interface& arm_interface_32; + Core::ARM_Interface& arm_interface_64; std::unique_ptr scheduler; Core::ARM_Interface* arm_interface{}; - std::unique_ptr guard; + std::unique_ptr guard; }; } // namespace Kernel -- cgit v1.2.3 From 1567824d2da8e9b49b433f3d1d753d8ad84e65f9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 1 Mar 2020 12:14:17 -0400 Subject: General: Move ARM_Interface into Threads. --- src/core/hle/kernel/kernel.cpp | 59 +++++++++++++---------------------- src/core/hle/kernel/kernel.h | 8 ++++- src/core/hle/kernel/physical_core.cpp | 37 +++------------------- src/core/hle/kernel/physical_core.h | 37 +++++----------------- src/core/hle/kernel/scheduler.cpp | 12 +++---- src/core/hle/kernel/svc.cpp | 11 ++----- src/core/hle/kernel/thread.cpp | 35 +++++++++++++++++++++ src/core/hle/kernel/thread.h | 8 ++++- 8 files changed, 88 insertions(+), 119 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e33ef5323..3feddd9ad 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -19,7 +19,6 @@ #include "core/arm/arm_interface.h" #include "core/arm/cpu_interrupt_handler.h" #include "core/arm/exclusive_monitor.h" -#include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -45,11 +44,6 @@ #include "core/hle/result.h" #include "core/memory.h" -#ifdef ARCHITECTURE_x86_64 -#include "core/arm/dynarmic/arm_dynarmic_32.h" -#include "core/arm/dynarmic/arm_dynarmic_64.h" -#endif - MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); namespace Kernel { @@ -186,20 +180,8 @@ struct KernelCore::Impl { exclusive_monitor = Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { -#ifdef ARCHITECTURE_x86_64 - arm_interfaces_32[i] = - std::make_unique(system, interrupts, *exclusive_monitor, i); - arm_interfaces_64[i] = - std::make_unique(system, interrupts, *exclusive_monitor, i); -#else - arm_interfaces_32[i] = std::make_shared( - system, interrupts, ARM_Unicorn::Arch::AArch32, i); - arm_interfaces_64[i] = std::make_shared( - system, interrupts, ARM_Unicorn::Arch::AArch64, i); - LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); -#endif - cores.emplace_back(system, i, *exclusive_monitor, interrupts[i], *arm_interfaces_32[i], - *arm_interfaces_64[i]); + schedulers[i] = std::make_unique(system, i); + cores.emplace_back(system, i, *schedulers[i], interrupts[i]); } } @@ -268,10 +250,6 @@ struct KernelCore::Impl { return; } - for (auto& core : cores) { - core.SetIs64Bit(process->Is64BitProcess()); - } - u32 core_id = GetCurrentHostThreadID(); if (core_id < Core::Hardware::NUM_CPU_CORES) { system.Memory().SetCurrentPageTable(*process, core_id); @@ -429,10 +407,7 @@ struct KernelCore::Impl { std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; std::array interrupts{}; - std::array, Core::Hardware::NUM_CPU_CORES> - arm_interfaces_32{}; - std::array, Core::Hardware::NUM_CPU_CORES> - arm_interfaces_64{}; + std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; bool is_multicore{}; std::thread::id single_core_thread_id{}; @@ -497,11 +472,11 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { } Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) { - return impl->cores[id].Scheduler(); + return *impl->schedulers[id]; } const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const { - return impl->cores[id].Scheduler(); + return *impl->schedulers[id]; } Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { @@ -525,11 +500,23 @@ const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { } Kernel::Scheduler& KernelCore::CurrentScheduler() { - return CurrentPhysicalCore().Scheduler(); + u32 core_id = impl->GetCurrentHostThreadID(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + return *impl->schedulers[core_id]; } const Kernel::Scheduler& KernelCore::CurrentScheduler() const { - return CurrentPhysicalCore().Scheduler(); + u32 core_id = impl->GetCurrentHostThreadID(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + return *impl->schedulers[core_id]; +} + +std::array& KernelCore::Interrupts() { + return impl->interrupts; +} + +const std::array& KernelCore::Interrupts() const { + return impl->interrupts; } Kernel::Synchronization& KernelCore::Synchronization() { @@ -557,15 +544,11 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { } void KernelCore::InvalidateAllInstructionCaches() { - for (std::size_t i = 0; i < impl->global_scheduler.CpuCoresCount(); i++) { - PhysicalCore(i).ArmInterface().ClearInstructionCache(); - } + //TODO: Reimplement, this } void KernelCore::PrepareReschedule(std::size_t id) { - if (id < impl->global_scheduler.CpuCoresCount()) { - impl->cores[id].Stop(); - } + // TODO: Reimplement, this } void KernelCore::AddNamedPort(std::string name, std::shared_ptr port) { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 1eb6ede73..846056b85 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -4,15 +4,17 @@ #pragma once +#include #include #include #include #include +#include "core/hardware_properties.h" #include "core/hle/kernel/memory/memory_types.h" #include "core/hle/kernel/object.h" namespace Core { -struct EmuThreadHandle; +class CPUInterruptHandler; class ExclusiveMonitor; class System; } // namespace Core @@ -144,6 +146,10 @@ public: const Core::ExclusiveMonitor& GetExclusiveMonitor() const; + std::array& Interrupts(); + + const std::array& Interrupts() const; + void InvalidateAllInstructionCaches(); /// Adds a port to the named port table diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 9146b331d..c82c60a16 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -20,50 +20,21 @@ namespace Kernel { -PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, - Core::ExclusiveMonitor& exclusive_monitor, - Core::CPUInterruptHandler& interrupt_handler, - Core::ARM_Interface& arm_interface32, - Core::ARM_Interface& arm_interface64) - : interrupt_handler{interrupt_handler}, core_index{id}, arm_interface_32{arm_interface32}, - arm_interface_64{arm_interface64} { +PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, + Core::CPUInterruptHandler& interrupt_handler) + : interrupt_handler{interrupt_handler}, core_index{id}, scheduler{scheduler} { - scheduler = std::make_unique(system, core_index); guard = std::make_unique(); } PhysicalCore::~PhysicalCore() = default; -void PhysicalCore::Run() { - arm_interface->Run(); -} - -void PhysicalCore::ClearExclusive() { - arm_interface->ClearExclusiveState(); -} - -void PhysicalCore::Step() { - arm_interface->Step(); -} - void PhysicalCore::Idle() { interrupt_handler.AwaitInterrupt(); } -void PhysicalCore::Stop() { - arm_interface->PrepareReschedule(); -} - void PhysicalCore::Shutdown() { - scheduler->Shutdown(); -} - -void PhysicalCore::SetIs64Bit(bool is_64_bit) { - if (is_64_bit) { - arm_interface = &arm_interface_64; - } else { - arm_interface = &arm_interface_32; - } + scheduler.Shutdown(); } void PhysicalCore::Interrupt() { diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 2673d90f2..751b994a7 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -10,7 +10,7 @@ #include "core/arm/cpu_interrupt_handler.h" namespace Common { -class SpinLock; + class SpinLock; } namespace Kernel { @@ -27,9 +27,9 @@ namespace Kernel { class PhysicalCore { public: - PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor, - Core::CPUInterruptHandler& interrupt_handler, Core::ARM_Interface& arm_interface32, - Core::ARM_Interface& arm_interface64); + PhysicalCore(Core::System& system, std::size_t id, + Kernel::Scheduler& scheduler, + Core::CPUInterruptHandler& interrupt_handler); ~PhysicalCore(); PhysicalCore(const PhysicalCore&) = delete; @@ -38,17 +38,7 @@ public: PhysicalCore(PhysicalCore&&) = default; PhysicalCore& operator=(PhysicalCore&&) = default; - /// Execute current jit state - void Run(); - /// Clear Exclusive state. - void ClearExclusive(); - /// Set this core in IdleState. void Idle(); - /// Execute a single instruction in current jit. - void Step(); - /// Stop JIT execution/exit - void Stop(); - /// Interrupt this physical core. void Interrupt(); @@ -63,14 +53,6 @@ public: // Shutdown this physical core. void Shutdown(); - Core::ARM_Interface& ArmInterface() { - return *arm_interface; - } - - const Core::ARM_Interface& ArmInterface() const { - return *arm_interface; - } - bool IsMainCore() const { return core_index == 0; } @@ -84,22 +66,17 @@ public: } Kernel::Scheduler& Scheduler() { - return *scheduler; + return scheduler; } const Kernel::Scheduler& Scheduler() const { - return *scheduler; + return scheduler; } - void SetIs64Bit(bool is_64_bit); - private: Core::CPUInterruptHandler& interrupt_handler; std::size_t core_index; - Core::ARM_Interface& arm_interface_32; - Core::ARM_Interface& arm_interface_64; - std::unique_ptr scheduler; - Core::ARM_Interface* arm_interface{}; + Kernel::Scheduler& scheduler; std::unique_ptr guard; }; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 8d56b49ce..a5083ae7c 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -681,15 +681,16 @@ void Scheduler::SwitchContextStep2() { new_thread->SetWasRunning(false); auto* const thread_owner_process = current_thread->GetOwnerProcess(); - if (previous_process != thread_owner_process && thread_owner_process != nullptr) { + if (thread_owner_process != nullptr) { system.Kernel().MakeCurrentProcess(thread_owner_process); } if (!new_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); + Core::ARM_Interface& cpu_core = new_thread->ArmInterface(); cpu_core.LoadContext(new_thread->GetContext32()); cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); + cpu_core.ChangeProcessorId(this->core_id); cpu_core.ClearExclusiveState(); } } @@ -722,18 +723,15 @@ void Scheduler::SwitchContext() { } previous_thread->SetContinuousOnSVC(false); previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); + previous_thread->SetIsRunning(false); if (!previous_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); + Core::ARM_Interface& cpu_core = previous_thread->ArmInterface(); cpu_core.SaveContext(previous_thread->GetContext32()); cpu_core.SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); cpu_core.ClearExclusiveState(); } - if (previous_thread->GetStatus() == ThreadStatus::Running) { - previous_thread->SetStatus(ThreadStatus::Ready); - } - previous_thread->SetIsRunning(false); previous_thread->context_guard.unlock(); } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f08745226..599972211 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1533,7 +1533,9 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { } if (is_redundant && !system.Kernel().IsMulticore()) { + system.Kernel().ExitSVCProfile(); system.GetCpuManager().PreemptSingleCore(); + system.Kernel().EnterSVCProfile(); } } @@ -2457,9 +2459,6 @@ void Call(Core::System& system, u32 immediate) { auto& kernel = system.Kernel(); kernel.EnterSVCProfile(); - auto* thread = system.CurrentScheduler().GetCurrentThread(); - thread->SetContinuousOnSVC(true); - const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); if (info) { @@ -2473,12 +2472,6 @@ void Call(Core::System& system, u32 immediate) { } kernel.ExitSVCProfile(); - - if (!thread->IsContinuousOnSVC()) { - auto* host_context = thread->GetHostContext().get(); - host_context->Rewind(); - } - system.EnterDynarmicProfile(); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 6f8e7a070..58b06aa9e 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -13,6 +13,13 @@ #include "common/logging/log.h" #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#endif +#include "core/arm/cpu_interrupt_handler.h" +#include "core/arm/exclusive_monitor.h" +#include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -232,7 +239,27 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy } // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used // to initialize the context + thread->arm_interface.reset(); if ((type_flags & THREADTYPE_HLE) == 0) { +#ifdef ARCHITECTURE_x86_64 + if (owner_process && !owner_process->Is64BitProcess()) { + thread->arm_interface = std::make_unique( + system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + } else { + thread->arm_interface = std::make_unique( + system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + } + +#else + if (owner_process && !owner_process->Is64BitProcess()) { + thread->arm_interface = std::make_shared( + system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch32, processor_id); + } else { + thread->arm_interface = std::make_shared( + system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch64, processor_id); + } + LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); +#endif ResetThreadContext32(thread->context_32, static_cast(stack_top), static_cast(entry_point), static_cast(arg)); ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); @@ -276,6 +303,14 @@ VAddr Thread::GetCommandBufferAddress() const { return GetTLSAddress() + command_header_offset; } +Core::ARM_Interface& Thread::ArmInterface() { + return *arm_interface; +} + +const Core::ARM_Interface& Thread::ArmInterface() const { + return *arm_interface; +} + void Thread::SetStatus(ThreadStatus new_status) { if (new_status == status) { return; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index f998890c4..c08fc3a89 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -21,6 +21,7 @@ class Fiber; } namespace Core { +class ARM_Interface; class System; } // namespace Core @@ -271,6 +272,10 @@ public: void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); + Core::ARM_Interface& ArmInterface(); + + const Core::ARM_Interface& ArmInterface() const; + SynchronizationObject* GetSignalingObject() const { return signaling_object; } @@ -617,9 +622,10 @@ private: void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); + Common::SpinLock context_guard{}; ThreadContext32 context_32{}; ThreadContext64 context_64{}; - Common::SpinLock context_guard{}; + std::unique_ptr arm_interface{}; std::shared_ptr host_context{}; u64 thread_id = 0; -- cgit v1.2.3 From 5974e3ea33e12e7abd813704e5b895003ba83555 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 14:16:25 -0400 Subject: Thread: Release the ARM Interface on exitting. --- src/core/hle/kernel/scheduler.cpp | 2 +- src/core/hle/kernel/thread.cpp | 2 ++ src/core/hle/kernel/thread.h | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index a5083ae7c..ce7e1986d 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -724,7 +724,7 @@ void Scheduler::SwitchContext() { previous_thread->SetContinuousOnSVC(false); previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); previous_thread->SetIsRunning(false); - if (!previous_thread->IsHLEThread()) { + if (!previous_thread->IsHLEThread() && !previous_thread->HasExited()) { Core::ARM_Interface& cpu_core = previous_thread->ArmInterface(); cpu_core.SaveContext(previous_thread->GetContext32()); cpu_core.SaveContext(previous_thread->GetContext64()); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 58b06aa9e..65fedfc9b 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -69,6 +69,8 @@ void Thread::Stop() { // Mark the TLS slot in the thread's page as free. owner_process->FreeTLSRegion(tls_address); } + arm_interface.reset(); + has_exited = true; } global_handle = 0; } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index c08fc3a89..f651d7822 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -610,6 +610,10 @@ public: is_phantom_mode = phantom; } + bool HasExited() const { + return has_exited; + } + private: friend class GlobalScheduler; friend class Scheduler; @@ -714,6 +718,7 @@ private: bool will_be_terminated = false; bool is_phantom_mode = false; + bool has_exited = false; bool was_running = false; -- cgit v1.2.3 From 9bde28d7b100fdcd1cc50c8f2a4b8c74704f5e34 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 10 Mar 2020 13:24:52 -0400 Subject: Scheduler: Correct Reload/Unload --- src/core/hle/kernel/kernel.cpp | 1 + src/core/hle/kernel/scheduler.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 3feddd9ad..739205eca 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -149,6 +149,7 @@ struct KernelCore::Impl { for (std::size_t i = 0; i < cores.size(); i++) { cores[i].Shutdown(); + schedulers[i].reset(); } cores.clear(); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index ce7e1986d..43c924fa0 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -625,8 +625,8 @@ void Scheduler::Unload() { thread->SetContinuousOnSVC(false); thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); thread->SetIsRunning(false); - if (!thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); + if (!thread->IsHLEThread() && !thread->HasExited()) { + Core::ARM_Interface& cpu_core = thread->ArmInterface(); cpu_core.SaveContext(thread->GetContext32()); cpu_core.SaveContext(thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. @@ -653,11 +653,12 @@ void Scheduler::Reload() { system.Kernel().MakeCurrentProcess(thread_owner_process); } if (!thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); + Core::ARM_Interface& cpu_core = thread->ArmInterface(); cpu_core.LoadContext(thread->GetContext32()); cpu_core.LoadContext(thread->GetContext64()); cpu_core.SetTlsAddress(thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); + cpu_core.ChangeProcessorId(this->core_id); cpu_core.ClearExclusiveState(); } } -- cgit v1.2.3 From f5e32935ca9d1727624c86ca78aff91027caf819 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 28 Mar 2020 15:23:28 -0400 Subject: SingleCore: Use Cycle Timing instead of Host Timing. --- src/core/hle/kernel/svc.cpp | 5 +++++ src/core/hle/kernel/thread.cpp | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 599972211..c47fa9167 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1534,6 +1534,7 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { if (is_redundant && !system.Kernel().IsMulticore()) { system.Kernel().ExitSVCProfile(); + system.CoreTiming().AddTicks(1000U); system.GetCpuManager().PreemptSingleCore(); system.Kernel().EnterSVCProfile(); } @@ -1762,6 +1763,10 @@ static u64 GetSystemTick(Core::System& system) { // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) const u64 result{system.CoreTiming().GetClockTicks()}; + if (!system.Kernel().IsMulticore()) { + core_timing.AddTicks(400U); + } + return result; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 65fedfc9b..d88039a16 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -246,19 +246,23 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy #ifdef ARCHITECTURE_x86_64 if (owner_process && !owner_process->Is64BitProcess()) { thread->arm_interface = std::make_unique( - system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(), + processor_id); } else { thread->arm_interface = std::make_unique( - system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(), + processor_id); } #else if (owner_process && !owner_process->Is64BitProcess()) { thread->arm_interface = std::make_shared( - system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch32, processor_id); + system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch32, + processor_id); } else { thread->arm_interface = std::make_shared( - system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch64, processor_id); + system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch64, + processor_id); } LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); #endif -- cgit v1.2.3 From 7e2ce2f7f47e77b46d66dcefbd0c391e58421103 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 29 Mar 2020 17:06:46 -0400 Subject: SingleCore: Improve Cycle timing Behavior and replace mutex in global scheduler for spinlock. --- src/core/hle/kernel/scheduler.h | 2 +- src/core/hle/kernel/server_session.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index f63cc5085..10dc4b832 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -188,7 +188,7 @@ private: /// Scheduler lock mechanisms. bool is_locked{}; - std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock + Common::SpinLock inner_lock{}; std::atomic scope_lock{}; Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()}; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 05516a453..e988a3f22 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -185,7 +185,8 @@ ResultCode ServerSession::CompleteSyncRequest() { ResultCode ServerSession::HandleSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory) { ResultCode result = QueueSyncRequest(std::move(thread), memory); - Core::System::GetInstance().CoreTiming().ScheduleEvent(0, request_event, {}); + const u64 delay = kernel.IsMulticore() ? 0U : 20000U; + Core::System::GetInstance().CoreTiming().ScheduleEvent(delay, request_event, {}); return result; } -- cgit v1.2.3 From 19165cd859dcbb1f7d5e2c74c831e5196c2d1c41 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 30 Mar 2020 21:50:05 -0400 Subject: HLE_IPC: Correct HLE Event behavior on timeout. --- src/core/hle/kernel/hle_ipc.cpp | 1 + src/core/hle/kernel/svc.cpp | 10 +++++++++- src/core/hle/kernel/thread.h | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index e74d91670..9277b5d08 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -70,6 +70,7 @@ std::shared_ptr HLERequestContext::SleepClientThread( }); const auto readable_event{writable_event->GetReadableEvent()}; writable_event->Clear(); + thread->SetHLESyncObject(readable_event.get()); thread->SetStatus(ThreadStatus::WaitHLEEvent); thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); readable_event->AddWaitingThread(thread); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c47fa9167..37e893c84 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -333,13 +333,21 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { thread->SetStatus(ThreadStatus::WaitIPC); session->SendSyncRequest(SharedFrom(thread), system.Memory()); } + if (thread->HasHLECallback()) { Handle event_handle = thread->GetHLETimeEvent(); if (event_handle != InvalidHandle) { auto& time_manager = system.Kernel().TimeManager(); time_manager.UnscheduleTimeEvent(event_handle); } - thread->InvokeHLECallback(SharedFrom(thread)); + + { + SchedulerLock lock(system.Kernel()); + auto* sync_object = thread->GetHLESyncObject(); + sync_object->RemoveWaitingThread(SharedFrom(thread)); + + thread->InvokeHLECallback(SharedFrom(thread)); + } } return thread->GetSignalingResult(); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index f651d7822..61963148d 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -489,10 +489,18 @@ public: hle_time_event = time_event; } + void SetHLESyncObject(SynchronizationObject* object) { + hle_object = object; + } + Handle GetHLETimeEvent() const { return hle_time_event; } + SynchronizationObject* GetHLESyncObject() const { + return hle_object; + } + void InvalidateWakeupCallback() { SetWakeupCallback(nullptr); } @@ -698,6 +706,7 @@ private: /// Callback for HLE Events HLECallback hle_callback; Handle hle_time_event; + SynchronizationObject* hle_object; Scheduler* scheduler = nullptr; -- cgit v1.2.3 From c8bf47dcfbd43f3e7835d2e45b4704e056d8e9ee Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 31 Mar 2020 15:12:41 -0400 Subject: Kernel/svcBreak: Implement CacheInvalidation for Singlecore and correct svcBreak. --- src/core/hle/kernel/kernel.cpp | 12 +++++++++++- src/core/hle/kernel/svc.cpp | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 739205eca..1f230fc4a 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -545,7 +545,17 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { } void KernelCore::InvalidateAllInstructionCaches() { - //TODO: Reimplement, this + if (!IsMulticore()) { + auto& threads = GlobalScheduler().GetThreadList(); + for (auto& thread : threads) { + if (!thread->IsHLEThread()) { + auto& arm_interface = thread->ArmInterface(); + arm_interface.ClearInstructionCache(); + } + } + } else { + UNIMPLEMENTED_MSG("Cache Invalidation unimplemented for multicore"); + } } void KernelCore::PrepareReschedule(std::size_t id) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 37e893c84..dbd35580e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -622,6 +622,7 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt); if (!break_reason.signal_debugger) { + SchedulerLock lock(system.Kernel()); LOG_CRITICAL( Debug_Emulated, "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", @@ -633,9 +634,8 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { const auto thread_processor_id = current_thread->GetProcessorID(); system.ArmInterface(static_cast(thread_processor_id)).LogBacktrace(); - system.Kernel().CurrentProcess()->PrepareForTermination(); - // Kill the current thread + system.Kernel().ExceptionalExit(); current_thread->Stop(); } } -- cgit v1.2.3 From 48fa3b7a0f2054a836b0a8061e6b082c246b5ae0 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 1 Apr 2020 17:28:49 -0400 Subject: General: Cleanup legacy code. --- src/core/hle/kernel/client_port.cpp | 2 +- src/core/hle/kernel/kernel.cpp | 81 +------------------------- src/core/hle/kernel/kernel.h | 3 - src/core/hle/kernel/svc.cpp | 3 +- src/core/hle/kernel/synchronization_object.cpp | 64 -------------------- src/core/hle/kernel/synchronization_object.h | 15 ----- src/core/hle/kernel/thread.cpp | 34 ----------- src/core/hle/kernel/thread.h | 56 +----------------- 8 files changed, 5 insertions(+), 253 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 5498fd313..8aff2227a 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -34,7 +34,7 @@ ResultVal> ClientPort::Connect() { } // Wake the threads waiting on the ServerPort - server_port->WakeupAllWaitingThreads(); + server_port->Signal(); return MakeResult(std::move(client)); } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1f230fc4a..dbb75416d 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -48,72 +48,6 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); namespace Kernel { -/** - * Callback that will wake up the thread it was scheduled for - * @param thread_handle The handle of the thread that's been awoken - * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time - */ -static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_late) { - UNREACHABLE(); - const auto proper_handle = static_cast(thread_handle); - const auto& system = Core::System::GetInstance(); - - // Lock the global kernel mutex when we enter the kernel HLE. - std::lock_guard lock{HLE::g_hle_lock}; - - std::shared_ptr thread = - system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); - if (thread == nullptr) { - LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); - return; - } - - bool resume = true; - - if (thread->GetStatus() == ThreadStatus::WaitSynch || - thread->GetStatus() == ThreadStatus::WaitHLEEvent) { - // Remove the thread from each of its waiting objects' waitlists - for (const auto& object : thread->GetSynchronizationObjects()) { - object->RemoveWaitingThread(thread); - } - thread->ClearSynchronizationObjects(); - - // Invoke the wakeup callback before clearing the wait objects - if (thread->HasWakeupCallback()) { - resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Timeout, thread, nullptr, 0); - } - } else if (thread->GetStatus() == ThreadStatus::WaitMutex || - thread->GetStatus() == ThreadStatus::WaitCondVar) { - thread->SetMutexWaitAddress(0); - thread->SetWaitHandle(0); - if (thread->GetStatus() == ThreadStatus::WaitCondVar) { - thread->GetOwnerProcess()->RemoveConditionVariableThread(thread); - thread->SetCondVarWaitAddress(0); - } - - auto* const lock_owner = thread->GetLockOwner(); - // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance - // and don't have a lock owner unless SignalProcessWideKey was called first and the thread - // wasn't awakened due to the mutex already being acquired. - if (lock_owner != nullptr) { - lock_owner->RemoveMutexWaiter(thread); - } - } - - if (thread->GetStatus() == ThreadStatus::WaitArb) { - auto& address_arbiter = thread->GetOwnerProcess()->GetAddressArbiter(); - address_arbiter.HandleWakeupThread(thread); - } - - if (resume) { - if (thread->GetStatus() == ThreadStatus::WaitCondVar || - thread->GetStatus() == ThreadStatus::WaitArb) { - thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); - } - thread->ResumeFromWait(); - } -} - struct KernelCore::Impl { explicit Impl(Core::System& system, KernelCore& kernel) : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {} @@ -129,7 +63,6 @@ struct KernelCore::Impl { InitializePhysicalCores(); InitializeSystemResourceLimit(kernel); InitializeMemoryLayout(); - InitializeThreads(); InitializePreemption(kernel); InitializeSchedulers(); InitializeSuspendThreads(); @@ -161,7 +94,6 @@ struct KernelCore::Impl { system_resource_limit = nullptr; global_handle_table.Clear(); - thread_wakeup_event_type = nullptr; preemption_event = nullptr; global_scheduler.Shutdown(); @@ -210,11 +142,6 @@ struct KernelCore::Impl { } } - void InitializeThreads() { - thread_wakeup_event_type = - Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback); - } - void InitializePreemption(KernelCore& kernel) { preemption_event = Core::Timing::CreateEvent( "PreemptionCallback", [this, &kernel](u64 userdata, s64 cycles_late) { @@ -376,7 +303,6 @@ struct KernelCore::Impl { std::shared_ptr system_resource_limit; - std::shared_ptr thread_wakeup_event_type; std::shared_ptr preemption_event; // This is the kernel's handle table or supervisor handle table which @@ -516,7 +442,8 @@ std::array& KernelCore return impl->interrupts; } -const std::array& KernelCore::Interrupts() const { +const std::array& KernelCore::Interrupts() + const { return impl->interrupts; } @@ -595,10 +522,6 @@ u64 KernelCore::CreateNewUserProcessID() { return impl->next_user_process_id++; } -const std::shared_ptr& KernelCore::ThreadWakeupCallbackEventType() const { - return impl->thread_wakeup_event_type; -} - Kernel::HandleTable& KernelCore::GlobalHandleTable() { return impl->global_handle_table; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 846056b85..49bd47e89 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -241,9 +241,6 @@ private: /// Creates a new thread ID, incrementing the internal thread ID counter. u64 CreateNewThreadID(); - /// Retrieves the event type used for thread wakeup callbacks. - const std::shared_ptr& ThreadWakeupCallbackEventType() const; - /// Provides a reference to the global handle table. Kernel::HandleTable& GlobalHandleTable(); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index dbd35580e..781032cd1 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -16,7 +16,6 @@ #include "common/string_util.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" -#include "core/core_manager.h" #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/cpu_manager.h" @@ -1909,7 +1908,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, return ERR_INVALID_COMBINATION; } - if (core < Core::NUM_CPU_CORES) { + if (core < Core::Hardware::NUM_CPU_CORES) { if ((affinity_mask & (1ULL << core)) == 0) { LOG_ERROR(Kernel_SVC, "Core is not enabled for the current mask, core={}, mask={:016X}", core, diff --git a/src/core/hle/kernel/synchronization_object.cpp b/src/core/hle/kernel/synchronization_object.cpp index be9e09106..ba4d39157 100644 --- a/src/core/hle/kernel/synchronization_object.cpp +++ b/src/core/hle/kernel/synchronization_object.cpp @@ -38,70 +38,6 @@ void SynchronizationObject::RemoveWaitingThread(std::shared_ptr thread) waiting_threads.erase(itr); } -std::shared_ptr SynchronizationObject::GetHighestPriorityReadyThread() const { - Thread* candidate = nullptr; - u32 candidate_priority = THREADPRIO_LOWEST + 1; - - for (const auto& thread : waiting_threads) { - const ThreadStatus thread_status = thread->GetStatus(); - - // The list of waiting threads must not contain threads that are not waiting to be awakened. - ASSERT_MSG(thread_status == ThreadStatus::WaitSynch || - thread_status == ThreadStatus::WaitHLEEvent, - "Inconsistent thread statuses in waiting_threads"); - - if (thread->GetPriority() >= candidate_priority) - continue; - - if (ShouldWait(thread.get())) - continue; - - candidate = thread.get(); - candidate_priority = thread->GetPriority(); - } - - return SharedFrom(candidate); -} - -void SynchronizationObject::WakeupWaitingThread(std::shared_ptr thread) { - ASSERT(!ShouldWait(thread.get())); - - if (!thread) { - return; - } - - if (thread->IsSleepingOnWait()) { - for (const auto& object : thread->GetSynchronizationObjects()) { - ASSERT(!object->ShouldWait(thread.get())); - object->Acquire(thread.get()); - } - } else { - Acquire(thread.get()); - } - - const std::size_t index = thread->GetSynchronizationObjectIndex(SharedFrom(this)); - - thread->ClearSynchronizationObjects(); - - thread->CancelWakeupTimer(); - - bool resume = true; - if (thread->HasWakeupCallback()) { - resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this), - index); - } - if (resume) { - thread->ResumeFromWait(); - kernel.PrepareReschedule(thread->GetProcessorID()); - } -} - -void SynchronizationObject::WakeupAllWaitingThreads() { - while (auto thread = GetHighestPriorityReadyThread()) { - WakeupWaitingThread(thread); - } -} - void SynchronizationObject::ClearWaitingThreads() { waiting_threads.clear(); } diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h index a35544ac1..f89b24204 100644 --- a/src/core/hle/kernel/synchronization_object.h +++ b/src/core/hle/kernel/synchronization_object.h @@ -50,21 +50,6 @@ public: */ void RemoveWaitingThread(std::shared_ptr thread); - /** - * Wake up all threads waiting on this object that can be awoken, in priority order, - * and set the synchronization result and output of the thread. - */ - void /* deprecated */ WakeupAllWaitingThreads(); - - /** - * Wakes up a single thread waiting on this object. - * @param thread Thread that is waiting on this object to wakeup. - */ - void WakeupWaitingThread(std::shared_ptr thread); - - /// Obtains the highest priority thread that is ready to run from this object's waiting list. - std::shared_ptr /* deprecated */ GetHighestPriorityReadyThread() const; - /// Get a const reference to the waiting threads list for debug use const std::vector>& GetWaitingThreads() const; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d88039a16..fba2a9c85 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -56,9 +56,6 @@ Thread::~Thread() = default; void Thread::Stop() { { SchedulerLock lock(kernel); - // Cancel any outstanding wakeup events for this thread - Core::System::GetInstance().CoreTiming().UnscheduleEvent( - kernel.ThreadWakeupCallbackEventType(), global_handle); SetStatus(ThreadStatus::Dead); Signal(); kernel.GlobalHandleTable().Close(global_handle); @@ -75,22 +72,6 @@ void Thread::Stop() { global_handle = 0; } -void Thread::WakeAfterDelay(s64 nanoseconds) { - // Don't schedule a wakeup if the thread wants to wait forever - if (nanoseconds == -1) - return; - - // This function might be called from any thread so we have to be cautious and use the - // thread-safe version of ScheduleEvent. - Core::System::GetInstance().CoreTiming().ScheduleEvent( - nanoseconds, kernel.ThreadWakeupCallbackEventType(), global_handle); -} - -void Thread::CancelWakeupTimer() { - Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - global_handle); -} - void Thread::ResumeFromWait() { SchedulerLock lock(kernel); switch (status) { @@ -284,14 +265,6 @@ void Thread::SetPriority(u32 priority) { UpdatePriority(); } -void Thread::SetWaitSynchronizationResult(ResultCode result) { - UNREACHABLE(); -} - -void Thread::SetWaitSynchronizationOutput(s32 output) { - UNREACHABLE(); -} - void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode result) { signaling_object = object; signaling_result = result; @@ -425,13 +398,6 @@ bool Thread::AllSynchronizationObjectsReady() const { }); } -bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, - std::size_t index) { - ASSERT(wakeup_callback); - return wakeup_callback(reason, std::move(thread), std::move(object), index); -} - bool Thread::InvokeHLECallback(std::shared_ptr thread) { ASSERT(hle_callback); return hle_callback(std::move(thread)); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 61963148d..3ae0df6ef 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -128,9 +128,6 @@ public: using ThreadSynchronizationObjects = std::vector>; - using WakeupCallback = - std::function thread, - std::shared_ptr object, std::size_t index)>; using HLECallback = std::function thread)>; /** @@ -235,7 +232,7 @@ public: } /// Resumes a thread from waiting - void /* deprecated */ ResumeFromWait(); + void ResumeFromWait(); void OnWakeUp(); @@ -249,27 +246,6 @@ public: /// void CancelWait(); - /** - * Schedules an event to wake up the specified thread after the specified delay - * @param nanoseconds The time this thread will be allowed to sleep for - */ - void /* deprecated */ WakeAfterDelay(s64 nanoseconds); - - /// Cancel any outstanding wakeup events for this thread - void /* deprecated */ CancelWakeupTimer(); - - /** - * Sets the result after the thread awakens (from svcWaitSynchronization) - * @param result Value to set to the returned result - */ - void /*deprecated*/ SetWaitSynchronizationResult(ResultCode result); - - /** - * Sets the output parameter value after the thread awakens (from svcWaitSynchronization) - * @param output Value to set to the output parameter - */ - void /*deprecated*/ SetWaitSynchronizationOutput(s32 output); - void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); Core::ARM_Interface& ArmInterface(); @@ -330,11 +306,6 @@ public: */ VAddr GetCommandBufferAddress() const; - /// Returns whether this thread is waiting on objects from a WaitSynchronization call. - bool IsSleepingOnWait() const { - return status == ThreadStatus::WaitSynch; - } - ThreadContext32& GetContext32() { return context_32; } @@ -469,18 +440,10 @@ public: arb_wait_address = address; } - bool HasWakeupCallback() const { - return wakeup_callback != nullptr; - } - bool HasHLECallback() const { return hle_callback != nullptr; } - void SetWakeupCallback(WakeupCallback callback) { - wakeup_callback = std::move(callback); - } - void SetHLECallback(HLECallback callback) { hle_callback = std::move(callback); } @@ -501,22 +464,10 @@ public: return hle_object; } - void InvalidateWakeupCallback() { - SetWakeupCallback(nullptr); - } - void InvalidateHLECallback() { SetHLECallback(nullptr); } - /** - * Invokes the thread's wakeup callback. - * - * @pre A valid wakeup callback has been set. Violating this precondition - * will cause an assertion to trigger. - */ - bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, std::size_t index); bool InvokeHLECallback(std::shared_ptr thread); u32 GetIdealCore() const { @@ -698,11 +649,6 @@ private: /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. Handle global_handle = 0; - /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread - /// was waiting via WaitSynchronization then the object will be the last object that became - /// available. In case of a timeout, the object will be nullptr. DEPRECATED - WakeupCallback wakeup_callback; - /// Callback for HLE Events HLECallback hle_callback; Handle hle_time_event; -- cgit v1.2.3 From 467d43570e10b98fa33067352d35fe62ceb3cb9e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 8 May 2020 18:53:13 -0400 Subject: Clang Format. --- src/core/hle/kernel/mutex.cpp | 11 +++++------ src/core/hle/kernel/mutex.h | 3 ++- src/core/hle/kernel/physical_core.h | 7 +++---- src/core/hle/kernel/server_session.cpp | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 32dc1ffae..8f6c944d1 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -9,7 +9,6 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -126,11 +125,11 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, std::pair> Mutex::Unlock(std::shared_ptr owner, VAddr address) { - // The mutex address must be 4-byte aligned - if ((address % sizeof(u32)) != 0) { - LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); - return {ERR_INVALID_ADDRESS, nullptr}; - } + // The mutex address must be 4-byte aligned + if ((address % sizeof(u32)) != 0) { + LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); + return {ERR_INVALID_ADDRESS, nullptr}; + } auto [new_owner, num_waiters] = GetHighestPriorityMutexWaitingThread(owner, address); if (new_owner == nullptr) { diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index bce06ecea..3b81dc3df 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -29,7 +29,8 @@ public: Handle requesting_thread_handle); /// Unlocks a mutex for owner at address - std::pair> Unlock(std::shared_ptr owner, VAddr address); + std::pair> Unlock(std::shared_ptr owner, + VAddr address); /// Releases the mutex at the specified address. ResultCode Release(VAddr address); diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 751b994a7..85f6dec05 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -10,7 +10,7 @@ #include "core/arm/cpu_interrupt_handler.h" namespace Common { - class SpinLock; +class SpinLock; } namespace Kernel { @@ -27,9 +27,8 @@ namespace Kernel { class PhysicalCore { public: - PhysicalCore(Core::System& system, std::size_t id, - Kernel::Scheduler& scheduler, - Core::CPUInterruptHandler& interrupt_handler); + PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, + Core::CPUInterruptHandler& interrupt_handler); ~PhysicalCore(); PhysicalCore(const PhysicalCore&) = delete; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index e988a3f22..7b23a6889 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -17,9 +17,9 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" -#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" #include "core/memory.h" -- cgit v1.2.3 From d24014358883987d7ebdafc4863a7bc36addfa1b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 13 May 2020 14:17:34 -0400 Subject: Kernel: Correct Host Context on Threads and Scheduler. --- src/core/hle/kernel/scheduler.cpp | 16 ++++++++-------- src/core/hle/kernel/scheduler.h | 2 +- src/core/hle/kernel/thread.cpp | 2 +- src/core/hle/kernel/thread.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 43c924fa0..61b8a396a 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -736,15 +736,15 @@ void Scheduler::SwitchContext() { previous_thread->context_guard.unlock(); } - std::shared_ptr old_context; + std::shared_ptr* old_context; if (previous_thread != nullptr) { - old_context = previous_thread->GetHostContext(); + old_context = &previous_thread->GetHostContext(); } else { - old_context = idle_thread->GetHostContext(); + old_context = &idle_thread->GetHostContext(); } guard.unlock(); - Common::Fiber::YieldTo(old_context, switch_fiber); + Common::Fiber::YieldTo(*old_context, switch_fiber); /// When a thread wakes up, the scheduler may have changed to other in another core. auto& next_scheduler = system.Kernel().CurrentScheduler(); next_scheduler.SwitchContextStep2(); @@ -774,13 +774,13 @@ void Scheduler::SwitchToCurrent() { break; } } - std::shared_ptr next_context; + std::shared_ptr* next_context; if (current_thread != nullptr) { - next_context = current_thread->GetHostContext(); + next_context = ¤t_thread->GetHostContext(); } else { - next_context = idle_thread->GetHostContext(); + next_context = &idle_thread->GetHostContext(); } - Common::Fiber::YieldTo(switch_fiber, next_context); + Common::Fiber::YieldTo(switch_fiber, *next_context); } } } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 10dc4b832..348107160 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -236,7 +236,7 @@ public: void OnThreadStart(); - std::shared_ptr ControlContext() { + std::shared_ptr& ControlContext() { return switch_fiber; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index fba2a9c85..2b1092697 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -150,7 +150,7 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, context.fpcr = 0; } -std::shared_ptr Thread::GetHostContext() const { +std::shared_ptr& Thread::GetHostContext() { return host_context; } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 3ae0df6ef..c0342c462 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -342,7 +342,7 @@ public: was_running = value; } - std::shared_ptr GetHostContext() const; + std::shared_ptr& GetHostContext(); ThreadStatus GetStatus() const { return status; -- cgit v1.2.3 From 7fd7d05838b88e9dd63a7329e29ea355669a5f18 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 29 May 2020 17:37:37 -0400 Subject: Common/Kernel: Corrections and small bug fixing. --- src/core/hle/kernel/svc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 781032cd1..013ae9e34 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -344,9 +344,9 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { SchedulerLock lock(system.Kernel()); auto* sync_object = thread->GetHLESyncObject(); sync_object->RemoveWaitingThread(SharedFrom(thread)); - - thread->InvokeHLECallback(SharedFrom(thread)); } + + thread->InvokeHLECallback(SharedFrom(thread)); } return thread->GetSignalingResult(); -- cgit v1.2.3 From 22ceaca2f415b962416637db9fff9782575746ce Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 18 Jun 2020 18:15:19 -0400 Subject: SVC: Add GetThreadPriority32 & SetThreadPriority32 --- src/core/hle/kernel/svc.cpp | 14 ++++++++++++-- src/core/hle/kernel/svc_wrap.h | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 013ae9e34..5674d9558 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1135,6 +1135,10 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri return RESULT_SUCCESS; } +static ResultCode SetThreadPriority32(Core::System& system, Handle handle, u32 priority) { + return SetThreadPriority(system, handle, priority); +} + /// Get which CPU core is executing the current thread static u32 GetCurrentProcessorNumber(Core::System& system) { LOG_TRACE(Kernel_SVC, "called"); @@ -1933,6 +1937,12 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, return thread->SetCoreAndAffinityMask(core, affinity_mask); } +static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, + u32 affinity_mask_low, u32 affinity_mask_high) { + const u64 affinity_mask = static_cast(affinity_mask_low) | (static_cast(affinity_mask_high) << 32); + return SetThreadCoreMask(system, thread_handle, core, affinity_mask); +} + static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { LOG_DEBUG(Kernel_SVC, "called"); @@ -2206,9 +2216,9 @@ static const FunctionDef SVC_Table_32[] = { {0x0a, nullptr, "ExitThread32"}, {0x0b, nullptr, "SleepThread32"}, {0x0c, SvcWrap32, "GetThreadPriority32"}, - {0x0d, nullptr, "SetThreadPriority32"}, + {0x0d, SvcWrap32, "SetThreadPriority32"}, {0x0e, nullptr, "GetThreadCoreMask32"}, - {0x0f, nullptr, "SetThreadCoreMask32"}, + {0x0f, SvcWrap32, "SetThreadCoreMask32"}, {0x10, nullptr, "GetCurrentProcessorNumber32"}, {0x11, nullptr, "SignalEvent32"}, {0x12, nullptr, "ClearEvent32"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 7d735e3fa..fd4edba2a 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -399,6 +399,24 @@ void SvcWrap32(Core::System& system) { func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1))); } +// Used by SetThreadPriority32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = + func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1))).raw; + FuncReturn(system, retval); +} + +// Used by SetThreadCoreMask32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = + func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1)), + static_cast(Param(system, 2)), static_cast(Param(system, 3))) + .raw; + FuncReturn(system, retval); +} + // Used by SendSyncRequest32 template void SvcWrap32(Core::System& system) { -- cgit v1.2.3 From ce350e7ce03b8d9e3e2c8ff8774f9b929a70047f Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 18 Jun 2020 20:33:04 -0400 Subject: SVC: Add GetCurrentProcessorNumber32, CreateTransferMemory32, SetMemoryAttribute32 --- src/core/hle/kernel/svc.cpp | 29 +++++++++++++++++++++++------ src/core/hle/kernel/svc_wrap.h | 16 ++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 5674d9558..1d47a2779 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -232,6 +232,12 @@ static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 si static_cast(attribute)); } +static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask, + u32 attribute) { + return SetMemoryAttribute(system, static_cast(address), static_cast(size), + mask, attribute); +} + /// Maps a memory range into a different range. static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { std::lock_guard lock{HLE::g_hle_lock}; @@ -1136,7 +1142,7 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri } static ResultCode SetThreadPriority32(Core::System& system, Handle handle, u32 priority) { - return SetThreadPriority(system, handle, priority); + return SetThreadPriority(system, handle, priority); } /// Get which CPU core is executing the current thread @@ -1145,6 +1151,10 @@ static u32 GetCurrentProcessorNumber(Core::System& system) { return static_cast(system.CurrentPhysicalCore().CoreIndex()); } +static u32 GetCurrentProcessorNumber32(Core::System& system) { + return GetCurrentProcessorNumber(system); +} + static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, u64 size, u32 permissions) { std::lock_guard lock{HLE::g_hle_lock}; @@ -1861,6 +1871,12 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd return RESULT_SUCCESS; } +static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size, + u32 permissions) { + return CreateTransferMemory(system, handle, static_cast(addr), + static_cast(size), permissions); +} + static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core, u64* mask) { LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); @@ -1938,8 +1954,9 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, } static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, - u32 affinity_mask_low, u32 affinity_mask_high) { - const u64 affinity_mask = static_cast(affinity_mask_low) | (static_cast(affinity_mask_high) << 32); + u32 affinity_mask_low, u32 affinity_mask_high) { + const u64 affinity_mask = + static_cast(affinity_mask_low) | (static_cast(affinity_mask_high) << 32); return SetThreadCoreMask(system, thread_handle, core, affinity_mask); } @@ -2206,7 +2223,7 @@ static const FunctionDef SVC_Table_32[] = { {0x00, nullptr, "Unknown"}, {0x01, SvcWrap32, "SetHeapSize32"}, {0x02, nullptr, "Unknown"}, - {0x03, nullptr, "SetMemoryAttribute32"}, + {0x03, SvcWrap32, "SetMemoryAttribute32"}, {0x04, nullptr, "MapMemory32"}, {0x05, nullptr, "UnmapMemory32"}, {0x06, SvcWrap32, "QueryMemory32"}, @@ -2219,12 +2236,12 @@ static const FunctionDef SVC_Table_32[] = { {0x0d, SvcWrap32, "SetThreadPriority32"}, {0x0e, nullptr, "GetThreadCoreMask32"}, {0x0f, SvcWrap32, "SetThreadCoreMask32"}, - {0x10, nullptr, "GetCurrentProcessorNumber32"}, + {0x10, SvcWrap32, "GetCurrentProcessorNumber32"}, {0x11, nullptr, "SignalEvent32"}, {0x12, nullptr, "ClearEvent32"}, {0x13, nullptr, "MapSharedMemory32"}, {0x14, nullptr, "UnmapSharedMemory32"}, - {0x15, nullptr, "CreateTransferMemory32"}, + {0x15, SvcWrap32, "CreateTransferMemory32"}, {0x16, SvcWrap32, "CloseHandle32"}, {0x17, nullptr, "ResetSignal32"}, {0x18, SvcWrap32, "WaitSynchronization32"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index fd4edba2a..ba90c354f 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -357,6 +357,12 @@ void SvcWrap32(Core::System& system) { func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)).raw); } +// Used by GetCurrentProcessorNumber32 +template +void SvcWrap32(Core::System& system) { + FuncReturn(system, func(system)); +} + // Used by GetInfo32 template void SvcWrap32(Core::System& system) { @@ -423,6 +429,16 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0))).raw); } +// Used by CreateTransferMemory32 +template +void SvcWrap32(Core::System& system) { + Handle handle = 0; + const u32 retval = + func(system, &handle, Param32(system, 1), Param32(system, 2), Param32(system, 3)).raw; + system.CurrentArmInterface().SetReg(1, handle); + FuncReturn(system, retval); +} + // Used by WaitSynchronization32 template void SvcWrap32(Core::System& system) { -- cgit v1.2.3 From 4105f38022a525aab2e7d4288f121b4f0a0dd7b2 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 19 Jun 2020 19:40:07 -0400 Subject: SVC: Implement 32-bits wrappers and update Dynarmic. --- src/core/hle/kernel/svc.cpp | 198 +++++++++++++++++++++++++++++++++++------ src/core/hle/kernel/svc_wrap.h | 105 +++++++++++++++++++++- 2 files changed, 273 insertions(+), 30 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 1d47a2779..5db19dcf3 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -254,6 +254,11 @@ static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr return page_table.Map(dst_addr, src_addr, size); } +static ResultCode MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { + return MapMemory(system, static_cast(dst_addr), static_cast(src_addr), + static_cast(size)); +} + /// Unmaps a region that was previously mapped with svcMapMemory static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { std::lock_guard lock{HLE::g_hle_lock}; @@ -270,6 +275,11 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad return page_table.Unmap(dst_addr, src_addr, size); } +static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { + return UnmapMemory(system, static_cast(dst_addr), static_cast(src_addr), + static_cast(size)); +} + /// Connect to an OS service given the port name, returns the handle to the port to out static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, VAddr port_name_address) { @@ -417,6 +427,15 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han return ERR_INVALID_HANDLE; } +static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32* process_id_high, + Handle handle) { + u64 process_id{}; + const auto result = GetProcessId(system, &process_id, handle); + *process_id_low = static_cast(process_id); + *process_id_high = static_cast(process_id >> 32); + return result; +} + /// Wait for the given handles to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address, u64 handle_count, s64 nano_seconds) { @@ -484,6 +503,10 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand return RESULT_SUCCESS; } +static ResultCode CancelSynchronization32(Core::System& system, Handle thread_handle) { + return CancelSynchronization(system, thread_handle); +} + /// Attempts to locks a mutex, creating it if it does not already exist static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_handle, VAddr mutex_addr, Handle requesting_thread_handle) { @@ -508,6 +531,12 @@ static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_hand requesting_thread_handle); } +static ResultCode ArbitrateLock32(Core::System& system, Handle holding_thread_handle, + u32 mutex_addr, Handle requesting_thread_handle) { + return ArbitrateLock(system, holding_thread_handle, static_cast(mutex_addr), + requesting_thread_handle); +} + /// Unlock a mutex static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) { LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); @@ -527,6 +556,10 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) { return current_process->GetMutex().Release(mutex_addr); } +static ResultCode ArbitrateUnlock32(Core::System& system, u32 mutex_addr) { + return ArbitrateUnlock(system, static_cast(mutex_addr)); +} + enum class BreakType : u32 { Panic = 0, AssertionFailed = 1, @@ -645,6 +678,10 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { } } +static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) { + Break(system, reason, static_cast(info1), static_cast(info2)); +} + /// Used to output a message on a debug hardware unit - does nothing on a retail unit static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr address, u64 len) { if (len == 0) { @@ -973,6 +1010,10 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) return page_table.MapPhysicalMemory(addr, size); } +static ResultCode MapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { + return MapPhysicalMemory(system, static_cast(addr), static_cast(size)); +} + /// Unmaps memory previously mapped via MapPhysicalMemory static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { std::lock_guard lock{HLE::g_hle_lock}; @@ -1023,6 +1064,10 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size return page_table.UnmapPhysicalMemory(addr, size); } +static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { + return UnmapPhysicalMemory(system, static_cast(addr), static_cast(size)); +} + /// Sets the thread activity static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); @@ -1055,6 +1100,10 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act return thread->SetActivity(static_cast(activity)); } +static ResultCode SetThreadActivity32(Core::System& system, Handle handle, u32 activity) { + return SetThreadActivity(system, handle, activity); +} + /// Gets the thread context static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) { LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); @@ -1096,6 +1145,10 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H return RESULT_SUCCESS; } +static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) { + return GetThreadContext(system, static_cast(thread_context), handle); +} + /// Gets the priority for the specified thread static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) { LOG_TRACE(Kernel_SVC, "called"); @@ -1228,6 +1281,12 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han return shared_memory->Map(*current_process, addr, size, permission_type); } +static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, + u32 size, u32 permissions) { + return MapSharedMemory(system, shared_memory_handle, static_cast(addr), + static_cast(size), permissions); +} + static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, VAddr page_info_address, Handle process_handle, VAddr address) { @@ -1426,6 +1485,10 @@ static void ExitProcess(Core::System& system) { system.CurrentScheduler().GetCurrentThread()->Stop(); } +static void ExitProcess32(Core::System& system) { + ExitProcess(system); +} + /// Creates a new thread static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, u32 priority, s32 processor_id) { @@ -1489,6 +1552,12 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e return RESULT_SUCCESS; } +static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 priority, + u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) { + return CreateThread(system, out_handle, static_cast(entry_point), static_cast(arg), + static_cast(stack_top), priority, processor_id); +} + /// Starts the thread for the provided handle static ResultCode StartThread(Core::System& system, Handle thread_handle) { LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); @@ -1506,6 +1575,10 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { return thread->Start(); } +static ResultCode StartThread32(Core::System& system, Handle thread_handle) { + return StartThread(system, thread_handle); +} + /// Called when a thread exits static void ExitThread(Core::System& system) { LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); @@ -1515,6 +1588,10 @@ static void ExitThread(Core::System& system) { current_thread->Stop(); } +static void ExitThread32(Core::System& system) { + ExitThread(system); +} + /// Sleep the current thread static void SleepThread(Core::System& system, s64 nanoseconds) { LOG_DEBUG(Kernel_SVC, "called nanoseconds={}", nanoseconds); @@ -1561,6 +1638,12 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { } } +static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) { + const s64 nanoseconds = static_cast(static_cast(nanoseconds_low) | + (static_cast(nanoseconds_high) << 32)); + SleepThread(system, nanoseconds); +} + /// Wait process wide key atomic static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_addr, VAddr condition_variable_addr, Handle thread_handle, @@ -1640,6 +1723,16 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add return current_thread->GetSignalingResult(); } +static ResultCode WaitProcessWideKeyAtomic32(Core::System& system, u32 mutex_addr, + u32 condition_variable_addr, Handle thread_handle, + u32 nanoseconds_low, u32 nanoseconds_high) { + const s64 nanoseconds = + static_cast(nanoseconds_low | (static_cast(nanoseconds_high) << 32)); + return WaitProcessWideKeyAtomic(system, static_cast(mutex_addr), + static_cast(condition_variable_addr), thread_handle, + nanoseconds); +} + /// Signal process wide key static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_addr, s32 target) { LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", @@ -1741,6 +1834,12 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, return result; } +static ResultCode WaitForAddress32(Core::System& system, u32 address, u32 type, s32 value, + u32 timeout_low, u32 timeout_high) { + s64 timeout = static_cast(timeout_low | (static_cast(timeout_high) << 32)); + return WaitForAddress(system, static_cast(address), type, value, timeout); +} + // Signals to an address (via Address Arbiter) static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, s32 value, s32 num_to_wake) { @@ -1764,6 +1863,11 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, return address_arbiter.SignalToAddress(address, signal_type, value, num_to_wake); } +static ResultCode SignalToAddress32(Core::System& system, u32 address, u32 type, s32 value, + s32 num_to_wake) { + return SignalToAddress(system, static_cast(address), type, value, num_to_wake); +} + static void KernelDebug([[maybe_unused]] Core::System& system, [[maybe_unused]] u32 kernel_debug_type, [[maybe_unused]] u64 param1, [[maybe_unused]] u64 param2, [[maybe_unused]] u64 param3) { @@ -1791,6 +1895,12 @@ static u64 GetSystemTick(Core::System& system) { return result; } +static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) { + u64 time = GetSystemTick(system); + *time_low = static_cast(time); + *time_high = static_cast(time >> 32); +} + /// Close a handle static ResultCode CloseHandle(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); @@ -1823,6 +1933,10 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) { return ERR_INVALID_HANDLE; } +static ResultCode ResetSignal32(Core::System& system, Handle handle) { + return ResetSignal(system, handle); +} + /// Creates a TransferMemory object static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size, u32 permissions) { @@ -1897,6 +2011,15 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, return RESULT_SUCCESS; } +static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core, + u32* mask_low, u32* mask_high) { + u64 mask{}; + const auto result = GetThreadCoreMask(system, thread_handle, core, &mask); + *mask_high = static_cast(mask >> 32); + *mask_low = static_cast(mask); + return result; +} + static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core, u64 affinity_mask) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}", @@ -1988,6 +2111,10 @@ static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle return RESULT_SUCCESS; } +static ResultCode CreateEvent32(Core::System& system, Handle* write_handle, Handle* read_handle) { + return CreateEvent(system, write_handle, read_handle); +} + static ResultCode ClearEvent(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); @@ -2009,6 +2136,10 @@ static ResultCode ClearEvent(Core::System& system, Handle handle) { return ERR_INVALID_HANDLE; } +static ResultCode ClearEvent32(Core::System& system, Handle handle) { + return ClearEvent(system, handle); +} + static ResultCode SignalEvent(Core::System& system, Handle handle) { LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle); @@ -2024,6 +2155,10 @@ static ResultCode SignalEvent(Core::System& system, Handle handle) { return RESULT_SUCCESS; } +static ResultCode SignalEvent32(Core::System& system, Handle handle) { + return SignalEvent(system, handle); +} + static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type); @@ -2209,6 +2344,15 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd return RESULT_SUCCESS; } +static ResultCode FlushProcessDataCache32(Core::System& system, Handle handle, u32 address, + u32 size) { + // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a nope + // as all emulation is done in the same cache level in host architecture, thus data cache + // does not need flushing. + LOG_DEBUG(Kernel_SVC, "called"); + return RESULT_SUCCESS; +} + namespace { struct FunctionDef { using Func = void(Core::System&); @@ -2224,56 +2368,56 @@ static const FunctionDef SVC_Table_32[] = { {0x01, SvcWrap32, "SetHeapSize32"}, {0x02, nullptr, "Unknown"}, {0x03, SvcWrap32, "SetMemoryAttribute32"}, - {0x04, nullptr, "MapMemory32"}, - {0x05, nullptr, "UnmapMemory32"}, + {0x04, SvcWrap32, "MapMemory32"}, + {0x05, SvcWrap32, "UnmapMemory32"}, {0x06, SvcWrap32, "QueryMemory32"}, - {0x07, nullptr, "ExitProcess32"}, - {0x08, nullptr, "CreateThread32"}, - {0x09, nullptr, "StartThread32"}, - {0x0a, nullptr, "ExitThread32"}, - {0x0b, nullptr, "SleepThread32"}, + {0x07, SvcWrap32, "ExitProcess32"}, + {0x08, SvcWrap32, "CreateThread32"}, + {0x09, SvcWrap32, "StartThread32"}, + {0x0a, SvcWrap32, "ExitThread32"}, + {0x0b, SvcWrap32, "SleepThread32"}, {0x0c, SvcWrap32, "GetThreadPriority32"}, {0x0d, SvcWrap32, "SetThreadPriority32"}, - {0x0e, nullptr, "GetThreadCoreMask32"}, + {0x0e, SvcWrap32, "GetThreadCoreMask32"}, {0x0f, SvcWrap32, "SetThreadCoreMask32"}, {0x10, SvcWrap32, "GetCurrentProcessorNumber32"}, - {0x11, nullptr, "SignalEvent32"}, - {0x12, nullptr, "ClearEvent32"}, - {0x13, nullptr, "MapSharedMemory32"}, + {0x11, SvcWrap32, "SignalEvent32"}, + {0x12, SvcWrap32, "ClearEvent32"}, + {0x13, SvcWrap32, "MapSharedMemory32"}, {0x14, nullptr, "UnmapSharedMemory32"}, {0x15, SvcWrap32, "CreateTransferMemory32"}, {0x16, SvcWrap32, "CloseHandle32"}, - {0x17, nullptr, "ResetSignal32"}, + {0x17, SvcWrap32, "ResetSignal32"}, {0x18, SvcWrap32, "WaitSynchronization32"}, - {0x19, nullptr, "CancelSynchronization32"}, - {0x1a, nullptr, "ArbitrateLock32"}, - {0x1b, nullptr, "ArbitrateUnlock32"}, - {0x1c, nullptr, "WaitProcessWideKeyAtomic32"}, + {0x19, SvcWrap32, "CancelSynchronization32"}, + {0x1a, SvcWrap32, "ArbitrateLock32"}, + {0x1b, SvcWrap32, "ArbitrateUnlock32"}, + {0x1c, SvcWrap32, "WaitProcessWideKeyAtomic32"}, {0x1d, SvcWrap32, "SignalProcessWideKey32"}, - {0x1e, nullptr, "GetSystemTick32"}, + {0x1e, SvcWrap32, "GetSystemTick32"}, {0x1f, SvcWrap32, "ConnectToNamedPort32"}, {0x20, nullptr, "Unknown"}, {0x21, SvcWrap32, "SendSyncRequest32"}, {0x22, nullptr, "SendSyncRequestWithUserBuffer32"}, {0x23, nullptr, "Unknown"}, - {0x24, nullptr, "GetProcessId32"}, + {0x24, SvcWrap32, "GetProcessId32"}, {0x25, SvcWrap32, "GetThreadId32"}, - {0x26, nullptr, "Break32"}, + {0x26, SvcWrap32, "Break32"}, {0x27, nullptr, "OutputDebugString32"}, {0x28, nullptr, "Unknown"}, {0x29, SvcWrap32, "GetInfo32"}, {0x2a, nullptr, "Unknown"}, {0x2b, nullptr, "Unknown"}, - {0x2c, nullptr, "MapPhysicalMemory32"}, - {0x2d, nullptr, "UnmapPhysicalMemory32"}, + {0x2c, SvcWrap32, "MapPhysicalMemory32"}, + {0x2d, SvcWrap32, "UnmapPhysicalMemory32"}, {0x2e, nullptr, "Unknown"}, {0x2f, nullptr, "Unknown"}, {0x30, nullptr, "Unknown"}, {0x31, nullptr, "Unknown"}, - {0x32, nullptr, "SetThreadActivity32"}, - {0x33, nullptr, "GetThreadContext32"}, - {0x34, nullptr, "WaitForAddress32"}, - {0x35, nullptr, "SignalToAddress32"}, + {0x32, SvcWrap32, "SetThreadActivity32"}, + {0x33, SvcWrap32, "GetThreadContext32"}, + {0x34, SvcWrap32, "WaitForAddress32"}, + {0x35, SvcWrap32, "SignalToAddress32"}, {0x36, nullptr, "Unknown"}, {0x37, nullptr, "Unknown"}, {0x38, nullptr, "Unknown"}, @@ -2289,7 +2433,7 @@ static const FunctionDef SVC_Table_32[] = { {0x42, nullptr, "Unknown"}, {0x43, nullptr, "ReplyAndReceive32"}, {0x44, nullptr, "Unknown"}, - {0x45, nullptr, "CreateEvent32"}, + {0x45, SvcWrap32, "CreateEvent32"}, {0x46, nullptr, "Unknown"}, {0x47, nullptr, "Unknown"}, {0x48, nullptr, "Unknown"}, @@ -2315,7 +2459,7 @@ static const FunctionDef SVC_Table_32[] = { {0x5c, nullptr, "Unknown"}, {0x5d, nullptr, "Unknown"}, {0x5e, nullptr, "Unknown"}, - {0x5F, nullptr, "FlushProcessDataCache32"}, + {0x5F, SvcWrap32, "FlushProcessDataCache32"}, {0x60, nullptr, "Unknown"}, {0x61, nullptr, "Unknown"}, {0x62, nullptr, "Unknown"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index ba90c354f..0b6dd9df0 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -350,17 +350,48 @@ void SvcWrap64(Core::System& system) { func(system, static_cast(Param(system, 0)), Param(system, 1), Param(system, 2)); } -// Used by QueryMemory32 +// Used by QueryMemory32, ArbitrateLock32 template void SvcWrap32(Core::System& system) { FuncReturn32(system, func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)).raw); } +// Used by Break32 +template +void SvcWrap32(Core::System& system) { + func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)); +} + +// Used by ExitProcess32, ExitThread32 +template +void SvcWrap32(Core::System& system) { + func(system); +} + // Used by GetCurrentProcessorNumber32 template void SvcWrap32(Core::System& system) { - FuncReturn(system, func(system)); + FuncReturn32(system, func(system)); +} + +// Used by SleepThread32 +template +void SvcWrap32(Core::System& system) { + func(system, Param32(system, 0), Param32(system, 1)); +} + +// Used by CreateThread32 +template +void SvcWrap32(Core::System& system) { + Handle param_1 = 0; + + const u32 retval = func(system, ¶m_1, Param32(system, 0), Param32(system, 1), + Param32(system, 2), Param32(system, 3), Param32(system, 4)) + .raw; + + system.CurrentArmInterface().SetReg(1, param_1); + FuncReturn(system, retval); } // Used by GetInfo32 @@ -399,6 +430,43 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } +// Used by GetSystemTick32 +template +void SvcWrap32(Core::System& system) { + u32 param_1 = 0; + u32 param_2 = 0; + + func(system, ¶m_1, ¶m_2); + system.CurrentArmInterface().SetReg(0, param_1); + system.CurrentArmInterface().SetReg(1, param_2); +} + +// Used by CreateEvent32 +template +void SvcWrap32(Core::System& system) { + Handle param_1 = 0; + Handle param_2 = 0; + + const u32 retval = func(system, ¶m_1, ¶m_2).raw; + system.CurrentArmInterface().SetReg(1, param_1); + system.CurrentArmInterface().SetReg(2, param_2); + FuncReturn(system, retval); +} + +// Used by GetThreadId32 +template +void SvcWrap32(Core::System& system) { + u32 param_1 = 0; + u32 param_2 = 0; + u32 param_3 = 0; + + const u32 retval = func(system, Param32(system, 2), ¶m_1, ¶m_2, ¶m_3).raw; + system.CurrentArmInterface().SetReg(1, param_1); + system.CurrentArmInterface().SetReg(2, param_2); + system.CurrentArmInterface().SetReg(3, param_3); + FuncReturn(system, retval); +} + // Used by SignalProcessWideKey32 template void SvcWrap32(Core::System& system) { @@ -423,7 +491,38 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } -// Used by SendSyncRequest32 +// Used by WaitProcessWideKeyAtomic32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = + func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1)), + static_cast(Param(system, 2)), static_cast(Param(system, 3)), + static_cast(Param(system, 4))) + .raw; + FuncReturn(system, retval); +} + +// Used by WaitForAddress32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = func(system, static_cast(Param(system, 0)), + static_cast(Param(system, 1)), static_cast(Param(system, 2)), + static_cast(Param(system, 3)), static_cast(Param(system, 4))) + .raw; + FuncReturn(system, retval); +} + +// Used by SignalToAddress32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = + func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1)), + static_cast(Param(system, 2)), static_cast(Param(system, 3))) + .raw; + FuncReturn(system, retval); +} + +// Used by SendSyncRequest32, ArbitrateUnlock32 template void SvcWrap32(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0))).raw); -- cgit v1.2.3 From 2f8947583f2f0af4058600243d6c1d244e3c4890 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 27 Jun 2020 18:20:06 -0400 Subject: Core/Common: Address Feedback. --- src/core/hle/kernel/kernel.cpp | 14 +++++--------- src/core/hle/kernel/physical_core.cpp | 4 ++++ src/core/hle/kernel/physical_core.h | 7 ++----- src/core/hle/kernel/scheduler.cpp | 4 ++-- src/core/hle/kernel/scheduler.h | 4 ++++ 5 files changed, 17 insertions(+), 16 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index dbb75416d..1f2af7a1b 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -472,16 +472,12 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { } void KernelCore::InvalidateAllInstructionCaches() { - if (!IsMulticore()) { - auto& threads = GlobalScheduler().GetThreadList(); - for (auto& thread : threads) { - if (!thread->IsHLEThread()) { - auto& arm_interface = thread->ArmInterface(); - arm_interface.ClearInstructionCache(); - } + auto& threads = GlobalScheduler().GetThreadList(); + for (auto& thread : threads) { + if (!thread->IsHLEThread()) { + auto& arm_interface = thread->ArmInterface(); + arm_interface.ClearInstructionCache(); } - } else { - UNIMPLEMENTED_MSG("Cache Invalidation unimplemented for multicore"); } } diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index c82c60a16..c6bbdb080 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -37,6 +37,10 @@ void PhysicalCore::Shutdown() { scheduler.Shutdown(); } +bool PhysicalCore::IsInterrupted() const { + return interrupt_handler.IsInterrupted(); +} + void PhysicalCore::Interrupt() { guard->lock(); interrupt_handler.SetInterrupt(true); diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 85f6dec05..d7a7a951c 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -7,8 +7,6 @@ #include #include -#include "core/arm/cpu_interrupt_handler.h" - namespace Common { class SpinLock; } @@ -19,6 +17,7 @@ class Scheduler; namespace Core { class ARM_Interface; +class CPUInterruptHandler; class ExclusiveMonitor; class System; } // namespace Core @@ -45,9 +44,7 @@ public: void ClearInterrupt(); /// Check if this core is interrupted - bool IsInterrupted() const { - return interrupt_handler.IsInterrupted(); - } + bool IsInterrupted() const; // Shutdown this physical core. void Shutdown(); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 61b8a396a..2b12c0dbf 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -658,7 +658,7 @@ void Scheduler::Reload() { cpu_core.LoadContext(thread->GetContext64()); cpu_core.SetTlsAddress(thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); - cpu_core.ChangeProcessorId(this->core_id); + cpu_core.ChangeProcessorID(this->core_id); cpu_core.ClearExclusiveState(); } } @@ -691,7 +691,7 @@ void Scheduler::SwitchContextStep2() { cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); - cpu_core.ChangeProcessorId(this->core_id); + cpu_core.ChangeProcessorID(this->core_id); cpu_core.ClearExclusiveState(); } } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 348107160..b3b4b5169 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -240,6 +240,10 @@ public: return switch_fiber; } + const std::shared_ptr& ControlContext() const { + return switch_fiber; + } + private: friend class GlobalScheduler; -- cgit v1.2.3