mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	SVC: Fixed SleepThread.
It will now properly wait the specified number of nanoseconds and then wake up the thread.
This commit is contained in:
		
							parent
							
								
									91d96840ea
								
							
						
					
					
						commit
						dfc440785a
					
				
					 3 changed files with 43 additions and 8 deletions
				
			
		|  | @ -308,6 +308,37 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_addres | ||||||
|     GetCurrentThread()->wait_address = wait_address; |     GetCurrentThread()->wait_address = wait_address; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Event type for the thread wake up event
 | ||||||
|  | static int ThreadWakeupEventType = -1; | ||||||
|  | 
 | ||||||
|  | /// Callback that will wake up the thread it was scheduled for
 | ||||||
|  | static void ThreadWakeupCallback(u64 parameter, int cycles_late) { | ||||||
|  |     Handle handle = static_cast<Handle>(parameter); | ||||||
|  |     Thread* thread = Kernel::g_handle_table.Get<Thread>(handle); | ||||||
|  |     if (thread == nullptr) { | ||||||
|  |         LOG_ERROR(Kernel, "Thread doesn't exist %u", handle); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Kernel::ResumeThreadFromWait(handle); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | void WakeThreadAfterDelay(Handle handle, s64 nanoseconds) { | ||||||
|  |     // Don't schedule a wakeup if the thread wants to wait forever
 | ||||||
|  |     if (nanoseconds == -1) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     Thread* thread = Kernel::g_handle_table.Get<Thread>(handle); | ||||||
|  |     if (thread == nullptr) { | ||||||
|  |         LOG_ERROR(Kernel, "Thread doesn't exist %u", handle); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     u64 microseconds = nanoseconds / 1000; | ||||||
|  |     CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, handle); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// Resumes a thread from waiting by marking it as "ready"
 | /// Resumes a thread from waiting by marking it as "ready"
 | ||||||
| void ResumeThreadFromWait(Handle handle) { | void ResumeThreadFromWait(Handle handle) { | ||||||
|     Thread* thread = Kernel::g_handle_table.Get<Thread>(handle); |     Thread* thread = Kernel::g_handle_table.Get<Thread>(handle); | ||||||
|  | @ -499,14 +530,6 @@ void Reschedule() { | ||||||
|                 thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_handle); |                 thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_handle); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     // 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()); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool IsIdleThread(Handle handle) { | bool IsIdleThread(Handle handle) { | ||||||
|  | @ -533,6 +556,7 @@ ResultCode GetThreadId(u32* thread_id, Handle handle) { | ||||||
| 
 | 
 | ||||||
| void ThreadingInit() { | void ThreadingInit() { | ||||||
|     next_thread_id = INITIAL_THREAD_ID; |     next_thread_id = INITIAL_THREAD_ID; | ||||||
|  |     ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ThreadingShutdown() { | void ThreadingShutdown() { | ||||||
|  |  | ||||||
|  | @ -87,6 +87,13 @@ Handle GetCurrentThreadHandle(); | ||||||
|  */ |  */ | ||||||
| void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle()); | void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle()); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Schedules an event to wake up the specified thread after the specified delay. | ||||||
|  |  * @param handle The thread handle. | ||||||
|  |  * @param nanoseconds The time this thread will be allowed to sleep for. | ||||||
|  |  */ | ||||||
|  | void WakeThreadAfterDelay(Handle handle, s64 nanoseconds); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Puts the current thread in the wait state for the given type |  * Puts the current thread in the wait state for the given type | ||||||
|  * @param wait_type Type of wait |  * @param wait_type Type of wait | ||||||
|  |  | ||||||
|  | @ -344,6 +344,10 @@ static void SleepThread(s64 nanoseconds) { | ||||||
| 
 | 
 | ||||||
|     // Sleep current thread and check for next thread to schedule
 |     // Sleep current thread and check for next thread to schedule
 | ||||||
|     Kernel::WaitCurrentThread(WAITTYPE_SLEEP); |     Kernel::WaitCurrentThread(WAITTYPE_SLEEP); | ||||||
|  | 
 | ||||||
|  |     // Create an event to wake the thread up after the specified nanosecond delay has passed
 | ||||||
|  |     Kernel::WakeThreadAfterDelay(Kernel::GetCurrentThreadHandle(), nanoseconds); | ||||||
|  | 
 | ||||||
|     HLE::Reschedule(__func__); |     HLE::Reschedule(__func__); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue