mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Merge pull request #4371 from wwylele/kernel-global-3
Kernel: eliminate global state for threads and timers
This commit is contained in:
		
						commit
						445538c2cf
					
				
					 20 changed files with 250 additions and 235 deletions
				
			
		|  | @ -51,7 +51,7 @@ std::size_t WaitTreeItem::Row() const { | |||
| } | ||||
| 
 | ||||
| std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() { | ||||
|     const auto& threads = Kernel::GetThreadList(); | ||||
|     const auto& threads = Core::System::GetInstance().Kernel().GetThreadManager().GetThreadList(); | ||||
|     std::vector<std::unique_ptr<WaitTreeThread>> item_list; | ||||
|     item_list.reserve(threads.size()); | ||||
|     for (std::size_t i = 0; i < threads.size(); ++i) { | ||||
|  |  | |||
|  | @ -134,7 +134,8 @@ public: | |||
|             if (GDBStub::IsConnected()) { | ||||
|                 parent.jit->HaltExecution(); | ||||
|                 parent.SetPC(pc); | ||||
|                 Kernel::Thread* thread = Kernel::GetCurrentThread(); | ||||
|                 Kernel::Thread* thread = | ||||
|                     Core::System::GetInstance().Kernel().GetThreadManager().GetCurrentThread(); | ||||
|                 parent.SaveContext(thread->context); | ||||
|                 GDBStub::Break(); | ||||
|                 GDBStub::SendTrap(thread, 5); | ||||
|  |  | |||
|  | @ -604,7 +604,8 @@ void ARMul_State::ServeBreak() { | |||
|     if (last_bkpt_hit) { | ||||
|         Reg[15] = last_bkpt.address; | ||||
|     } | ||||
|     Kernel::Thread* thread = Kernel::GetCurrentThread(); | ||||
|     Kernel::Thread* thread = | ||||
|         Core::System::GetInstance().Kernel().GetThreadManager().GetCurrentThread(); | ||||
|     Core::CPU().SaveContext(thread->context); | ||||
|     if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) { | ||||
|         last_bkpt_hit = false; | ||||
|  |  | |||
|  | @ -59,7 +59,7 @@ System::ResultStatus System::RunLoop(bool tight_loop) { | |||
| 
 | ||||
|     // If we don't have a currently active thread then don't execute instructions,
 | ||||
|     // instead advance to the next event and try to yield to the next thread
 | ||||
|     if (Kernel::GetCurrentThread() == nullptr) { | ||||
|     if (kernel->GetThreadManager().GetCurrentThread() == nullptr) { | ||||
|         LOG_TRACE(Core_ARM11, "Idling"); | ||||
|         CoreTiming::Idle(); | ||||
|         CoreTiming::Advance(); | ||||
|  | @ -164,7 +164,7 @@ void System::Reschedule() { | |||
|     } | ||||
| 
 | ||||
|     reschedule_pending = false; | ||||
|     Kernel::Reschedule(); | ||||
|     kernel->GetThreadManager().Reschedule(); | ||||
| } | ||||
| 
 | ||||
| System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { | ||||
|  |  | |||
|  | @ -160,7 +160,7 @@ BreakpointMap breakpoints_write; | |||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| static Kernel::Thread* FindThreadById(int id) { | ||||
|     const auto& threads = Kernel::GetThreadList(); | ||||
|     const auto& threads = Core::System::GetInstance().Kernel().GetThreadManager().GetThreadList(); | ||||
|     for (auto& thread : threads) { | ||||
|         if (thread->GetThreadId() == static_cast<u32>(id)) { | ||||
|             return thread.get(); | ||||
|  | @ -535,7 +535,8 @@ static void HandleQuery() { | |||
|         SendReply(target_xml); | ||||
|     } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { | ||||
|         std::string val = "m"; | ||||
|         const auto& threads = Kernel::GetThreadList(); | ||||
|         const auto& threads = | ||||
|             Core::System::GetInstance().Kernel().GetThreadManager().GetThreadList(); | ||||
|         for (const auto& thread : threads) { | ||||
|             val += fmt::format("{:x},", thread->GetThreadId()); | ||||
|         } | ||||
|  | @ -547,7 +548,8 @@ static void HandleQuery() { | |||
|         std::string buffer; | ||||
|         buffer += "l<?xml version=\"1.0\"?>"; | ||||
|         buffer += "<threads>"; | ||||
|         const auto& threads = Kernel::GetThreadList(); | ||||
|         const auto& threads = | ||||
|             Core::System::GetInstance().Kernel().GetThreadManager().GetThreadList(); | ||||
|         for (const auto& thread : threads) { | ||||
|             buffer += fmt::format(R"*(<thread id="{:x}" name="Thread {:x}"></thread>)*", | ||||
|                                   thread->GetThreadId(), thread->GetThreadId()); | ||||
|  |  | |||
|  | @ -9,27 +9,6 @@ | |||
| #include "core/hle/kernel/thread.h" | ||||
| #include "core/memory.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| /// Offset into command buffer of header
 | ||||
| static const int kCommandHeaderOffset = 0x80; | ||||
| 
 | ||||
| /**
 | ||||
|  * Returns a pointer to the command buffer in the current thread's TLS | ||||
|  * TODO(Subv): This is not entirely correct, the command buffer should be copied from | ||||
|  * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to | ||||
|  * the service handler process' memory. | ||||
|  * @param offset Optional offset into command buffer | ||||
|  * @param offset Optional offset into command buffer (in bytes) | ||||
|  * @return Pointer to command buffer | ||||
|  */ | ||||
| inline u32* GetCommandBuffer(const int offset = 0) { | ||||
|     return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + | ||||
|                                     offset); | ||||
| } | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
| 
 | ||||
| namespace IPC { | ||||
| 
 | ||||
| /// Size of the command buffer area, in 32-bit words.
 | ||||
|  |  | |||
|  | @ -72,7 +72,7 @@ bool HandleTable::IsValid(Handle handle) const { | |||
| 
 | ||||
| SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { | ||||
|     if (handle == CurrentThread) { | ||||
|         return GetCurrentThread(); | ||||
|         return kernel.GetThreadManager().GetCurrentThread(); | ||||
|     } else if (handle == CurrentProcess) { | ||||
|         return kernel.GetCurrentProcess(); | ||||
|     } | ||||
|  |  | |||
|  | @ -124,8 +124,7 @@ private: | |||
| 
 | ||||
| /**
 | ||||
|  * Class containing information about an in-flight IPC request being handled by an HLE service | ||||
|  * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and | ||||
|  * when possible use the APIs in this class to service the request. | ||||
|  * implementation. | ||||
|  * | ||||
|  * HLE handle protocol | ||||
|  * =================== | ||||
|  |  | |||
|  | @ -21,15 +21,12 @@ KernelSystem::KernelSystem(u32 system_mode) { | |||
|     Kernel::MemoryInit(system_mode); | ||||
| 
 | ||||
|     resource_limits = std::make_unique<ResourceLimitList>(*this); | ||||
|     Kernel::ThreadingInit(); | ||||
|     Kernel::TimersInit(); | ||||
|     thread_manager = std::make_unique<ThreadManager>(); | ||||
|     timer_manager = std::make_unique<TimerManager>(); | ||||
| } | ||||
| 
 | ||||
| /// Shutdown the kernel
 | ||||
| KernelSystem::~KernelSystem() { | ||||
|     Kernel::ThreadingShutdown(); | ||||
| 
 | ||||
|     Kernel::TimersShutdown(); | ||||
|     Kernel::MemoryShutdown(); | ||||
| } | ||||
| 
 | ||||
|  | @ -53,4 +50,20 @@ void KernelSystem::SetCurrentProcess(SharedPtr<Process> process) { | |||
|     current_process = std::move(process); | ||||
| } | ||||
| 
 | ||||
| ThreadManager& KernelSystem::GetThreadManager() { | ||||
|     return *thread_manager; | ||||
| } | ||||
| 
 | ||||
| const ThreadManager& KernelSystem::GetThreadManager() const { | ||||
|     return *thread_manager; | ||||
| } | ||||
| 
 | ||||
| TimerManager& KernelSystem::GetTimerManager() { | ||||
|     return *timer_manager; | ||||
| } | ||||
| 
 | ||||
| const TimerManager& KernelSystem::GetTimerManager() const { | ||||
|     return *timer_manager; | ||||
| } | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
|  | @ -28,6 +28,8 @@ class ClientSession; | |||
| class ServerSession; | ||||
| class ResourceLimitList; | ||||
| class SharedMemory; | ||||
| class ThreadManager; | ||||
| class TimerManager; | ||||
| 
 | ||||
| enum class ResetType { | ||||
|     OneShot, | ||||
|  | @ -187,6 +189,12 @@ public: | |||
|     SharedPtr<Process> GetCurrentProcess() const; | ||||
|     void SetCurrentProcess(SharedPtr<Process> process); | ||||
| 
 | ||||
|     ThreadManager& GetThreadManager(); | ||||
|     const ThreadManager& GetThreadManager() const; | ||||
| 
 | ||||
|     TimerManager& GetTimerManager(); | ||||
|     const TimerManager& GetTimerManager() const; | ||||
| 
 | ||||
| private: | ||||
|     std::unique_ptr<ResourceLimitList> resource_limits; | ||||
|     std::atomic<u32> next_object_id{0}; | ||||
|  | @ -199,6 +207,9 @@ private: | |||
|     std::vector<SharedPtr<Process>> process_list; | ||||
| 
 | ||||
|     SharedPtr<Process> current_process; | ||||
| 
 | ||||
|     std::unique_ptr<ThreadManager> thread_manager; | ||||
|     std::unique_ptr<TimerManager> timer_manager; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ SharedPtr<Mutex> KernelSystem::CreateMutex(bool initial_locked, std::string name | |||
| 
 | ||||
|     // Acquire mutex with current thread if initialized as locked
 | ||||
|     if (initial_locked) | ||||
|         mutex->Acquire(GetCurrentThread()); | ||||
|         mutex->Acquire(thread_manager->GetCurrentThread()); | ||||
| 
 | ||||
|     return mutex; | ||||
| } | ||||
|  |  | |||
|  | @ -145,7 +145,8 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add | |||
| } | ||||
| 
 | ||||
| static void ExitProcess() { | ||||
|     SharedPtr<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||
|     KernelSystem& kernel = Core::System::GetInstance().Kernel(); | ||||
|     SharedPtr<Process> current_process = kernel.GetCurrentProcess(); | ||||
|     LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->process_id); | ||||
| 
 | ||||
|     ASSERT_MSG(current_process->status == ProcessStatus::Running, "Process has already exited"); | ||||
|  | @ -153,12 +154,12 @@ static void ExitProcess() { | |||
|     current_process->status = ProcessStatus::Exited; | ||||
| 
 | ||||
|     // Stop all the process threads that are currently waiting for objects.
 | ||||
|     auto& thread_list = GetThreadList(); | ||||
|     auto& thread_list = kernel.GetThreadManager().GetThreadList(); | ||||
|     for (auto& thread : thread_list) { | ||||
|         if (thread->owner_process != current_process) | ||||
|             continue; | ||||
| 
 | ||||
|         if (thread == GetCurrentThread()) | ||||
|         if (thread == kernel.GetThreadManager().GetCurrentThread()) | ||||
|             continue; | ||||
| 
 | ||||
|         // TODO(Subv): When are the other running/ready threads terminated?
 | ||||
|  | @ -170,7 +171,7 @@ static void ExitProcess() { | |||
|     } | ||||
| 
 | ||||
|     // Kill the current thread
 | ||||
|     GetCurrentThread()->Stop(); | ||||
|     kernel.GetThreadManager().GetCurrentThread()->Stop(); | ||||
| 
 | ||||
|     Core::System::GetInstance().PrepareReschedule(); | ||||
| } | ||||
|  | @ -254,9 +255,9 @@ static ResultCode ConnectToPort(Handle* out_handle, VAddr port_name_address) { | |||
| 
 | ||||
| /// Makes a blocking IPC call to an OS service.
 | ||||
| static ResultCode SendSyncRequest(Handle handle) { | ||||
|     KernelSystem& kernel = Core::System::GetInstance().Kernel(); | ||||
|     SharedPtr<ClientSession> session = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<ClientSession>( | ||||
|             handle); | ||||
|         kernel.GetCurrentProcess()->handle_table.Get<ClientSession>(handle); | ||||
|     if (session == nullptr) { | ||||
|         return ERR_INVALID_HANDLE; | ||||
|     } | ||||
|  | @ -265,7 +266,7 @@ static ResultCode SendSyncRequest(Handle handle) { | |||
| 
 | ||||
|     Core::System::GetInstance().PrepareReschedule(); | ||||
| 
 | ||||
|     return session->SendSyncRequest(GetCurrentThread()); | ||||
|     return session->SendSyncRequest(kernel.GetThreadManager().GetCurrentThread()); | ||||
| } | ||||
| 
 | ||||
| /// Close a handle
 | ||||
|  | @ -276,10 +277,9 @@ static ResultCode CloseHandle(Handle handle) { | |||
| 
 | ||||
| /// Wait for a handle to synchronize, timeout after the specified nanoseconds
 | ||||
| static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { | ||||
|     auto object = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<WaitObject>( | ||||
|             handle); | ||||
|     Thread* thread = GetCurrentThread(); | ||||
|     KernelSystem& kernel = Core::System::GetInstance().Kernel(); | ||||
|     auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle); | ||||
|     Thread* thread = kernel.GetThreadManager().GetCurrentThread(); | ||||
| 
 | ||||
|     if (object == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
|  | @ -331,7 +331,8 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| /// Wait for the given handles to synchronize, timeout after the specified nanoseconds
 | ||||
| static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle_count, | ||||
|                                        bool wait_all, s64 nano_seconds) { | ||||
|     Thread* thread = GetCurrentThread(); | ||||
|     KernelSystem& kernel = Core::System::GetInstance().Kernel(); | ||||
|     Thread* thread = kernel.GetThreadManager().GetCurrentThread(); | ||||
| 
 | ||||
|     if (!Memory::IsValidVirtualAddress(handles_address)) | ||||
|         return ERR_INVALID_POINTER; | ||||
|  | @ -349,9 +350,7 @@ static ResultCode WaitSynchronizationN(s32* out, VAddr handles_address, s32 hand | |||
| 
 | ||||
|     for (int i = 0; i < handle_count; ++i) { | ||||
|         Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); | ||||
|         auto object = | ||||
|             Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<WaitObject>( | ||||
|                 handle); | ||||
|         auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle); | ||||
|         if (object == nullptr) | ||||
|             return ERR_INVALID_HANDLE; | ||||
|         objects[i] = object; | ||||
|  | @ -515,7 +514,8 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ | |||
|     using ObjectPtr = SharedPtr<WaitObject>; | ||||
|     std::vector<ObjectPtr> objects(handle_count); | ||||
| 
 | ||||
|     SharedPtr<Process> current_process = Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||
|     KernelSystem& kernel = Core::System::GetInstance().Kernel(); | ||||
|     SharedPtr<Process> current_process = kernel.GetCurrentProcess(); | ||||
| 
 | ||||
|     for (int i = 0; i < handle_count; ++i) { | ||||
|         Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); | ||||
|  | @ -527,8 +527,9 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ | |||
| 
 | ||||
|     // We are also sending a command reply.
 | ||||
|     // Do not send a reply if the command id in the command buffer is 0xFFFF.
 | ||||
|     u32* cmd_buff = GetCommandBuffer(); | ||||
|     IPC::Header header{cmd_buff[0]}; | ||||
|     Thread* thread = kernel.GetThreadManager().GetCurrentThread(); | ||||
|     u32 cmd_buff_header = Memory::Read32(thread->GetCommandBufferAddress()); | ||||
|     IPC::Header header{cmd_buff_header}; | ||||
|     if (reply_target != 0 && header.command_id != 0xFFFF) { | ||||
|         auto session = current_process->handle_table.Get<ServerSession>(reply_target); | ||||
|         if (session == nullptr) | ||||
|  | @ -546,11 +547,11 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ | |||
|             return ERR_SESSION_CLOSED_BY_REMOTE; | ||||
|         } | ||||
| 
 | ||||
|         VAddr source_address = GetCurrentThread()->GetCommandBufferAddress(); | ||||
|         VAddr source_address = thread->GetCommandBufferAddress(); | ||||
|         VAddr target_address = request_thread->GetCommandBufferAddress(); | ||||
| 
 | ||||
|         ResultCode translation_result = TranslateCommandBuffer( | ||||
|             Kernel::GetCurrentThread(), request_thread, source_address, target_address, true); | ||||
|         ResultCode translation_result = | ||||
|             TranslateCommandBuffer(thread, request_thread, source_address, target_address, true); | ||||
| 
 | ||||
|         // Note: The real kernel seems to always panic if the Server->Client buffer translation
 | ||||
|         // fails for whatever reason.
 | ||||
|  | @ -570,8 +571,6 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ | |||
|         return RESULT_SUCCESS; | ||||
|     } | ||||
| 
 | ||||
|     auto thread = GetCurrentThread(); | ||||
| 
 | ||||
|     // Find the first object that is acquirable in the provided list of objects
 | ||||
|     auto itr = std::find_if(objects.begin(), objects.end(), [thread](const ObjectPtr& object) { | ||||
|         return !object->ShouldWait(thread); | ||||
|  | @ -587,7 +586,7 @@ static ResultCode ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_ | |||
|             return RESULT_SUCCESS; | ||||
| 
 | ||||
|         auto server_session = static_cast<ServerSession*>(object); | ||||
|         return ReceiveIPCRequest(server_session, GetCurrentThread()); | ||||
|         return ReceiveIPCRequest(server_session, thread); | ||||
|     } | ||||
| 
 | ||||
|     // No objects were ready to be acquired, prepare to suspend the thread.
 | ||||
|  | @ -644,14 +643,16 @@ static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 val | |||
|     LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}, address=0x{:08X}, type=0x{:08X}, value=0x{:08X}", | ||||
|               handle, address, type, value); | ||||
| 
 | ||||
|     KernelSystem& kernel = Core::System::GetInstance().Kernel(); | ||||
| 
 | ||||
|     SharedPtr<AddressArbiter> arbiter = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<AddressArbiter>( | ||||
|             handle); | ||||
|         kernel.GetCurrentProcess()->handle_table.Get<AddressArbiter>(handle); | ||||
|     if (arbiter == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|     auto res = arbiter->ArbitrateAddress(GetCurrentThread(), static_cast<ArbitrationType>(type), | ||||
|                                          address, value, nanoseconds); | ||||
|     auto res = | ||||
|         arbiter->ArbitrateAddress(kernel.GetThreadManager().GetCurrentThread(), | ||||
|                                   static_cast<ArbitrationType>(type), address, value, nanoseconds); | ||||
| 
 | ||||
|     // TODO(Subv): Identify in which specific cases this call should cause a reschedule.
 | ||||
|     Core::System::GetInstance().PrepareReschedule(); | ||||
|  | @ -808,7 +809,7 @@ static ResultCode CreateThread(Handle* out_handle, u32 priority, u32 entry_point | |||
| static void ExitThread() { | ||||
|     LOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CPU().GetPC()); | ||||
| 
 | ||||
|     ExitCurrentThread(); | ||||
|     Core::System::GetInstance().Kernel().GetThreadManager().ExitCurrentThread(); | ||||
|     Core::System::GetInstance().PrepareReschedule(); | ||||
| } | ||||
| 
 | ||||
|  | @ -870,12 +871,13 @@ static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) { | |||
| static ResultCode ReleaseMutex(Handle handle) { | ||||
|     LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle); | ||||
| 
 | ||||
|     SharedPtr<Mutex> mutex = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess()->handle_table.Get<Mutex>(handle); | ||||
|     KernelSystem& kernel = Core::System::GetInstance().Kernel(); | ||||
| 
 | ||||
|     SharedPtr<Mutex> mutex = kernel.GetCurrentProcess()->handle_table.Get<Mutex>(handle); | ||||
|     if (mutex == nullptr) | ||||
|         return ERR_INVALID_HANDLE; | ||||
| 
 | ||||
|     return mutex->Release(GetCurrentThread()); | ||||
|     return mutex->Release(kernel.GetThreadManager().GetCurrentThread()); | ||||
| } | ||||
| 
 | ||||
| /// Get the ID of the specified process
 | ||||
|  | @ -1090,16 +1092,19 @@ static ResultCode CancelTimer(Handle handle) { | |||
| static void SleepThread(s64 nanoseconds) { | ||||
|     LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds); | ||||
| 
 | ||||
|     KernelSystem& kernel = Core::System::GetInstance().Kernel(); | ||||
|     ThreadManager& thread_manager = kernel.GetThreadManager(); | ||||
| 
 | ||||
|     // Don't attempt to yield execution if there are no available threads to run,
 | ||||
|     // this way we avoid a useless reschedule to the idle thread.
 | ||||
|     if (nanoseconds == 0 && !HaveReadyThreads()) | ||||
|     if (nanoseconds == 0 && !thread_manager.HaveReadyThreads()) | ||||
|         return; | ||||
| 
 | ||||
|     // Sleep current thread and check for next thread to schedule
 | ||||
|     WaitCurrentThread_Sleep(); | ||||
|     thread_manager.WaitCurrentThread_Sleep(); | ||||
| 
 | ||||
|     // Create an event to wake the thread up after the specified nanosecond delay has passed
 | ||||
|     GetCurrentThread()->WakeAfterDelay(nanoseconds); | ||||
|     thread_manager.GetCurrentThread()->WakeAfterDelay(nanoseconds); | ||||
| 
 | ||||
|     Core::System::GetInstance().PrepareReschedule(); | ||||
| } | ||||
|  |  | |||
|  | @ -10,11 +10,9 @@ | |||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/math_util.h" | ||||
| #include "common/thread_queue_list.h" | ||||
| #include "core/arm/arm_interface.h" | ||||
| #include "core/arm/skyeye_common/armstate.h" | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/hle/kernel/errors.h" | ||||
| #include "core/hle/kernel/handle_table.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
|  | @ -27,9 +25,6 @@ | |||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| /// Event type for the thread wake up event
 | ||||
| static CoreTiming::EventType* ThreadWakeupEventType = nullptr; | ||||
| 
 | ||||
| bool Thread::ShouldWait(Thread* thread) const { | ||||
|     return status != ThreadStatus::Dead; | ||||
| } | ||||
|  | @ -38,43 +33,28 @@ void Thread::Acquire(Thread* thread) { | |||
|     ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); | ||||
| } | ||||
| 
 | ||||
| static std::unordered_map<u64, Thread*> wakeup_callback_table; | ||||
| 
 | ||||
| // Lists all thread ids that aren't deleted/etc.
 | ||||
| static std::vector<SharedPtr<Thread>> thread_list; | ||||
| 
 | ||||
| // Lists only ready thread ids.
 | ||||
| static Common::ThreadQueueList<Thread*, ThreadPrioLowest + 1> ready_queue; | ||||
| 
 | ||||
| static SharedPtr<Thread> current_thread; | ||||
| 
 | ||||
| // The first available thread id at startup
 | ||||
| static u32 next_thread_id; | ||||
| 
 | ||||
| /**
 | ||||
|  * Creates a new thread ID | ||||
|  * @return The new thread ID | ||||
|  */ | ||||
| inline static u32 const NewThreadId() { | ||||
| u32 ThreadManager::NewThreadId() { | ||||
|     return next_thread_id++; | ||||
| } | ||||
| 
 | ||||
| Thread::Thread(KernelSystem& kernel) : WaitObject(kernel), context(Core::CPU().NewContext()) {} | ||||
| Thread::Thread(KernelSystem& kernel) | ||||
|     : WaitObject(kernel), context(Core::CPU().NewContext()), | ||||
|       thread_manager(kernel.GetThreadManager()) {} | ||||
| Thread::~Thread() {} | ||||
| 
 | ||||
| Thread* GetCurrentThread() { | ||||
| Thread* ThreadManager::GetCurrentThread() const { | ||||
|     return current_thread.get(); | ||||
| } | ||||
| 
 | ||||
| void Thread::Stop() { | ||||
|     // Cancel any outstanding wakeup events for this thread
 | ||||
|     CoreTiming::UnscheduleEvent(ThreadWakeupEventType, thread_id); | ||||
|     wakeup_callback_table.erase(thread_id); | ||||
|     CoreTiming::UnscheduleEvent(thread_manager.ThreadWakeupEventType, thread_id); | ||||
|     thread_manager.wakeup_callback_table.erase(thread_id); | ||||
| 
 | ||||
|     // Clean up thread from ready queue
 | ||||
|     // This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
 | ||||
|     if (status == ThreadStatus::Ready) { | ||||
|         ready_queue.remove(current_priority, this); | ||||
|         thread_manager.ready_queue.remove(current_priority, this); | ||||
|     } | ||||
| 
 | ||||
|     status = ThreadStatus::Dead; | ||||
|  | @ -97,11 +77,7 @@ void Thread::Stop() { | |||
|     owner_process->tls_slots[tls_page].reset(tls_slot); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Switches the CPU's active thread context to that of the specified thread | ||||
|  * @param new_thread The thread to switch to | ||||
|  */ | ||||
| static void SwitchContext(Thread* new_thread) { | ||||
| void ThreadManager::SwitchContext(Thread* new_thread) { | ||||
|     Thread* previous_thread = GetCurrentThread(); | ||||
| 
 | ||||
|     // Save context for previous thread
 | ||||
|  | @ -146,11 +122,7 @@ static void SwitchContext(Thread* new_thread) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Pops and returns the next thread from the thread queue | ||||
|  * @return A pointer to the next ready thread | ||||
|  */ | ||||
| static Thread* PopNextReadyThread() { | ||||
| Thread* ThreadManager::PopNextReadyThread() { | ||||
|     Thread* next; | ||||
|     Thread* thread = GetCurrentThread(); | ||||
| 
 | ||||
|  | @ -169,24 +141,19 @@ static Thread* PopNextReadyThread() { | |||
|     return next; | ||||
| } | ||||
| 
 | ||||
| void WaitCurrentThread_Sleep() { | ||||
| void ThreadManager::WaitCurrentThread_Sleep() { | ||||
|     Thread* thread = GetCurrentThread(); | ||||
|     thread->status = ThreadStatus::WaitSleep; | ||||
| } | ||||
| 
 | ||||
| void ExitCurrentThread() { | ||||
| void ThreadManager::ExitCurrentThread() { | ||||
|     Thread* thread = GetCurrentThread(); | ||||
|     thread->Stop(); | ||||
|     thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), | ||||
|                       thread_list.end()); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Callback that will wake up the thread it was scheduled for | ||||
|  * @param thread_id The ID 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_id, s64 cycles_late) { | ||||
| void ThreadManager::ThreadWakeupCallback(u64 thread_id, s64 cycles_late) { | ||||
|     SharedPtr<Thread> thread = wakeup_callback_table.at(thread_id); | ||||
|     if (thread == nullptr) { | ||||
|         LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", thread_id); | ||||
|  | @ -215,7 +182,8 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { | |||
|     if (nanoseconds == -1) | ||||
|         return; | ||||
| 
 | ||||
|     CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), ThreadWakeupEventType, thread_id); | ||||
|     CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), thread_manager.ThreadWakeupEventType, | ||||
|                               thread_id); | ||||
| } | ||||
| 
 | ||||
| void Thread::ResumeFromWait() { | ||||
|  | @ -251,15 +219,12 @@ void Thread::ResumeFromWait() { | |||
| 
 | ||||
|     wakeup_callback = nullptr; | ||||
| 
 | ||||
|     ready_queue.push_back(current_priority, this); | ||||
|     thread_manager.ready_queue.push_back(current_priority, this); | ||||
|     status = ThreadStatus::Ready; | ||||
|     Core::System::GetInstance().PrepareReschedule(); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Prints the thread queue for debugging purposes | ||||
|  */ | ||||
| static void DebugThreadQueue() { | ||||
| void ThreadManager::DebugThreadQueue() { | ||||
|     Thread* thread = GetCurrentThread(); | ||||
|     if (!thread) { | ||||
|         LOG_DEBUG(Kernel, "Current: NO CURRENT THREAD"); | ||||
|  | @ -343,10 +308,10 @@ ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr | |||
| 
 | ||||
|     SharedPtr<Thread> thread(new Thread(*this)); | ||||
| 
 | ||||
|     thread_list.push_back(thread); | ||||
|     ready_queue.prepare(priority); | ||||
|     thread_manager->thread_list.push_back(thread); | ||||
|     thread_manager->ready_queue.prepare(priority); | ||||
| 
 | ||||
|     thread->thread_id = NewThreadId(); | ||||
|     thread->thread_id = thread_manager->NewThreadId(); | ||||
|     thread->status = ThreadStatus::Dormant; | ||||
|     thread->entry_point = entry_point; | ||||
|     thread->stack_top = stack_top; | ||||
|  | @ -356,7 +321,7 @@ ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr | |||
|     thread->wait_objects.clear(); | ||||
|     thread->wait_address = 0; | ||||
|     thread->name = std::move(name); | ||||
|     wakeup_callback_table[thread->thread_id] = thread.get(); | ||||
|     thread_manager->wakeup_callback_table[thread->thread_id] = thread.get(); | ||||
|     thread->owner_process = &owner_process; | ||||
| 
 | ||||
|     // Find the next available TLS index, and mark it as used
 | ||||
|  | @ -405,7 +370,7 @@ ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr | |||
|     // to initialize the context
 | ||||
|     ResetThreadContext(thread->context, stack_top, entry_point, arg); | ||||
| 
 | ||||
|     ready_queue.push_back(thread->current_priority, thread.get()); | ||||
|     thread_manager->ready_queue.push_back(thread->current_priority, thread.get()); | ||||
|     thread->status = ThreadStatus::Ready; | ||||
| 
 | ||||
|     return MakeResult<SharedPtr<Thread>>(std::move(thread)); | ||||
|  | @ -416,9 +381,9 @@ void Thread::SetPriority(u32 priority) { | |||
|                "Invalid priority value."); | ||||
|     // If thread was ready, adjust queues
 | ||||
|     if (status == ThreadStatus::Ready) | ||||
|         ready_queue.move(this, current_priority, priority); | ||||
|         thread_manager.ready_queue.move(this, current_priority, priority); | ||||
|     else | ||||
|         ready_queue.prepare(priority); | ||||
|         thread_manager.ready_queue.prepare(priority); | ||||
| 
 | ||||
|     nominal_priority = current_priority = priority; | ||||
| } | ||||
|  | @ -435,9 +400,9 @@ void Thread::UpdatePriority() { | |||
| void Thread::BoostPriority(u32 priority) { | ||||
|     // If thread was ready, adjust queues
 | ||||
|     if (status == ThreadStatus::Ready) | ||||
|         ready_queue.move(this, current_priority, priority); | ||||
|         thread_manager.ready_queue.move(this, current_priority, priority); | ||||
|     else | ||||
|         ready_queue.prepare(priority); | ||||
|         thread_manager.ready_queue.prepare(priority); | ||||
|     current_priority = priority; | ||||
| } | ||||
| 
 | ||||
|  | @ -457,11 +422,11 @@ SharedPtr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u32 pri | |||
|     return thread; | ||||
| } | ||||
| 
 | ||||
| bool HaveReadyThreads() { | ||||
| bool ThreadManager::HaveReadyThreads() { | ||||
|     return ready_queue.get_first() != nullptr; | ||||
| } | ||||
| 
 | ||||
| void Reschedule() { | ||||
| void ThreadManager::Reschedule() { | ||||
|     Thread* cur = GetCurrentThread(); | ||||
|     Thread* next = PopNextReadyThread(); | ||||
| 
 | ||||
|  | @ -496,26 +461,20 @@ VAddr Thread::GetCommandBufferAddress() const { | |||
|     return GetTLSAddress() + CommandHeaderOffset; | ||||
| } | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| void ThreadingInit() { | ||||
|     ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); | ||||
| 
 | ||||
|     current_thread = nullptr; | ||||
|     next_thread_id = 1; | ||||
| ThreadManager::ThreadManager() { | ||||
|     ThreadWakeupEventType = | ||||
|         CoreTiming::RegisterEvent("ThreadWakeupCallback", [this](u64 thread_id, s64 cycle_late) { | ||||
|             ThreadWakeupCallback(thread_id, cycle_late); | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void ThreadingShutdown() { | ||||
|     current_thread = nullptr; | ||||
| 
 | ||||
| ThreadManager::~ThreadManager() { | ||||
|     for (auto& t : thread_list) { | ||||
|         t->Stop(); | ||||
|     } | ||||
|     thread_list.clear(); | ||||
|     ready_queue.clear(); | ||||
| } | ||||
| 
 | ||||
| const std::vector<SharedPtr<Thread>>& GetThreadList() { | ||||
| const std::vector<SharedPtr<Thread>>& ThreadManager::GetThreadList() { | ||||
|     return thread_list; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,7 +10,9 @@ | |||
| #include <boost/container/flat_map.hpp> | ||||
| #include <boost/container/flat_set.hpp> | ||||
| #include "common/common_types.h" | ||||
| #include "common/thread_queue_list.h" | ||||
| #include "core/arm/arm_interface.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| #include "core/hle/result.h" | ||||
|  | @ -53,6 +55,87 @@ enum class ThreadWakeupReason { | |||
|     Timeout // The thread was woken up due to a wait timeout.
 | ||||
| }; | ||||
| 
 | ||||
| class ThreadManager { | ||||
| public: | ||||
|     ThreadManager(); | ||||
|     ~ThreadManager(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Creates a new thread ID | ||||
|      * @return The new thread ID | ||||
|      */ | ||||
|     u32 NewThreadId(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets the current thread | ||||
|      */ | ||||
|     Thread* GetCurrentThread() const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Reschedules to the next available thread (call after current thread is suspended) | ||||
|      */ | ||||
|     void Reschedule(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Prints the thread queue for debugging purposes | ||||
|      */ | ||||
|     void DebugThreadQueue(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Returns whether there are any threads that are ready to run. | ||||
|      */ | ||||
|     bool HaveReadyThreads(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Waits the current thread on a sleep | ||||
|      */ | ||||
|     void WaitCurrentThread_Sleep(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Stops the current thread and removes it from the thread_list | ||||
|      */ | ||||
|     void ExitCurrentThread(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Get a const reference to the thread list for debug use | ||||
|      */ | ||||
|     const std::vector<SharedPtr<Thread>>& GetThreadList(); | ||||
| 
 | ||||
| private: | ||||
|     /**
 | ||||
|      * Switches the CPU's active thread context to that of the specified thread | ||||
|      * @param new_thread The thread to switch to | ||||
|      */ | ||||
|     void SwitchContext(Thread* new_thread); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Pops and returns the next thread from the thread queue | ||||
|      * @return A pointer to the next ready thread | ||||
|      */ | ||||
|     Thread* PopNextReadyThread(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Callback that will wake up the thread it was scheduled for | ||||
|      * @param thread_id The ID of the thread that's been awoken | ||||
|      * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time | ||||
|      */ | ||||
|     void ThreadWakeupCallback(u64 thread_id, s64 cycles_late); | ||||
| 
 | ||||
|     u32 next_thread_id = 1; | ||||
|     SharedPtr<Thread> current_thread; | ||||
|     Common::ThreadQueueList<Thread*, ThreadPrioLowest + 1> ready_queue; | ||||
|     std::unordered_map<u64, Thread*> wakeup_callback_table; | ||||
| 
 | ||||
|     /// Event type for the thread wake up event
 | ||||
|     CoreTiming::EventType* ThreadWakeupEventType = nullptr; | ||||
| 
 | ||||
|     // Lists all threadsthat aren't deleted.
 | ||||
|     std::vector<SharedPtr<Thread>> thread_list; | ||||
| 
 | ||||
|     friend class Thread; | ||||
|     friend class KernelSystem; | ||||
| }; | ||||
| 
 | ||||
| class Thread final : public WaitObject { | ||||
| public: | ||||
|     std::string GetName() const override { | ||||
|  | @ -210,6 +293,8 @@ private: | |||
|     explicit Thread(KernelSystem&); | ||||
|     ~Thread() override; | ||||
| 
 | ||||
|     ThreadManager& thread_manager; | ||||
| 
 | ||||
|     friend class KernelSystem; | ||||
| }; | ||||
| 
 | ||||
|  | @ -224,56 +309,4 @@ private: | |||
| SharedPtr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u32 priority, | ||||
|                                   SharedPtr<Process> owner_process); | ||||
| 
 | ||||
| /**
 | ||||
|  * Returns whether there are any threads that are ready to run. | ||||
|  */ | ||||
| bool HaveReadyThreads(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Reschedules to the next available thread (call after current thread is suspended) | ||||
|  */ | ||||
| void Reschedule(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Arbitrate the highest priority thread that is waiting | ||||
|  * @param address The address for which waiting threads should be arbitrated | ||||
|  */ | ||||
| Thread* ArbitrateHighestPriorityThread(u32 address); | ||||
| 
 | ||||
| /**
 | ||||
|  * Arbitrate all threads currently waiting. | ||||
|  * @param address The address for which waiting threads should be arbitrated | ||||
|  */ | ||||
| void ArbitrateAllThreads(u32 address); | ||||
| 
 | ||||
| /**
 | ||||
|  * Gets the current thread | ||||
|  */ | ||||
| Thread* GetCurrentThread(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Waits the current thread on a sleep | ||||
|  */ | ||||
| void WaitCurrentThread_Sleep(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Stops the current thread and removes it from the thread_list | ||||
|  */ | ||||
| void ExitCurrentThread(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Initialize threading | ||||
|  */ | ||||
| void ThreadingInit(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Shutdown threading | ||||
|  */ | ||||
| void ThreadingShutdown(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Get a const reference to the thread list for debug use | ||||
|  */ | ||||
| const std::vector<SharedPtr<Thread>>& GetThreadList(); | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
|  | @ -6,7 +6,6 @@ | |||
| #include <unordered_map> | ||||
| #include "common/assert.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/hle/kernel/handle_table.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
|  | @ -14,16 +13,10 @@ | |||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| /// The event type of the generic timer callback event
 | ||||
| static CoreTiming::EventType* timer_callback_event_type = nullptr; | ||||
| 
 | ||||
| static u64 next_timer_callback_id; | ||||
| static std::unordered_map<u64, Timer*> timer_callback_table; | ||||
| 
 | ||||
| Timer::Timer(KernelSystem& kernel) : WaitObject(kernel) {} | ||||
| Timer::Timer(KernelSystem& kernel) : WaitObject(kernel), timer_manager(kernel.GetTimerManager()) {} | ||||
| Timer::~Timer() { | ||||
|     Cancel(); | ||||
|     timer_callback_table.erase(callback_id); | ||||
|     timer_manager.timer_callback_table.erase(callback_id); | ||||
| } | ||||
| 
 | ||||
| SharedPtr<Timer> KernelSystem::CreateTimer(ResetType reset_type, std::string name) { | ||||
|  | @ -34,8 +27,8 @@ SharedPtr<Timer> KernelSystem::CreateTimer(ResetType reset_type, std::string nam | |||
|     timer->name = std::move(name); | ||||
|     timer->initial_delay = 0; | ||||
|     timer->interval_delay = 0; | ||||
|     timer->callback_id = ++next_timer_callback_id; | ||||
|     timer_callback_table[timer->callback_id] = timer.get(); | ||||
|     timer->callback_id = ++timer_manager->next_timer_callback_id; | ||||
|     timer_manager->timer_callback_table[timer->callback_id] = timer.get(); | ||||
| 
 | ||||
|     return timer; | ||||
| } | ||||
|  | @ -62,12 +55,13 @@ void Timer::Set(s64 initial, s64 interval) { | |||
|         // Immediately invoke the callback
 | ||||
|         Signal(0); | ||||
|     } else { | ||||
|         CoreTiming::ScheduleEvent(nsToCycles(initial), timer_callback_event_type, callback_id); | ||||
|         CoreTiming::ScheduleEvent(nsToCycles(initial), timer_manager.timer_callback_event_type, | ||||
|                                   callback_id); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void Timer::Cancel() { | ||||
|     CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_id); | ||||
|     CoreTiming::UnscheduleEvent(timer_manager.timer_callback_event_type, callback_id); | ||||
| } | ||||
| 
 | ||||
| void Timer::Clear() { | ||||
|  | @ -92,12 +86,12 @@ void Timer::Signal(s64 cycles_late) { | |||
|     if (interval_delay != 0) { | ||||
|         // Reschedule the timer with the interval delay
 | ||||
|         CoreTiming::ScheduleEvent(nsToCycles(interval_delay) - cycles_late, | ||||
|                                   timer_callback_event_type, callback_id); | ||||
|                                   timer_manager.timer_callback_event_type, callback_id); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// The timer callback event, called when a timer is fired
 | ||||
| static void TimerCallback(u64 callback_id, s64 cycles_late) { | ||||
| void TimerManager::TimerCallback(u64 callback_id, s64 cycles_late) { | ||||
|     SharedPtr<Timer> timer = timer_callback_table.at(callback_id); | ||||
| 
 | ||||
|     if (timer == nullptr) { | ||||
|  | @ -108,12 +102,11 @@ static void TimerCallback(u64 callback_id, s64 cycles_late) { | |||
|     timer->Signal(cycles_late); | ||||
| } | ||||
| 
 | ||||
| void TimersInit() { | ||||
|     next_timer_callback_id = 0; | ||||
|     timer_callback_table.clear(); | ||||
|     timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); | ||||
| TimerManager::TimerManager() { | ||||
|     timer_callback_event_type = | ||||
|         CoreTiming::RegisterEvent("TimerCallback", [this](u64 thread_id, s64 cycle_late) { | ||||
|             TimerCallback(thread_id, cycle_late); | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| void TimersShutdown() {} | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
|  | @ -5,11 +5,30 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/hle/kernel/object.h" | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
| class TimerManager { | ||||
| public: | ||||
|     TimerManager(); | ||||
| 
 | ||||
| private: | ||||
|     /// The timer callback event, called when a timer is fired
 | ||||
|     void TimerCallback(u64 callback_id, s64 cycles_late); | ||||
| 
 | ||||
|     /// The event type of the generic timer callback event
 | ||||
|     CoreTiming::EventType* timer_callback_event_type = nullptr; | ||||
| 
 | ||||
|     u64 next_timer_callback_id = 0; | ||||
|     std::unordered_map<u64, Timer*> timer_callback_table; | ||||
| 
 | ||||
|     friend class Timer; | ||||
|     friend class KernelSystem; | ||||
| }; | ||||
| 
 | ||||
| class Timer final : public WaitObject { | ||||
| public: | ||||
|     std::string GetTypeName() const override { | ||||
|  | @ -74,12 +93,9 @@ private: | |||
|     /// ID used as userdata to reference this object when inserting into the CoreTiming queue.
 | ||||
|     u64 callback_id; | ||||
| 
 | ||||
|     TimerManager& timer_manager; | ||||
| 
 | ||||
|     friend class KernelSystem; | ||||
| }; | ||||
| 
 | ||||
| /// Initializes the required variables for timers
 | ||||
| void TimersInit(); | ||||
| /// Tears down the timer variables
 | ||||
| void TimersShutdown(); | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
|  | @ -71,7 +71,8 @@ void File::Read(Kernel::HLERequestContext& ctx) { | |||
|     rb.PushMappedBuffer(buffer); | ||||
| 
 | ||||
|     std::chrono::nanoseconds read_timeout_ns{backend->GetReadDelayNs(length)}; | ||||
|     ctx.SleepClientThread(Kernel::GetCurrentThread(), "file::read", read_timeout_ns, | ||||
|     ctx.SleepClientThread(system.Kernel().GetThreadManager().GetCurrentThread(), "file::read", | ||||
|                           read_timeout_ns, | ||||
|                           [](Kernel::SharedPtr<Kernel::Thread> thread, | ||||
|                              Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { | ||||
|                               // Nothing to do here
 | ||||
|  |  | |||
|  | @ -1231,7 +1231,8 @@ void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx) { | |||
|     static constexpr std::chrono::nanoseconds UDSConnectionTimeout{300000000}; | ||||
| 
 | ||||
|     connection_event = ctx.SleepClientThread( | ||||
|         Kernel::GetCurrentThread(), "uds::ConnectToNetwork", UDSConnectionTimeout, | ||||
|         system.Kernel().GetThreadManager().GetCurrentThread(), "uds::ConnectToNetwork", | ||||
|         UDSConnectionTimeout, | ||||
|         [](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, | ||||
|            Kernel::ThreadWakeupReason reason) { | ||||
|             // TODO(B3N30): Add error handling for host full and timeout
 | ||||
|  |  | |||
|  | @ -179,7 +179,10 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(u32* cmd_buf, const Funct | |||
| } | ||||
| 
 | ||||
| void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_session) { | ||||
|     u32* cmd_buf = Kernel::GetCommandBuffer(); | ||||
|     Kernel::KernelSystem& kernel = Core::System::GetInstance().Kernel(); | ||||
|     auto thread = kernel.GetThreadManager().GetCurrentThread(); | ||||
|     // TODO(wwylele): avoid GetPointer
 | ||||
|     u32* cmd_buf = reinterpret_cast<u32*>(Memory::GetPointer(thread->GetCommandBufferAddress())); | ||||
| 
 | ||||
|     u32 header_code = cmd_buf[0]; | ||||
|     auto itr = handlers.find(header_code); | ||||
|  | @ -188,8 +191,7 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_ses | |||
|         return ReportUnimplementedFunction(cmd_buf, info); | ||||
|     } | ||||
| 
 | ||||
|     Kernel::SharedPtr<Kernel::Process> current_process = | ||||
|         Core::System::GetInstance().Kernel().GetCurrentProcess(); | ||||
|     Kernel::SharedPtr<Kernel::Process> current_process = kernel.GetCurrentProcess(); | ||||
| 
 | ||||
|     // TODO(yuriks): The kernel should be the one handling this as part of translation after
 | ||||
|     // everything else is migrated
 | ||||
|  | @ -199,7 +201,6 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_ses | |||
|     LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName().c_str(), cmd_buf)); | ||||
|     handler_invoker(this, info->handler_callback, context); | ||||
| 
 | ||||
|     auto thread = Kernel::GetCurrentThread(); | ||||
|     ASSERT(thread->status == Kernel::ThreadStatus::Running || | ||||
|            thread->status == Kernel::ThreadStatus::WaitHleEvent); | ||||
|     // Only write the response immediately if the thread is still running. If the HLE handler put
 | ||||
|  |  | |||
|  | @ -128,8 +128,8 @@ void SRV::GetServiceHandle(Kernel::HLERequestContext& ctx) { | |||
|         if (wait_until_available && client_port.Code() == ERR_SERVICE_NOT_REGISTERED) { | ||||
|             LOG_INFO(Service_SRV, "called service={} delayed", name); | ||||
|             Kernel::SharedPtr<Kernel::Event> get_service_handle_event = | ||||
|                 ctx.SleepClientThread(Kernel::GetCurrentThread(), "GetServiceHandle", | ||||
|                                       std::chrono::nanoseconds(-1), get_handle); | ||||
|                 ctx.SleepClientThread(system.Kernel().GetThreadManager().GetCurrentThread(), | ||||
|                                       "GetServiceHandle", std::chrono::nanoseconds(-1), get_handle); | ||||
|             get_service_handle_delayed_map[name] = std::move(get_service_handle_event); | ||||
|             return; | ||||
|         } else { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue