mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-30 18:24:15 +01:00 
			
		
		
		
	kernel: convert KThread to new style
This commit is contained in:
		
							parent
							
								
									ac6cbb7134
								
							
						
					
					
						commit
						6bfb4c8f71
					
				| @ -421,7 +421,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { | ||||
| static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory, | ||||
|                                                           const Kernel::KThread* thread) { | ||||
|     // Read thread type from TLS
 | ||||
|     const VAddr tls_thread_type{memory.Read32(thread->GetTLSAddress() + 0x1fc)}; | ||||
|     const VAddr tls_thread_type{memory.Read32(thread->GetTlsAddress() + 0x1fc)}; | ||||
|     const VAddr argument_thread_type{thread->GetArgument()}; | ||||
| 
 | ||||
|     if (argument_thread_type && tls_thread_type != argument_thread_type) { | ||||
| @ -452,7 +452,7 @@ static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& | ||||
| static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory, | ||||
|                                                           const Kernel::KThread* thread) { | ||||
|     // Read thread type from TLS
 | ||||
|     const VAddr tls_thread_type{memory.Read64(thread->GetTLSAddress() + 0x1f8)}; | ||||
|     const VAddr tls_thread_type{memory.Read64(thread->GetTlsAddress() + 0x1f8)}; | ||||
|     const VAddr argument_thread_type{thread->GetArgument()}; | ||||
| 
 | ||||
|     if (argument_thread_type && tls_thread_type != argument_thread_type) { | ||||
| @ -576,7 +576,7 @@ void GDBStub::HandleQuery(std::string_view command) { | ||||
|         const auto& threads = system.ApplicationProcess()->GetThreadList(); | ||||
|         std::vector<std::string> thread_ids; | ||||
|         for (const auto& thread : threads) { | ||||
|             thread_ids.push_back(fmt::format("{:x}", thread->GetThreadID())); | ||||
|             thread_ids.push_back(fmt::format("{:x}", thread->GetThreadId())); | ||||
|         } | ||||
|         SendReply(fmt::format("m{}", fmt::join(thread_ids, ","))); | ||||
|     } else if (command.starts_with("sThreadInfo")) { | ||||
| @ -591,11 +591,11 @@ void GDBStub::HandleQuery(std::string_view command) { | ||||
|         for (const auto* thread : threads) { | ||||
|             auto thread_name{GetThreadName(system, thread)}; | ||||
|             if (!thread_name) { | ||||
|                 thread_name = fmt::format("Thread {:d}", thread->GetThreadID()); | ||||
|                 thread_name = fmt::format("Thread {:d}", thread->GetThreadId()); | ||||
|             } | ||||
| 
 | ||||
|             buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)", | ||||
|                                   thread->GetThreadID(), thread->GetActiveCore(), | ||||
|                                   thread->GetThreadId(), thread->GetActiveCore(), | ||||
|                                   EscapeXML(*thread_name), GetThreadState(thread)); | ||||
|         } | ||||
| 
 | ||||
| @ -819,7 +819,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { | ||||
| Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { | ||||
|     const auto& threads{system.ApplicationProcess()->GetThreadList()}; | ||||
|     for (auto* thread : threads) { | ||||
|         if (thread->GetThreadID() == thread_id) { | ||||
|         if (thread->GetThreadId() == thread_id) { | ||||
|             return thread; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -259,7 +259,7 @@ void GDBStubA64::WriteRegisters(Kernel::KThread* thread, std::string_view regist | ||||
| std::string GDBStubA64::ThreadStatus(const Kernel::KThread* thread, u8 signal) const { | ||||
|     return fmt::format("T{:02x}{:02x}:{};{:02x}:{};{:02x}:{};thread:{:x};", signal, PC_REGISTER, | ||||
|                        RegRead(thread, PC_REGISTER), SP_REGISTER, RegRead(thread, SP_REGISTER), | ||||
|                        LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadID()); | ||||
|                        LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadId()); | ||||
| } | ||||
| 
 | ||||
| u32 GDBStubA64::BreakpointInstruction() const { | ||||
| @ -469,7 +469,7 @@ void GDBStubA32::WriteRegisters(Kernel::KThread* thread, std::string_view regist | ||||
| std::string GDBStubA32::ThreadStatus(const Kernel::KThread* thread, u8 signal) const { | ||||
|     return fmt::format("T{:02x}{:02x}:{};{:02x}:{};{:02x}:{};thread:{:x};", signal, PC_REGISTER, | ||||
|                        RegRead(thread, PC_REGISTER), SP_REGISTER, RegRead(thread, SP_REGISTER), | ||||
|                        LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadID()); | ||||
|                        LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadId()); | ||||
| } | ||||
| 
 | ||||
| u32 GDBStubA32::BreakpointInstruction() const { | ||||
|  | ||||
| @ -29,7 +29,7 @@ Result KClientSession::SendSyncRequest() { | ||||
|     SCOPE_EXIT({ request->Close(); }); | ||||
| 
 | ||||
|     // Initialize the request.
 | ||||
|     request->Initialize(nullptr, GetCurrentThread(m_kernel).GetTLSAddress(), MessageBufferSize); | ||||
|     request->Initialize(nullptr, GetCurrentThread(m_kernel).GetTlsAddress(), MessageBufferSize); | ||||
| 
 | ||||
|     // Send the request.
 | ||||
|     R_RETURN(m_parent->GetServerSession().OnRequest(request)); | ||||
|  | ||||
| @ -177,7 +177,6 @@ Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) | ||||
|         // Begin waiting.
 | ||||
|         cur_thread->BeginWait(std::addressof(wait_queue)); | ||||
|         cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); | ||||
|         cur_thread->SetMutexWaitAddressForDebugging(addr); | ||||
|     } | ||||
| 
 | ||||
|     // Close our reference to the owner thread, now that the wait is over.
 | ||||
| @ -324,7 +323,6 @@ Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { | ||||
|         wait_queue.SetHardwareTimer(timer); | ||||
|         cur_thread->BeginWait(std::addressof(wait_queue)); | ||||
|         cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); | ||||
|         cur_thread->SetMutexWaitAddressForDebugging(addr); | ||||
|     } | ||||
| 
 | ||||
|     // Get the wait result.
 | ||||
|  | ||||
| @ -41,16 +41,16 @@ private: | ||||
|     ThreadTree m_tree{}; | ||||
| }; | ||||
| 
 | ||||
| inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree, | ||||
| inline void BeforeUpdatePriority(KernelCore& kernel, KConditionVariable::ThreadTree* tree, | ||||
|                                  KThread* thread) { | ||||
|     ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||||
|     ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); | ||||
| 
 | ||||
|     tree->erase(tree->iterator_to(*thread)); | ||||
| } | ||||
| 
 | ||||
| inline void AfterUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree, | ||||
| inline void AfterUpdatePriority(KernelCore& kernel, KConditionVariable::ThreadTree* tree, | ||||
|                                 KThread* thread) { | ||||
|     ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||||
|     ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); | ||||
| 
 | ||||
|     tree->insert(*thread); | ||||
| } | ||||
|  | ||||
| @ -52,7 +52,6 @@ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority | ||||
|     Handle thread_handle{}; | ||||
|     owner_process.GetHandleTable().Add(std::addressof(thread_handle), thread); | ||||
| 
 | ||||
|     thread->SetName("main"); | ||||
|     thread->GetContext32().cpu_registers[0] = 0; | ||||
|     thread->GetContext64().cpu_registers[0] = 0; | ||||
|     thread->GetContext32().cpu_registers[1] = thread_handle; | ||||
|  | ||||
| @ -411,7 +411,7 @@ void KScheduler::ScheduleImpl() { | ||||
|     m_switch_cur_thread = cur_thread; | ||||
|     m_switch_highest_priority_thread = highest_priority_thread; | ||||
|     m_switch_from_schedule = true; | ||||
|     Common::Fiber::YieldTo(cur_thread->host_context, *m_switch_fiber); | ||||
|     Common::Fiber::YieldTo(cur_thread->m_host_context, *m_switch_fiber); | ||||
| 
 | ||||
|     // Returning from ScheduleImpl occurs after this thread has been scheduled again.
 | ||||
| } | ||||
| @ -450,7 +450,7 @@ void KScheduler::ScheduleImplFiber() { | ||||
| 
 | ||||
|         // We want to try to lock the highest priority thread's context.
 | ||||
|         // Try to take it.
 | ||||
|         while (!highest_priority_thread->context_guard.try_lock()) { | ||||
|         while (!highest_priority_thread->m_context_guard.try_lock()) { | ||||
|             // The highest priority thread's context is already locked.
 | ||||
|             // Check if we need scheduling. If we don't, we can retry directly.
 | ||||
|             if (m_state.needs_scheduling.load(std::memory_order_seq_cst)) { | ||||
| @ -468,7 +468,7 @@ void KScheduler::ScheduleImplFiber() { | ||||
|         if (m_state.needs_scheduling.load(std::memory_order_seq_cst)) { | ||||
|             // Our switch failed.
 | ||||
|             // We should unlock the thread context, and then retry.
 | ||||
|             highest_priority_thread->context_guard.unlock(); | ||||
|             highest_priority_thread->m_context_guard.unlock(); | ||||
|             goto retry; | ||||
|         } else { | ||||
|             break; | ||||
| @ -489,7 +489,7 @@ void KScheduler::ScheduleImplFiber() { | ||||
|     Reload(highest_priority_thread); | ||||
| 
 | ||||
|     // Reload the host thread.
 | ||||
|     Common::Fiber::YieldTo(m_switch_fiber, *highest_priority_thread->host_context); | ||||
|     Common::Fiber::YieldTo(m_switch_fiber, *highest_priority_thread->m_host_context); | ||||
| } | ||||
| 
 | ||||
| void KScheduler::Unload(KThread* thread) { | ||||
| @ -497,13 +497,13 @@ void KScheduler::Unload(KThread* thread) { | ||||
|     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()); | ||||
|     thread->SetTpidrEl0(cpu_core.GetTPIDR_EL0()); | ||||
|     cpu_core.ClearExclusiveState(); | ||||
| 
 | ||||
|     // Check if the thread is terminated by checking the DPC flags.
 | ||||
|     if ((thread->GetStackParameters().dpc_flags & static_cast<u32>(DpcFlag::Terminated)) == 0) { | ||||
|         // The thread isn't terminated, so we want to unlock it.
 | ||||
|         thread->context_guard.unlock(); | ||||
|         thread->m_context_guard.unlock(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -511,8 +511,8 @@ void KScheduler::Reload(KThread* thread) { | ||||
|     auto& cpu_core = m_kernel.System().ArmInterface(m_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.SetTlsAddress(thread->GetTlsAddress()); | ||||
|     cpu_core.SetTPIDR_EL0(thread->GetTpidrEl0()); | ||||
|     cpu_core.LoadWatchpointArray(thread->GetOwnerProcess()->GetWatchpoints()); | ||||
|     cpu_core.ClearExclusiveState(); | ||||
| } | ||||
|  | ||||
| @ -226,7 +226,7 @@ Result KServerSession::SendReply(bool is_hle) { | ||||
|             KThread* server_thread{GetCurrentThreadPointer(m_kernel)}; | ||||
|             UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); | ||||
| 
 | ||||
|             auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); | ||||
|             auto* src_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress()); | ||||
|             auto* dst_msg_buffer = memory.GetPointer(client_message); | ||||
|             std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); | ||||
|         } | ||||
| @ -334,7 +334,7 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext | ||||
|         UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); | ||||
| 
 | ||||
|         auto* src_msg_buffer = memory.GetPointer(client_message); | ||||
|         auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); | ||||
|         auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress()); | ||||
|         std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -108,11 +108,11 @@ enum class StepState : u32 { | ||||
| }; | ||||
| 
 | ||||
| void SetCurrentThread(KernelCore& kernel, KThread* thread); | ||||
| [[nodiscard]] KThread* GetCurrentThreadPointer(KernelCore& kernel); | ||||
| [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); | ||||
| [[nodiscard]] KProcess* GetCurrentProcessPointer(KernelCore& kernel); | ||||
| [[nodiscard]] KProcess& GetCurrentProcess(KernelCore& kernel); | ||||
| [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); | ||||
| KThread* GetCurrentThreadPointer(KernelCore& kernel); | ||||
| KThread& GetCurrentThread(KernelCore& kernel); | ||||
| KProcess* GetCurrentProcessPointer(KernelCore& kernel); | ||||
| KProcess& GetCurrentProcess(KernelCore& kernel); | ||||
| s32 GetCurrentCoreId(KernelCore& kernel); | ||||
| 
 | ||||
| class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>, | ||||
|                       public boost::intrusive::list_base_hook<>, | ||||
| @ -136,16 +136,12 @@ public: | ||||
|     using ThreadContext64 = Core::ARM_Interface::ThreadContext64; | ||||
|     using WaiterList = boost::intrusive::list<KThread>; | ||||
| 
 | ||||
|     void SetName(std::string new_name) { | ||||
|         name = std::move(new_name); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets the thread's current priority | ||||
|      * @return The current thread's priority | ||||
|      */ | ||||
|     [[nodiscard]] s32 GetPriority() const { | ||||
|         return priority; | ||||
|     s32 GetPriority() const { | ||||
|         return m_priority; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
| @ -153,23 +149,23 @@ public: | ||||
|      * @param priority The new priority. | ||||
|      */ | ||||
|     void SetPriority(s32 value) { | ||||
|         priority = value; | ||||
|         m_priority = value; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets the thread's nominal priority. | ||||
|      * @return The current thread's nominal priority. | ||||
|      */ | ||||
|     [[nodiscard]] s32 GetBasePriority() const { | ||||
|         return base_priority; | ||||
|     s32 GetBasePriority() const { | ||||
|         return m_base_priority; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets the thread's thread ID | ||||
|      * @return The thread's ID | ||||
|      */ | ||||
|     [[nodiscard]] u64 GetThreadID() const { | ||||
|         return thread_id; | ||||
|     u64 GetThreadId() const { | ||||
|         return m_thread_id; | ||||
|     } | ||||
| 
 | ||||
|     void ContinueIfHasKernelWaiters() { | ||||
| @ -180,7 +176,7 @@ public: | ||||
| 
 | ||||
|     void SetBasePriority(s32 value); | ||||
| 
 | ||||
|     [[nodiscard]] Result Run(); | ||||
|     Result Run(); | ||||
| 
 | ||||
|     void Exit(); | ||||
| 
 | ||||
| @ -188,22 +184,22 @@ public: | ||||
| 
 | ||||
|     ThreadState RequestTerminate(); | ||||
| 
 | ||||
|     [[nodiscard]] u32 GetSuspendFlags() const { | ||||
|         return suspend_allowed_flags & suspend_request_flags; | ||||
|     u32 GetSuspendFlags() const { | ||||
|         return m_suspend_allowed_flags & m_suspend_request_flags; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool IsSuspended() const { | ||||
|     bool IsSuspended() const { | ||||
|         return GetSuspendFlags() != 0; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool IsSuspendRequested(SuspendType type) const { | ||||
|         return (suspend_request_flags & | ||||
|                 (1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)))) != | ||||
|     bool IsSuspendRequested(SuspendType type) const { | ||||
|         return (m_suspend_request_flags & | ||||
|                 (1U << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)))) != | ||||
|                0; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool IsSuspendRequested() const { | ||||
|         return suspend_request_flags != 0; | ||||
|     bool IsSuspendRequested() const { | ||||
|         return m_suspend_request_flags != 0; | ||||
|     } | ||||
| 
 | ||||
|     void RequestSuspend(SuspendType type); | ||||
| @ -217,124 +213,124 @@ public: | ||||
|     void Continue(); | ||||
| 
 | ||||
|     constexpr void SetSyncedIndex(s32 index) { | ||||
|         synced_index = index; | ||||
|         m_synced_index = index; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] constexpr s32 GetSyncedIndex() const { | ||||
|         return synced_index; | ||||
|     constexpr s32 GetSyncedIndex() const { | ||||
|         return m_synced_index; | ||||
|     } | ||||
| 
 | ||||
|     constexpr void SetWaitResult(Result wait_res) { | ||||
|         wait_result = wait_res; | ||||
|         m_wait_result = wait_res; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] constexpr Result GetWaitResult() const { | ||||
|         return wait_result; | ||||
|     constexpr Result GetWaitResult() const { | ||||
|         return m_wait_result; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * Returns the Thread Local Storage address of the current thread | ||||
|      * @returns VAddr of the thread's TLS | ||||
|      */ | ||||
|     [[nodiscard]] VAddr GetTLSAddress() const { | ||||
|         return tls_address; | ||||
|     VAddr GetTlsAddress() const { | ||||
|         return m_tls_address; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|      * Returns the value of the TPIDR_EL0 Read/Write system register for this thread. | ||||
|      * @returns The value of the TPIDR_EL0 register. | ||||
|      */ | ||||
|     [[nodiscard]] u64 GetTPIDR_EL0() const { | ||||
|         return thread_context_64.tpidr; | ||||
|     u64 GetTpidrEl0() const { | ||||
|         return m_thread_context_64.tpidr; | ||||
|     } | ||||
| 
 | ||||
|     /// Sets the value of the TPIDR_EL0 Read/Write system register for this thread.
 | ||||
|     void SetTPIDR_EL0(u64 value) { | ||||
|         thread_context_64.tpidr = value; | ||||
|         thread_context_32.tpidr = static_cast<u32>(value); | ||||
|     void SetTpidrEl0(u64 value) { | ||||
|         m_thread_context_64.tpidr = value; | ||||
|         m_thread_context_32.tpidr = static_cast<u32>(value); | ||||
|     } | ||||
| 
 | ||||
|     void CloneFpuStatus(); | ||||
| 
 | ||||
|     [[nodiscard]] ThreadContext32& GetContext32() { | ||||
|         return thread_context_32; | ||||
|     ThreadContext32& GetContext32() { | ||||
|         return m_thread_context_32; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] const ThreadContext32& GetContext32() const { | ||||
|         return thread_context_32; | ||||
|     const ThreadContext32& GetContext32() const { | ||||
|         return m_thread_context_32; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] ThreadContext64& GetContext64() { | ||||
|         return thread_context_64; | ||||
|     ThreadContext64& GetContext64() { | ||||
|         return m_thread_context_64; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] const ThreadContext64& GetContext64() const { | ||||
|         return thread_context_64; | ||||
|     const ThreadContext64& GetContext64() const { | ||||
|         return m_thread_context_64; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] std::shared_ptr<Common::Fiber>& GetHostContext(); | ||||
|     std::shared_ptr<Common::Fiber>& GetHostContext(); | ||||
| 
 | ||||
|     [[nodiscard]] ThreadState GetState() const { | ||||
|         return thread_state.load(std::memory_order_relaxed) & ThreadState::Mask; | ||||
|     ThreadState GetState() const { | ||||
|         return m_thread_state.load(std::memory_order_relaxed) & ThreadState::Mask; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] ThreadState GetRawState() const { | ||||
|         return thread_state.load(std::memory_order_relaxed); | ||||
|     ThreadState GetRawState() const { | ||||
|         return m_thread_state.load(std::memory_order_relaxed); | ||||
|     } | ||||
| 
 | ||||
|     void SetState(ThreadState state); | ||||
| 
 | ||||
|     [[nodiscard]] StepState GetStepState() const { | ||||
|         return step_state; | ||||
|     StepState GetStepState() const { | ||||
|         return m_step_state; | ||||
|     } | ||||
| 
 | ||||
|     void SetStepState(StepState state) { | ||||
|         step_state = state; | ||||
|         m_step_state = state; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] s64 GetLastScheduledTick() const { | ||||
|         return last_scheduled_tick; | ||||
|     s64 GetLastScheduledTick() const { | ||||
|         return m_last_scheduled_tick; | ||||
|     } | ||||
| 
 | ||||
|     void SetLastScheduledTick(s64 tick) { | ||||
|         last_scheduled_tick = tick; | ||||
|         m_last_scheduled_tick = tick; | ||||
|     } | ||||
| 
 | ||||
|     void AddCpuTime([[maybe_unused]] s32 core_id_, s64 amount) { | ||||
|         cpu_time += amount; | ||||
|     void AddCpuTime(s32 core_id, s64 amount) { | ||||
|         m_cpu_time += amount; | ||||
|         // TODO(bunnei): Debug kernels track per-core tick counts. Should we?
 | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] s64 GetCpuTime() const { | ||||
|         return cpu_time; | ||||
|     s64 GetCpuTime() const { | ||||
|         return m_cpu_time; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] s32 GetActiveCore() const { | ||||
|         return core_id; | ||||
|     s32 GetActiveCore() const { | ||||
|         return m_core_id; | ||||
|     } | ||||
| 
 | ||||
|     void SetActiveCore(s32 core) { | ||||
|         core_id = core; | ||||
|         m_core_id = core; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] s32 GetCurrentCore() const { | ||||
|         return current_core_id; | ||||
|     s32 GetCurrentCore() const { | ||||
|         return m_current_core_id; | ||||
|     } | ||||
| 
 | ||||
|     void SetCurrentCore(s32 core) { | ||||
|         current_core_id = core; | ||||
|         m_current_core_id = core; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] KProcess* GetOwnerProcess() { | ||||
|         return parent; | ||||
|     KProcess* GetOwnerProcess() { | ||||
|         return m_parent; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] const KProcess* GetOwnerProcess() const { | ||||
|         return parent; | ||||
|     const KProcess* GetOwnerProcess() const { | ||||
|         return m_parent; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool IsUserThread() const { | ||||
|         return parent != nullptr; | ||||
|     bool IsUserThread() const { | ||||
|         return m_parent != nullptr; | ||||
|     } | ||||
| 
 | ||||
|     u16 GetUserDisableCount() const; | ||||
| @ -343,69 +339,69 @@ public: | ||||
| 
 | ||||
|     KThread* GetLockOwner() const; | ||||
| 
 | ||||
|     [[nodiscard]] const KAffinityMask& GetAffinityMask() const { | ||||
|         return physical_affinity_mask; | ||||
|     const KAffinityMask& GetAffinityMask() const { | ||||
|         return m_physical_affinity_mask; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] Result GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask); | ||||
|     Result GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask); | ||||
| 
 | ||||
|     [[nodiscard]] Result GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask); | ||||
|     Result GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask); | ||||
| 
 | ||||
|     [[nodiscard]] Result SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask); | ||||
|     Result SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask); | ||||
| 
 | ||||
|     [[nodiscard]] Result SetActivity(Svc::ThreadActivity activity); | ||||
|     Result SetActivity(Svc::ThreadActivity activity); | ||||
| 
 | ||||
|     [[nodiscard]] Result Sleep(s64 timeout); | ||||
|     Result Sleep(s64 timeout); | ||||
| 
 | ||||
|     [[nodiscard]] s64 GetYieldScheduleCount() const { | ||||
|         return schedule_count; | ||||
|     s64 GetYieldScheduleCount() const { | ||||
|         return m_schedule_count; | ||||
|     } | ||||
| 
 | ||||
|     void SetYieldScheduleCount(s64 count) { | ||||
|         schedule_count = count; | ||||
|         m_schedule_count = count; | ||||
|     } | ||||
| 
 | ||||
|     void WaitCancel(); | ||||
| 
 | ||||
|     [[nodiscard]] bool IsWaitCancelled() const { | ||||
|         return wait_cancelled; | ||||
|     bool IsWaitCancelled() const { | ||||
|         return m_wait_cancelled; | ||||
|     } | ||||
| 
 | ||||
|     void ClearWaitCancelled() { | ||||
|         wait_cancelled = false; | ||||
|         m_wait_cancelled = false; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool IsCancellable() const { | ||||
|         return cancellable; | ||||
|     bool IsCancellable() const { | ||||
|         return m_cancellable; | ||||
|     } | ||||
| 
 | ||||
|     void SetCancellable() { | ||||
|         cancellable = true; | ||||
|         m_cancellable = true; | ||||
|     } | ||||
| 
 | ||||
|     void ClearCancellable() { | ||||
|         cancellable = false; | ||||
|         m_cancellable = false; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool IsTerminationRequested() const { | ||||
|         return termination_requested || GetRawState() == ThreadState::Terminated; | ||||
|     bool IsTerminationRequested() const { | ||||
|         return m_termination_requested || GetRawState() == ThreadState::Terminated; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] u64 GetId() const override { | ||||
|         return this->GetThreadID(); | ||||
|     u64 GetId() const override { | ||||
|         return this->GetThreadId(); | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool IsInitialized() const override { | ||||
|         return initialized; | ||||
|     bool IsInitialized() const override { | ||||
|         return m_initialized; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] uintptr_t GetPostDestroyArgument() const override { | ||||
|         return reinterpret_cast<uintptr_t>(parent) | (resource_limit_release_hint ? 1 : 0); | ||||
|     uintptr_t GetPostDestroyArgument() const override { | ||||
|         return reinterpret_cast<uintptr_t>(m_parent) | (m_resource_limit_release_hint ? 1 : 0); | ||||
|     } | ||||
| 
 | ||||
|     void Finalize() override; | ||||
| 
 | ||||
|     [[nodiscard]] bool IsSignaled() const override; | ||||
|     bool IsSignaled() const override; | ||||
| 
 | ||||
|     void OnTimer(); | ||||
| 
 | ||||
| @ -413,26 +409,22 @@ public: | ||||
| 
 | ||||
|     static void PostDestroy(uintptr_t arg); | ||||
| 
 | ||||
|     [[nodiscard]] static Result InitializeDummyThread(KThread* thread, KProcess* owner); | ||||
|     static Result InitializeDummyThread(KThread* thread, KProcess* owner); | ||||
| 
 | ||||
|     [[nodiscard]] static Result InitializeMainThread(Core::System& system, KThread* thread, | ||||
|                                                      s32 virt_core); | ||||
|     static Result InitializeMainThread(Core::System& system, KThread* thread, s32 virt_core); | ||||
| 
 | ||||
|     [[nodiscard]] static Result InitializeIdleThread(Core::System& system, KThread* thread, | ||||
|                                                      s32 virt_core); | ||||
|     static Result InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core); | ||||
| 
 | ||||
|     [[nodiscard]] static Result InitializeHighPriorityThread(Core::System& system, KThread* thread, | ||||
|                                                              KThreadFunction func, uintptr_t arg, | ||||
|                                                              s32 virt_core); | ||||
|     static Result InitializeHighPriorityThread(Core::System& system, KThread* thread, | ||||
|                                                KThreadFunction func, uintptr_t arg, s32 virt_core); | ||||
| 
 | ||||
|     [[nodiscard]] static Result InitializeUserThread(Core::System& system, KThread* thread, | ||||
|                                                      KThreadFunction func, uintptr_t arg, | ||||
|                                                      VAddr user_stack_top, s32 prio, s32 virt_core, | ||||
|                                                      KProcess* owner); | ||||
|     static Result InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func, | ||||
|                                        uintptr_t arg, VAddr user_stack_top, s32 prio, s32 virt_core, | ||||
|                                        KProcess* owner); | ||||
| 
 | ||||
|     [[nodiscard]] static Result InitializeServiceThread(Core::System& system, KThread* thread, | ||||
|                                                         std::function<void()>&& thread_func, | ||||
|                                                         s32 prio, s32 virt_core, KProcess* owner); | ||||
|     static Result InitializeServiceThread(Core::System& system, KThread* thread, | ||||
|                                           std::function<void()>&& thread_func, s32 prio, | ||||
|                                           s32 virt_core, KProcess* owner); | ||||
| 
 | ||||
| public: | ||||
|     struct StackParameters { | ||||
| @ -446,12 +438,12 @@ public: | ||||
|         KThread* cur_thread; | ||||
|     }; | ||||
| 
 | ||||
|     [[nodiscard]] StackParameters& GetStackParameters() { | ||||
|         return stack_parameters; | ||||
|     StackParameters& GetStackParameters() { | ||||
|         return m_stack_parameters; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] const StackParameters& GetStackParameters() const { | ||||
|         return stack_parameters; | ||||
|     const StackParameters& GetStackParameters() const { | ||||
|         return m_stack_parameters; | ||||
|     } | ||||
| 
 | ||||
|     class QueueEntry { | ||||
| @ -459,37 +451,37 @@ public: | ||||
|         constexpr QueueEntry() = default; | ||||
| 
 | ||||
|         constexpr void Initialize() { | ||||
|             prev = nullptr; | ||||
|             next = nullptr; | ||||
|             m_prev = nullptr; | ||||
|             m_next = nullptr; | ||||
|         } | ||||
| 
 | ||||
|         constexpr KThread* GetPrev() const { | ||||
|             return prev; | ||||
|             return m_prev; | ||||
|         } | ||||
|         constexpr KThread* GetNext() const { | ||||
|             return next; | ||||
|             return m_next; | ||||
|         } | ||||
|         constexpr void SetPrev(KThread* thread) { | ||||
|             prev = thread; | ||||
|             m_prev = thread; | ||||
|         } | ||||
|         constexpr void SetNext(KThread* thread) { | ||||
|             next = thread; | ||||
|             m_next = thread; | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         KThread* prev{}; | ||||
|         KThread* next{}; | ||||
|         KThread* m_prev{}; | ||||
|         KThread* m_next{}; | ||||
|     }; | ||||
| 
 | ||||
|     [[nodiscard]] QueueEntry& GetPriorityQueueEntry(s32 core) { | ||||
|         return per_core_priority_queue_entry[core]; | ||||
|     QueueEntry& GetPriorityQueueEntry(s32 core) { | ||||
|         return m_per_core_priority_queue_entry[core]; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] const QueueEntry& GetPriorityQueueEntry(s32 core) const { | ||||
|         return per_core_priority_queue_entry[core]; | ||||
|     const QueueEntry& GetPriorityQueueEntry(s32 core) const { | ||||
|         return m_per_core_priority_queue_entry[core]; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] s32 GetDisableDispatchCount() const { | ||||
|     s32 GetDisableDispatchCount() const { | ||||
|         return this->GetStackParameters().disable_count; | ||||
|     } | ||||
| 
 | ||||
| @ -515,7 +507,7 @@ public: | ||||
|         this->GetStackParameters().is_in_exception_handler = false; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool IsInExceptionHandler() const { | ||||
|     bool IsInExceptionHandler() const { | ||||
|         return this->GetStackParameters().is_in_exception_handler; | ||||
|     } | ||||
| 
 | ||||
| @ -527,11 +519,11 @@ public: | ||||
|         this->GetStackParameters().is_calling_svc = false; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool IsCallingSvc() const { | ||||
|     bool IsCallingSvc() const { | ||||
|         return this->GetStackParameters().is_calling_svc; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] u8 GetSvcId() const { | ||||
|     u8 GetSvcId() const { | ||||
|         return this->GetStackParameters().current_svc_id; | ||||
|     } | ||||
| 
 | ||||
| @ -543,78 +535,54 @@ public: | ||||
|         this->GetStackParameters().dpc_flags &= ~static_cast<u8>(flag); | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] u8 GetDpc() const { | ||||
|     u8 GetDpc() const { | ||||
|         return this->GetStackParameters().dpc_flags; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool HasDpc() const { | ||||
|     bool HasDpc() const { | ||||
|         return this->GetDpc() != 0; | ||||
|     } | ||||
| 
 | ||||
|     void SetWaitReasonForDebugging(ThreadWaitReasonForDebugging reason) { | ||||
|         wait_reason_for_debugging = reason; | ||||
|         m_wait_reason_for_debugging = reason; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] ThreadWaitReasonForDebugging GetWaitReasonForDebugging() const { | ||||
|         return wait_reason_for_debugging; | ||||
|     ThreadWaitReasonForDebugging GetWaitReasonForDebugging() const { | ||||
|         return m_wait_reason_for_debugging; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] ThreadType GetThreadType() const { | ||||
|         return thread_type; | ||||
|     ThreadType GetThreadType() const { | ||||
|         return m_thread_type; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool IsDummyThread() const { | ||||
|         return GetThreadType() == ThreadType::Dummy; | ||||
|     } | ||||
| 
 | ||||
|     void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { | ||||
|         wait_objects_for_debugging.clear(); | ||||
|         wait_objects_for_debugging.reserve(objects.size()); | ||||
|         for (const auto& object : objects) { | ||||
|             wait_objects_for_debugging.emplace_back(object); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] const std::vector<KSynchronizationObject*>& GetWaitObjectsForDebugging() const { | ||||
|         return wait_objects_for_debugging; | ||||
|     } | ||||
| 
 | ||||
|     void SetMutexWaitAddressForDebugging(VAddr address) { | ||||
|         mutex_wait_address_for_debugging = address; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] VAddr GetMutexWaitAddressForDebugging() const { | ||||
|         return mutex_wait_address_for_debugging; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] s32 GetIdealCoreForDebugging() const { | ||||
|         return virtual_ideal_core_id; | ||||
|     bool IsDummyThread() const { | ||||
|         return this->GetThreadType() == ThreadType::Dummy; | ||||
|     } | ||||
| 
 | ||||
|     void AddWaiter(KThread* thread); | ||||
| 
 | ||||
|     void RemoveWaiter(KThread* thread); | ||||
| 
 | ||||
|     [[nodiscard]] Result GetThreadContext3(std::vector<u8>& out); | ||||
|     Result GetThreadContext3(std::vector<u8>& out); | ||||
| 
 | ||||
|     [[nodiscard]] KThread* RemoveUserWaiterByKey(bool* out_has_waiters, VAddr key) { | ||||
|     KThread* RemoveUserWaiterByKey(bool* out_has_waiters, VAddr key) { | ||||
|         return this->RemoveWaiterByKey(out_has_waiters, key, false); | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] KThread* RemoveKernelWaiterByKey(bool* out_has_waiters, VAddr key) { | ||||
|     KThread* RemoveKernelWaiterByKey(bool* out_has_waiters, VAddr key) { | ||||
|         return this->RemoveWaiterByKey(out_has_waiters, key, true); | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] VAddr GetAddressKey() const { | ||||
|         return address_key; | ||||
|     VAddr GetAddressKey() const { | ||||
|         return m_address_key; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] u32 GetAddressKeyValue() const { | ||||
|         return address_key_value; | ||||
|     u32 GetAddressKeyValue() const { | ||||
|         return m_address_key_value; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool GetIsKernelAddressKey() const { | ||||
|         return is_kernel_address_key; | ||||
|     bool GetIsKernelAddressKey() const { | ||||
|         return m_is_kernel_address_key; | ||||
|     } | ||||
| 
 | ||||
|     //! NB: intentional deviation from official kernel.
 | ||||
| @ -624,37 +592,37 @@ public: | ||||
|     // into things.
 | ||||
| 
 | ||||
|     void SetUserAddressKey(VAddr key, u32 val) { | ||||
|         ASSERT(waiting_lock_info == nullptr); | ||||
|         address_key = key; | ||||
|         address_key_value = val; | ||||
|         is_kernel_address_key = false; | ||||
|         ASSERT(m_waiting_lock_info == nullptr); | ||||
|         m_address_key = key; | ||||
|         m_address_key_value = val; | ||||
|         m_is_kernel_address_key = false; | ||||
|     } | ||||
| 
 | ||||
|     void SetKernelAddressKey(VAddr key) { | ||||
|         ASSERT(waiting_lock_info == nullptr); | ||||
|         address_key = key; | ||||
|         is_kernel_address_key = true; | ||||
|         ASSERT(m_waiting_lock_info == nullptr); | ||||
|         m_address_key = key; | ||||
|         m_is_kernel_address_key = true; | ||||
|     } | ||||
| 
 | ||||
|     void ClearWaitQueue() { | ||||
|         wait_queue = nullptr; | ||||
|         m_wait_queue = nullptr; | ||||
|     } | ||||
| 
 | ||||
|     void BeginWait(KThreadQueue* queue); | ||||
|     void NotifyAvailable(KSynchronizationObject* signaled_object, Result wait_result_); | ||||
|     void EndWait(Result wait_result_); | ||||
|     void CancelWait(Result wait_result_, bool cancel_timer_task); | ||||
|     void NotifyAvailable(KSynchronizationObject* signaled_object, Result wait_result); | ||||
|     void EndWait(Result wait_result); | ||||
|     void CancelWait(Result wait_result, bool cancel_timer_task); | ||||
| 
 | ||||
|     [[nodiscard]] s32 GetNumKernelWaiters() const { | ||||
|         return num_kernel_waiters; | ||||
|     s32 GetNumKernelWaiters() const { | ||||
|         return m_num_kernel_waiters; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] u64 GetConditionVariableKey() const { | ||||
|         return condvar_key; | ||||
|     u64 GetConditionVariableKey() const { | ||||
|         return m_condvar_key; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] u64 GetAddressArbiterKey() const { | ||||
|         return condvar_key; | ||||
|     u64 GetAddressArbiterKey() const { | ||||
|         return m_condvar_key; | ||||
|     } | ||||
| 
 | ||||
|     // Dummy threads (used for HLE host threads) cannot wait based on the guest scheduler, and
 | ||||
| @ -665,17 +633,16 @@ public: | ||||
|     void DummyThreadBeginWait(); | ||||
|     void DummyThreadEndWait(); | ||||
| 
 | ||||
|     [[nodiscard]] uintptr_t GetArgument() const { | ||||
|         return argument; | ||||
|     uintptr_t GetArgument() const { | ||||
|         return m_argument; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] VAddr GetUserStackTop() const { | ||||
|         return stack_top; | ||||
|     VAddr GetUserStackTop() const { | ||||
|         return m_stack_top; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     [[nodiscard]] KThread* RemoveWaiterByKey(bool* out_has_waiters, VAddr key, | ||||
|                                              bool is_kernel_address_key); | ||||
|     KThread* RemoveWaiterByKey(bool* out_has_waiters, VAddr key, bool is_kernel_address_key); | ||||
| 
 | ||||
|     static constexpr size_t PriorityInheritanceCountMax = 10; | ||||
|     union SyncObjectBuffer { | ||||
| @ -692,11 +659,11 @@ private: | ||||
|             u64 cv_key{}; | ||||
|             s32 priority{}; | ||||
| 
 | ||||
|             [[nodiscard]] constexpr u64 GetConditionVariableKey() const { | ||||
|             constexpr u64 GetConditionVariableKey() const { | ||||
|                 return cv_key; | ||||
|             } | ||||
| 
 | ||||
|             [[nodiscard]] constexpr s32 GetPriority() const { | ||||
|             constexpr s32 GetPriority() const { | ||||
|                 return priority; | ||||
|             } | ||||
|         }; | ||||
| @ -728,22 +695,21 @@ private: | ||||
| 
 | ||||
|     void IncreaseBasePriority(s32 priority); | ||||
| 
 | ||||
|     [[nodiscard]] Result Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, | ||||
|                                     s32 prio, s32 virt_core, KProcess* owner, ThreadType type); | ||||
|     Result Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, | ||||
|                       s32 virt_core, KProcess* owner, ThreadType type); | ||||
| 
 | ||||
|     [[nodiscard]] static Result InitializeThread(KThread* thread, KThreadFunction func, | ||||
|                                                  uintptr_t arg, VAddr user_stack_top, s32 prio, | ||||
|                                                  s32 core, KProcess* owner, ThreadType type, | ||||
|                                                  std::function<void()>&& init_func); | ||||
|     static Result InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg, | ||||
|                                    VAddr user_stack_top, s32 prio, s32 core, KProcess* owner, | ||||
|                                    ThreadType type, std::function<void()>&& init_func); | ||||
| 
 | ||||
|     // For core KThread implementation
 | ||||
|     ThreadContext32 thread_context_32{}; | ||||
|     ThreadContext64 thread_context_64{}; | ||||
|     Common::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node{}; | ||||
|     s32 priority{}; | ||||
|     ThreadContext32 m_thread_context_32{}; | ||||
|     ThreadContext64 m_thread_context_64{}; | ||||
|     Common::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node{}; | ||||
|     s32 m_priority{}; | ||||
|     using ConditionVariableThreadTreeTraits = | ||||
|         Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert< | ||||
|             &KThread::condvar_arbiter_tree_node>; | ||||
|             &KThread::m_condvar_arbiter_tree_node>; | ||||
|     using ConditionVariableThreadTree = | ||||
|         ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>; | ||||
| 
 | ||||
| @ -773,7 +739,7 @@ private: | ||||
| 
 | ||||
|     using LockWithPriorityInheritanceThreadTreeTraits = | ||||
|         Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert< | ||||
|             &KThread::condvar_arbiter_tree_node>; | ||||
|             &KThread::m_condvar_arbiter_tree_node>; | ||||
|     using LockWithPriorityInheritanceThreadTree = | ||||
|         ConditionVariableThreadTreeTraits::TreeType<LockWithPriorityInheritanceComparator>; | ||||
| 
 | ||||
| @ -809,7 +775,7 @@ public: | ||||
|             waiter->SetWaitingLockInfo(this); | ||||
|         } | ||||
| 
 | ||||
|         [[nodiscard]] bool RemoveWaiter(KThread* waiter) { | ||||
|         bool RemoveWaiter(KThread* waiter) { | ||||
|             m_tree.erase(m_tree.iterator_to(*waiter)); | ||||
| 
 | ||||
|             waiter->SetWaitingLockInfo(nullptr); | ||||
| @ -853,11 +819,11 @@ public: | ||||
|     }; | ||||
| 
 | ||||
|     void SetWaitingLockInfo(LockWithPriorityInheritanceInfo* lock) { | ||||
|         waiting_lock_info = lock; | ||||
|         m_waiting_lock_info = lock; | ||||
|     } | ||||
| 
 | ||||
|     LockWithPriorityInheritanceInfo* GetWaitingLockInfo() { | ||||
|         return waiting_lock_info; | ||||
|         return m_waiting_lock_info; | ||||
|     } | ||||
| 
 | ||||
|     void AddHeldLock(LockWithPriorityInheritanceInfo* lock_info); | ||||
| @ -867,110 +833,108 @@ private: | ||||
|     using LockWithPriorityInheritanceInfoList = | ||||
|         boost::intrusive::list<LockWithPriorityInheritanceInfo>; | ||||
| 
 | ||||
|     ConditionVariableThreadTree* condvar_tree{}; | ||||
|     u64 condvar_key{}; | ||||
|     u64 virtual_affinity_mask{}; | ||||
|     KAffinityMask physical_affinity_mask{}; | ||||
|     u64 thread_id{}; | ||||
|     std::atomic<s64> cpu_time{}; | ||||
|     VAddr address_key{}; | ||||
|     KProcess* parent{}; | ||||
|     VAddr kernel_stack_top{}; | ||||
|     u32* light_ipc_data{}; | ||||
|     VAddr tls_address{}; | ||||
|     KLightLock activity_pause_lock; | ||||
|     s64 schedule_count{}; | ||||
|     s64 last_scheduled_tick{}; | ||||
|     std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{}; | ||||
|     KThreadQueue* wait_queue{}; | ||||
|     LockWithPriorityInheritanceInfoList held_lock_info_list{}; | ||||
|     LockWithPriorityInheritanceInfo* waiting_lock_info{}; | ||||
|     WaiterList pinned_waiter_list{}; | ||||
|     u32 address_key_value{}; | ||||
|     u32 suspend_request_flags{}; | ||||
|     u32 suspend_allowed_flags{}; | ||||
|     s32 synced_index{}; | ||||
|     Result wait_result{ResultSuccess}; | ||||
|     s32 base_priority{}; | ||||
|     s32 physical_ideal_core_id{}; | ||||
|     s32 virtual_ideal_core_id{}; | ||||
|     s32 num_kernel_waiters{}; | ||||
|     s32 current_core_id{}; | ||||
|     s32 core_id{}; | ||||
|     KAffinityMask original_physical_affinity_mask{}; | ||||
|     s32 original_physical_ideal_core_id{}; | ||||
|     s32 num_core_migration_disables{}; | ||||
|     std::atomic<ThreadState> thread_state{}; | ||||
|     std::atomic<bool> termination_requested{}; | ||||
|     bool wait_cancelled{}; | ||||
|     bool cancellable{}; | ||||
|     bool signaled{}; | ||||
|     bool initialized{}; | ||||
|     bool debug_attached{}; | ||||
|     s8 priority_inheritance_count{}; | ||||
|     bool resource_limit_release_hint{}; | ||||
|     bool is_kernel_address_key{}; | ||||
|     StackParameters stack_parameters{}; | ||||
|     Common::SpinLock context_guard{}; | ||||
|     ConditionVariableThreadTree* m_condvar_tree{}; | ||||
|     u64 m_condvar_key{}; | ||||
|     u64 m_virtual_affinity_mask{}; | ||||
|     KAffinityMask m_physical_affinity_mask{}; | ||||
|     u64 m_thread_id{}; | ||||
|     std::atomic<s64> m_cpu_time{}; | ||||
|     VAddr m_address_key{}; | ||||
|     KProcess* m_parent{}; | ||||
|     VAddr m_kernel_stack_top{}; | ||||
|     u32* m_light_ipc_data{}; | ||||
|     VAddr m_tls_address{}; | ||||
|     KLightLock m_activity_pause_lock; | ||||
|     s64 m_schedule_count{}; | ||||
|     s64 m_last_scheduled_tick{}; | ||||
|     std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> m_per_core_priority_queue_entry{}; | ||||
|     KThreadQueue* m_wait_queue{}; | ||||
|     LockWithPriorityInheritanceInfoList m_held_lock_info_list{}; | ||||
|     LockWithPriorityInheritanceInfo* m_waiting_lock_info{}; | ||||
|     WaiterList m_pinned_waiter_list{}; | ||||
|     u32 m_address_key_value{}; | ||||
|     u32 m_suspend_request_flags{}; | ||||
|     u32 m_suspend_allowed_flags{}; | ||||
|     s32 m_synced_index{}; | ||||
|     Result m_wait_result{ResultSuccess}; | ||||
|     s32 m_base_priority{}; | ||||
|     s32 m_physical_ideal_core_id{}; | ||||
|     s32 m_virtual_ideal_core_id{}; | ||||
|     s32 m_num_kernel_waiters{}; | ||||
|     s32 m_current_core_id{}; | ||||
|     s32 m_core_id{}; | ||||
|     KAffinityMask m_original_physical_affinity_mask{}; | ||||
|     s32 m_original_physical_ideal_core_id{}; | ||||
|     s32 m_num_core_migration_disables{}; | ||||
|     std::atomic<ThreadState> m_thread_state{}; | ||||
|     std::atomic<bool> m_termination_requested{}; | ||||
|     bool m_wait_cancelled{}; | ||||
|     bool m_cancellable{}; | ||||
|     bool m_signaled{}; | ||||
|     bool m_initialized{}; | ||||
|     bool m_debug_attached{}; | ||||
|     s8 m_priority_inheritance_count{}; | ||||
|     bool m_resource_limit_release_hint{}; | ||||
|     bool m_is_kernel_address_key{}; | ||||
|     StackParameters m_stack_parameters{}; | ||||
|     Common::SpinLock m_context_guard{}; | ||||
| 
 | ||||
|     // For emulation
 | ||||
|     std::shared_ptr<Common::Fiber> host_context{}; | ||||
|     bool is_single_core{}; | ||||
|     ThreadType thread_type{}; | ||||
|     StepState step_state{}; | ||||
|     std::atomic<bool> dummy_thread_runnable{true}; | ||||
|     std::shared_ptr<Common::Fiber> m_host_context{}; | ||||
|     ThreadType m_thread_type{}; | ||||
|     StepState m_step_state{}; | ||||
|     std::atomic<bool> m_dummy_thread_runnable{true}; | ||||
| 
 | ||||
|     // For debugging
 | ||||
|     std::vector<KSynchronizationObject*> wait_objects_for_debugging; | ||||
|     VAddr mutex_wait_address_for_debugging{}; | ||||
|     ThreadWaitReasonForDebugging wait_reason_for_debugging{}; | ||||
|     uintptr_t argument{}; | ||||
|     VAddr stack_top{}; | ||||
|     std::string name{}; | ||||
|     std::vector<KSynchronizationObject*> m_wait_objects_for_debugging{}; | ||||
|     VAddr m_mutex_wait_address_for_debugging{}; | ||||
|     ThreadWaitReasonForDebugging m_wait_reason_for_debugging{}; | ||||
|     uintptr_t m_argument{}; | ||||
|     VAddr m_stack_top{}; | ||||
| 
 | ||||
| public: | ||||
|     using ConditionVariableThreadTreeType = ConditionVariableThreadTree; | ||||
| 
 | ||||
|     void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, u64 cv_key, | ||||
|                               u32 value) { | ||||
|         ASSERT(waiting_lock_info == nullptr); | ||||
|         condvar_tree = tree; | ||||
|         condvar_key = cv_key; | ||||
|         address_key = address; | ||||
|         address_key_value = value; | ||||
|         is_kernel_address_key = false; | ||||
|         ASSERT(m_waiting_lock_info == nullptr); | ||||
|         m_condvar_tree = tree; | ||||
|         m_condvar_key = cv_key; | ||||
|         m_address_key = address; | ||||
|         m_address_key_value = value; | ||||
|         m_is_kernel_address_key = false; | ||||
|     } | ||||
| 
 | ||||
|     void ClearConditionVariable() { | ||||
|         condvar_tree = nullptr; | ||||
|         m_condvar_tree = nullptr; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool IsWaitingForConditionVariable() const { | ||||
|         return condvar_tree != nullptr; | ||||
|     bool IsWaitingForConditionVariable() const { | ||||
|         return m_condvar_tree != nullptr; | ||||
|     } | ||||
| 
 | ||||
|     void SetAddressArbiter(ConditionVariableThreadTree* tree, u64 address) { | ||||
|         ASSERT(waiting_lock_info == nullptr); | ||||
|         condvar_tree = tree; | ||||
|         condvar_key = address; | ||||
|         ASSERT(m_waiting_lock_info == nullptr); | ||||
|         m_condvar_tree = tree; | ||||
|         m_condvar_key = address; | ||||
|     } | ||||
| 
 | ||||
|     void ClearAddressArbiter() { | ||||
|         condvar_tree = nullptr; | ||||
|         m_condvar_tree = nullptr; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool IsWaitingForAddressArbiter() const { | ||||
|         return condvar_tree != nullptr; | ||||
|     bool IsWaitingForAddressArbiter() const { | ||||
|         return m_condvar_tree != nullptr; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] ConditionVariableThreadTree* GetConditionVariableTree() const { | ||||
|         return condvar_tree; | ||||
|     ConditionVariableThreadTree* GetConditionVariableTree() const { | ||||
|         return m_condvar_tree; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| class KScopedDisableDispatch { | ||||
| public: | ||||
|     [[nodiscard]] explicit KScopedDisableDispatch(KernelCore& kernel) : m_kernel{kernel} { | ||||
|     explicit KScopedDisableDispatch(KernelCore& kernel) : m_kernel{kernel} { | ||||
|         // If we are shutting down the kernel, none of this is relevant anymore.
 | ||||
|         if (m_kernel.IsShuttingDown()) { | ||||
|             return; | ||||
|  | ||||
| @ -214,7 +214,6 @@ struct KernelCore::Impl { | ||||
|             cores[i] = std::make_unique<Kernel::PhysicalCore>(i, system, *schedulers[i]); | ||||
| 
 | ||||
|             auto* main_thread{Kernel::KThread::Create(system.Kernel())}; | ||||
|             main_thread->SetName(fmt::format("MainThread:{}", core)); | ||||
|             main_thread->SetCurrentCore(core); | ||||
|             ASSERT(Kernel::KThread::InitializeMainThread(system, main_thread, core).IsSuccess()); | ||||
| 
 | ||||
| @ -356,7 +355,6 @@ struct KernelCore::Impl { | ||||
|             ASSERT(KThread::InitializeHighPriorityThread(system, shutdown_threads[core_id], {}, {}, | ||||
|                                                          core_id) | ||||
|                        .IsSuccess()); | ||||
|             shutdown_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -390,7 +388,6 @@ struct KernelCore::Impl { | ||||
|     KThread* GetHostDummyThread(KThread* existing_thread) { | ||||
|         auto initialize = [this](KThread* thread) { | ||||
|             ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess()); | ||||
|             thread->SetName(fmt::format("DummyThread:{}", next_host_thread_id++)); | ||||
|             return thread; | ||||
|         }; | ||||
| 
 | ||||
|  | ||||
| @ -59,9 +59,6 @@ Result CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, | ||||
|                                             priority, core_id, std::addressof(process))); | ||||
|     } | ||||
| 
 | ||||
|     // Set the thread name for debugging purposes.
 | ||||
|     thread->SetName(fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *out_handle)); | ||||
| 
 | ||||
|     // Commit the thread reservation.
 | ||||
|     thread_reservation.Commit(); | ||||
| 
 | ||||
| @ -252,7 +249,7 @@ Result GetThreadList(Core::System& system, s32* out_num_threads, VAddr out_threa | ||||
| 
 | ||||
|     auto list_iter = thread_list.cbegin(); | ||||
|     for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) { | ||||
|         memory.Write64(out_thread_ids, (*list_iter)->GetThreadID()); | ||||
|         memory.Write64(out_thread_ids, (*list_iter)->GetThreadId()); | ||||
|         out_thread_ids += sizeof(u64); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -303,7 +303,7 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesti | ||||
|     } | ||||
| 
 | ||||
|     // Copy the translated command buffer back into the thread's command buffer area.
 | ||||
|     memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(), | ||||
|     memory.WriteBlock(owner_process, requesting_thread.GetTlsAddress(), cmd_buf.data(), | ||||
|                       write_size * sizeof(u32)); | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
|  | ||||
| @ -112,33 +112,6 @@ QString WaitTreeText::GetText() const { | ||||
|     return text; | ||||
| } | ||||
| 
 | ||||
| WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address_, const Kernel::KHandleTable& handle_table, | ||||
|                                      Core::System& system_) | ||||
|     : mutex_address{mutex_address_}, system{system_} { | ||||
|     mutex_value = system.Memory().Read32(mutex_address); | ||||
|     owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask); | ||||
|     owner = handle_table.GetObject<Kernel::KThread>(owner_handle).GetPointerUnsafe(); | ||||
| } | ||||
| 
 | ||||
| WaitTreeMutexInfo::~WaitTreeMutexInfo() = default; | ||||
| 
 | ||||
| QString WaitTreeMutexInfo::GetText() const { | ||||
|     return tr("waiting for mutex 0x%1").arg(mutex_address, 16, 16, QLatin1Char{'0'}); | ||||
| } | ||||
| 
 | ||||
| std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexInfo::GetChildren() const { | ||||
|     const bool has_waiters = (mutex_value & Kernel::Svc::HandleWaitMask) != 0; | ||||
| 
 | ||||
|     std::vector<std::unique_ptr<WaitTreeItem>> list; | ||||
|     list.push_back(std::make_unique<WaitTreeText>(tr("has waiters: %1").arg(has_waiters))); | ||||
|     list.push_back(std::make_unique<WaitTreeText>( | ||||
|         tr("owner handle: 0x%1").arg(owner_handle, 8, 16, QLatin1Char{'0'}))); | ||||
|     if (owner != nullptr) { | ||||
|         list.push_back(std::make_unique<WaitTreeThread>(*owner, system)); | ||||
|     } | ||||
|     return list; | ||||
| } | ||||
| 
 | ||||
| WaitTreeCallstack::WaitTreeCallstack(const Kernel::KThread& thread_, Core::System& system_) | ||||
|     : thread{thread_}, system{system_} {} | ||||
| WaitTreeCallstack::~WaitTreeCallstack() = default; | ||||
| @ -216,26 +189,6 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSynchronizationObject::GetChi | ||||
|     return list; | ||||
| } | ||||
| 
 | ||||
| WaitTreeObjectList::WaitTreeObjectList(const std::vector<Kernel::KSynchronizationObject*>& list, | ||||
|                                        bool w_all, Core::System& system_) | ||||
|     : object_list(list), wait_all(w_all), system{system_} {} | ||||
| 
 | ||||
| WaitTreeObjectList::~WaitTreeObjectList() = default; | ||||
| 
 | ||||
| QString WaitTreeObjectList::GetText() const { | ||||
|     if (wait_all) | ||||
|         return tr("waiting for all objects"); | ||||
|     return tr("waiting for one of the following objects"); | ||||
| } | ||||
| 
 | ||||
| std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeObjectList::GetChildren() const { | ||||
|     std::vector<std::unique_ptr<WaitTreeItem>> list(object_list.size()); | ||||
|     std::transform(object_list.begin(), object_list.end(), list.begin(), [this](const auto& t) { | ||||
|         return WaitTreeSynchronizationObject::make(*t, system); | ||||
|     }); | ||||
|     return list; | ||||
| } | ||||
| 
 | ||||
| WaitTreeThread::WaitTreeThread(const Kernel::KThread& thread, Core::System& system_) | ||||
|     : WaitTreeSynchronizationObject(thread, system_), system{system_} {} | ||||
| WaitTreeThread::~WaitTreeThread() = default; | ||||
| @ -346,33 +299,15 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { | ||||
|     } | ||||
| 
 | ||||
|     list.push_back(std::make_unique<WaitTreeText>(tr("processor = %1").arg(processor))); | ||||
|     list.push_back(std::make_unique<WaitTreeText>( | ||||
|         tr("ideal core = %1").arg(thread.GetIdealCoreForDebugging()))); | ||||
|     list.push_back(std::make_unique<WaitTreeText>( | ||||
|         tr("affinity mask = %1").arg(thread.GetAffinityMask().GetAffinityMask()))); | ||||
|     list.push_back(std::make_unique<WaitTreeText>(tr("thread id = %1").arg(thread.GetThreadID()))); | ||||
|     list.push_back(std::make_unique<WaitTreeText>(tr("thread id = %1").arg(thread.GetThreadId()))); | ||||
|     list.push_back(std::make_unique<WaitTreeText>(tr("priority = %1(current) / %2(normal)") | ||||
|                                                       .arg(thread.GetPriority()) | ||||
|                                                       .arg(thread.GetBasePriority()))); | ||||
|     list.push_back(std::make_unique<WaitTreeText>( | ||||
|         tr("last running ticks = %1").arg(thread.GetLastScheduledTick()))); | ||||
| 
 | ||||
|     const VAddr mutex_wait_address = thread.GetMutexWaitAddressForDebugging(); | ||||
|     if (mutex_wait_address != 0) { | ||||
|         const auto& handle_table = thread.GetOwnerProcess()->GetHandleTable(); | ||||
|         list.push_back( | ||||
|             std::make_unique<WaitTreeMutexInfo>(mutex_wait_address, handle_table, system)); | ||||
|     } else { | ||||
|         list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); | ||||
|     } | ||||
| 
 | ||||
|     if (thread.GetState() == Kernel::ThreadState::Waiting && | ||||
|         thread.GetWaitReasonForDebugging() == | ||||
|             Kernel::ThreadWaitReasonForDebugging::Synchronization) { | ||||
|         list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjectsForDebugging(), | ||||
|                                                             thread.IsCancellable(), system)); | ||||
|     } | ||||
| 
 | ||||
|     list.push_back(std::make_unique<WaitTreeCallstack>(thread, system)); | ||||
| 
 | ||||
|     return list; | ||||
|  | ||||
| @ -74,25 +74,6 @@ public: | ||||
|     bool IsExpandable() const override; | ||||
| }; | ||||
| 
 | ||||
| class WaitTreeMutexInfo : public WaitTreeExpandableItem { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     explicit WaitTreeMutexInfo(VAddr mutex_address_, const Kernel::KHandleTable& handle_table, | ||||
|                                Core::System& system_); | ||||
|     ~WaitTreeMutexInfo() override; | ||||
| 
 | ||||
|     QString GetText() const override; | ||||
|     std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | ||||
| 
 | ||||
| private: | ||||
|     VAddr mutex_address{}; | ||||
|     u32 mutex_value{}; | ||||
|     Kernel::Handle owner_handle{}; | ||||
|     Kernel::KThread* owner{}; | ||||
| 
 | ||||
|     Core::System& system; | ||||
| }; | ||||
| 
 | ||||
| class WaitTreeCallstack : public WaitTreeExpandableItem { | ||||
|     Q_OBJECT | ||||
| public: | ||||
| @ -127,23 +108,6 @@ private: | ||||
|     Core::System& system; | ||||
| }; | ||||
| 
 | ||||
| class WaitTreeObjectList : public WaitTreeExpandableItem { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     WaitTreeObjectList(const std::vector<Kernel::KSynchronizationObject*>& list, bool wait_all, | ||||
|                        Core::System& system_); | ||||
|     ~WaitTreeObjectList() override; | ||||
| 
 | ||||
|     QString GetText() const override; | ||||
|     std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | ||||
| 
 | ||||
| private: | ||||
|     const std::vector<Kernel::KSynchronizationObject*>& object_list; | ||||
|     bool wait_all; | ||||
| 
 | ||||
|     Core::System& system; | ||||
| }; | ||||
| 
 | ||||
| class WaitTreeThread : public WaitTreeSynchronizationObject { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user