mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-27 00:00:08 +00:00
commit
cf1bbe8705
@ -308,6 +308,37 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_addres
|
||||
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"
|
||||
void ResumeThreadFromWait(Handle 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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@ -533,6 +556,7 @@ ResultCode GetThreadId(u32* thread_id, Handle handle) {
|
||||
|
||||
void ThreadingInit() {
|
||||
next_thread_id = INITIAL_THREAD_ID;
|
||||
ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
|
||||
}
|
||||
|
||||
void ThreadingShutdown() {
|
||||
|
@ -87,6 +87,13 @@ 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
|
||||
* @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
|
||||
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__);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user