mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #439 from Subv/idle_thread_m
Threads: Use a dummy idle thread when no other are ready.
This commit is contained in:
		
						commit
						91d96840ea
					
				
					 4 changed files with 47 additions and 2 deletions
				
			
		|  | @ -5,6 +5,7 @@ | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| 
 | 
 | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
|  | #include "core/core_timing.h" | ||||||
| 
 | 
 | ||||||
| #include "core/settings.h" | #include "core/settings.h" | ||||||
| #include "core/arm/disassembler/arm_disasm.h" | #include "core/arm/disassembler/arm_disasm.h" | ||||||
|  | @ -23,7 +24,17 @@ ARM_Interface*     g_sys_core = nullptr;  ///< ARM11 system (OS) core | ||||||
| 
 | 
 | ||||||
| /// Run the core CPU loop
 | /// Run the core CPU loop
 | ||||||
| void RunLoop(int tight_loop) { | void RunLoop(int tight_loop) { | ||||||
|  |     // If the current thread is an idle thread, then don't execute instructions,
 | ||||||
|  |     // instead advance to the next event and try to yield to the next thread
 | ||||||
|  |     if (Kernel::IsIdleThread(Kernel::GetCurrentThreadHandle())) { | ||||||
|  |         LOG_TRACE(Core_ARM11, "Idling"); | ||||||
|  |         CoreTiming::Idle(); | ||||||
|  |         CoreTiming::Advance(); | ||||||
|  |         HLE::Reschedule(__func__); | ||||||
|  |     } else { | ||||||
|         g_app_core->Run(tight_loop); |         g_app_core->Run(tight_loop); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     HW::Update(); |     HW::Update(); | ||||||
|     if (HLE::g_reschedule) { |     if (HLE::g_reschedule) { | ||||||
|         Kernel::Reschedule(); |         Kernel::Reschedule(); | ||||||
|  |  | ||||||
|  | @ -124,6 +124,8 @@ bool LoadExec(u32 entry_point) { | ||||||
| 
 | 
 | ||||||
|     // 0x30 is the typical main thread priority I've seen used so far
 |     // 0x30 is the typical main thread priority I've seen used so far
 | ||||||
|     g_main_thread = Kernel::SetupMainThread(0x30); |     g_main_thread = Kernel::SetupMainThread(0x30); | ||||||
|  |     // Setup the idle thread
 | ||||||
|  |     Kernel::SetupIdleThread(); | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -11,6 +11,7 @@ | ||||||
| #include "common/thread_queue_list.h" | #include "common/thread_queue_list.h" | ||||||
| 
 | 
 | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
|  | #include "core/core_timing.h" | ||||||
| #include "core/hle/hle.h" | #include "core/hle/hle.h" | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
| #include "core/hle/kernel/thread.h" | #include "core/hle/kernel/thread.h" | ||||||
|  | @ -34,6 +35,7 @@ public: | ||||||
|     inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; } |     inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; } | ||||||
|     inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } |     inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } | ||||||
|     inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } |     inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } | ||||||
|  |     inline bool IsIdle() const { return idle; } | ||||||
| 
 | 
 | ||||||
|     ResultVal<bool> WaitSynchronization() override { |     ResultVal<bool> WaitSynchronization() override { | ||||||
|         const bool wait = status != THREADSTATUS_DORMANT; |         const bool wait = status != THREADSTATUS_DORMANT; | ||||||
|  | @ -69,6 +71,9 @@ public: | ||||||
|     std::vector<Handle> waiting_threads; |     std::vector<Handle> waiting_threads; | ||||||
| 
 | 
 | ||||||
|     std::string name; |     std::string name; | ||||||
|  | 
 | ||||||
|  |     /// Whether this thread is intended to never actually be executed, i.e. always idle
 | ||||||
|  |     bool idle = false; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // Lists all thread ids that aren't deleted/etc.
 | // Lists all thread ids that aren't deleted/etc.
 | ||||||
|  | @ -444,7 +449,14 @@ ResultCode SetThreadPriority(Handle handle, s32 priority) { | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Sets up the primary application thread
 | Handle SetupIdleThread() { | ||||||
|  |     Handle handle; | ||||||
|  |     Thread* thread = CreateThread(handle, "idle", 0, THREADPRIO_LOWEST, THREADPROCESSORID_0, 0, 0); | ||||||
|  |     thread->idle = true; | ||||||
|  |     CallThread(thread); | ||||||
|  |     return handle; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Handle SetupMainThread(s32 priority, int stack_size) { | Handle SetupMainThread(s32 priority, int stack_size) { | ||||||
|     Handle handle; |     Handle handle; | ||||||
| 
 | 
 | ||||||
|  | @ -497,6 +509,15 @@ void Reschedule() { | ||||||
|         ResumeThreadFromWait(prev->GetHandle()); |         ResumeThreadFromWait(prev->GetHandle()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool IsIdleThread(Handle handle) { | ||||||
|  |     Thread* thread = g_handle_table.Get<Thread>(handle); | ||||||
|  |     if (!thread) { | ||||||
|  |         LOG_ERROR(Kernel, "Thread not found %u", handle); | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |     return thread->IsIdle(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ResultCode GetThreadId(u32* thread_id, Handle handle) { | ResultCode GetThreadId(u32* thread_id, Handle handle) { | ||||||
|     Thread* thread = g_handle_table.Get<Thread>(handle); |     Thread* thread = g_handle_table.Get<Thread>(handle); | ||||||
|     if (thread == nullptr) |     if (thread == nullptr) | ||||||
|  |  | ||||||
|  | @ -104,6 +104,17 @@ ResultVal<u32> GetThreadPriority(const Handle handle); | ||||||
| /// Set the priority of the thread specified by handle
 | /// Set the priority of the thread specified by handle
 | ||||||
| ResultCode SetThreadPriority(Handle handle, s32 priority); | ResultCode SetThreadPriority(Handle handle, s32 priority); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Sets up the idle thread, this is a thread that is intended to never execute instructions, | ||||||
|  |  * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue | ||||||
|  |  * and will try to yield on every call. | ||||||
|  |  * @returns The handle of the idle thread | ||||||
|  |  */ | ||||||
|  | Handle SetupIdleThread(); | ||||||
|  | 
 | ||||||
|  | /// Whether the current thread is an idle thread
 | ||||||
|  | bool IsIdleThread(Handle thread); | ||||||
|  | 
 | ||||||
| /// Initialize threading
 | /// Initialize threading
 | ||||||
| void ThreadingInit(); | void ThreadingInit(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue