mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #318 from bunnei/simulate-thread-sleep
Thread: Wait current thread on svc_SleepThread
This commit is contained in:
		
						commit
						cdfe665a21
					
				
					 3 changed files with 35 additions and 22 deletions
				
			
		|  | @ -147,16 +147,19 @@ void ChangeReadyState(Thread* t, bool ready) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Verify that a thread has not been released from waiting
 | /// Check if a thread is blocking on a specified wait type
 | ||||||
| static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) { | static bool CheckWaitType(const Thread* thread, WaitType type) { | ||||||
|     _dbg_assert_(Kernel, thread != nullptr); |     return (type == thread->wait_type) && (thread->IsWaiting()); | ||||||
|     return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting()); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Verify that a thread has not been released from waiting (with wait address)
 | /// Check if a thread is blocking on a specified wait type with a specified handle
 | ||||||
| static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) { | static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle) { | ||||||
|     _dbg_assert_(Kernel, thread != nullptr); |     return CheckWaitType(thread, type) && (wait_handle == thread->wait_handle); | ||||||
|     return VerifyWait(thread, type, wait_handle) && (wait_address == thread->wait_address); | } | ||||||
|  | 
 | ||||||
|  | /// Check if a thread is blocking on a specified wait type with a specified handle and address
 | ||||||
|  | static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) { | ||||||
|  |     return CheckWaitType(thread, type, wait_handle) && (wait_address == thread->wait_address); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Stops the current thread
 | /// Stops the current thread
 | ||||||
|  | @ -171,9 +174,9 @@ ResultCode StopThread(Handle handle, const char* reason) { | ||||||
|     thread->status = THREADSTATUS_DORMANT; |     thread->status = THREADSTATUS_DORMANT; | ||||||
|     for (Handle waiting_handle : thread->waiting_threads) { |     for (Handle waiting_handle : thread->waiting_threads) { | ||||||
|         Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); |         Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); | ||||||
|         if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { | 
 | ||||||
|  |         if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, handle)) | ||||||
|             ResumeThreadFromWait(waiting_handle); |             ResumeThreadFromWait(waiting_handle); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     thread->waiting_threads.clear(); |     thread->waiting_threads.clear(); | ||||||
| 
 | 
 | ||||||
|  | @ -209,7 +212,7 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { | ||||||
|     for (Handle handle : thread_queue) { |     for (Handle handle : thread_queue) { | ||||||
|         Thread* thread = g_object_pool.Get<Thread>(handle); |         Thread* thread = g_object_pool.Get<Thread>(handle); | ||||||
| 
 | 
 | ||||||
|         if (!VerifyWait(thread, WAITTYPE_ARB, arbiter, address)) |         if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) | ||||||
|             continue; |             continue; | ||||||
| 
 | 
 | ||||||
|         if (thread == nullptr) |         if (thread == nullptr) | ||||||
|  | @ -234,7 +237,7 @@ void ArbitrateAllThreads(u32 arbiter, u32 address) { | ||||||
|     for (Handle handle : thread_queue) { |     for (Handle handle : thread_queue) { | ||||||
|         Thread* thread = g_object_pool.Get<Thread>(handle); |         Thread* thread = g_object_pool.Get<Thread>(handle); | ||||||
| 
 | 
 | ||||||
|         if (VerifyWait(thread, WAITTYPE_ARB, arbiter, address)) |         if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) | ||||||
|             ResumeThreadFromWait(handle); |             ResumeThreadFromWait(handle); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -305,6 +308,8 @@ void ResumeThreadFromWait(Handle handle) { | ||||||
|     Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); |     Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); | ||||||
|     if (thread) { |     if (thread) { | ||||||
|         thread->status &= ~THREADSTATUS_WAIT; |         thread->status &= ~THREADSTATUS_WAIT; | ||||||
|  |         thread->wait_handle = 0; | ||||||
|  |         thread->wait_type = WAITTYPE_NONE; | ||||||
|         if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { |         if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { | ||||||
|             ChangeReadyState(thread, true); |             ChangeReadyState(thread, true); | ||||||
|         } |         } | ||||||
|  | @ -468,19 +473,27 @@ void Reschedule() { | ||||||
|     Thread* prev = GetCurrentThread(); |     Thread* prev = GetCurrentThread(); | ||||||
|     Thread* next = NextThread(); |     Thread* next = NextThread(); | ||||||
|     HLE::g_reschedule = false; |     HLE::g_reschedule = false; | ||||||
|     if (next > 0) { | 
 | ||||||
|  |     if (next != nullptr) { | ||||||
|         LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); |         LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); | ||||||
| 
 |  | ||||||
|         SwitchContext(next); |         SwitchContext(next); | ||||||
|  |     } else { | ||||||
|  |         LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); | ||||||
| 
 | 
 | ||||||
|         // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep
 |         for (Handle handle : thread_queue) { | ||||||
|         // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again.
 |             Thread* thread = g_object_pool.Get<Thread>(handle); | ||||||
|         // This results in the current thread yielding on a VBLANK once, and then it will be
 |             LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X", | ||||||
|         // immediately placed back in the queue for execution.
 |                 thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_handle); | ||||||
|         if (prev->wait_type == WAITTYPE_VBLANK) { |  | ||||||
|             ResumeThreadFromWait(prev->GetHandle()); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     // TODO(bunnei): Hack - There is no timing mechanism yet to wake up a thread if it has been put
 | ||||||
|  |     // to sleep. So, we'll just immediately set it to "ready" again after an attempted context
 | ||||||
|  |     // switch has occurred. This results in the current thread yielding on a sleep once, and then it
 | ||||||
|  |     // will immediately be placed back in the queue for execution.
 | ||||||
|  | 
 | ||||||
|  |     if (CheckWaitType(prev, WAITTYPE_SLEEP)) | ||||||
|  |         ResumeThreadFromWait(prev->GetHandle()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode GetThreadId(u32* thread_id, Handle handle) { | ResultCode GetThreadId(u32* thread_id, Handle handle) { | ||||||
|  |  | ||||||
|  | @ -40,7 +40,6 @@ enum WaitType { | ||||||
|     WAITTYPE_SEMA, |     WAITTYPE_SEMA, | ||||||
|     WAITTYPE_EVENT, |     WAITTYPE_EVENT, | ||||||
|     WAITTYPE_THREADEND, |     WAITTYPE_THREADEND, | ||||||
|     WAITTYPE_VBLANK, |  | ||||||
|     WAITTYPE_MUTEX, |     WAITTYPE_MUTEX, | ||||||
|     WAITTYPE_SYNCH, |     WAITTYPE_SYNCH, | ||||||
|     WAITTYPE_ARB, |     WAITTYPE_ARB, | ||||||
|  |  | ||||||
|  | @ -352,7 +352,8 @@ static Result ClearEvent(Handle evt) { | ||||||
| static void SleepThread(s64 nanoseconds) { | static void SleepThread(s64 nanoseconds) { | ||||||
|     LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); |     LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds); | ||||||
| 
 | 
 | ||||||
|     // Check for next thread to schedule
 |     // Sleep current thread and check for next thread to schedule
 | ||||||
|  |     Kernel::WaitCurrentThread(WAITTYPE_SLEEP); | ||||||
|     HLE::Reschedule(__func__); |     HLE::Reschedule(__func__); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue