فهرست منبع

SVC: Fixed SleepThread.

It will now properly wait the specified number of nanoseconds and then wake up the thread.
Subv 11 سال پیش
والد
کامیت
dfc440785a
3فایلهای تغییر یافته به همراه43 افزوده شده و 8 حذف شده
  1. 32 8
      src/core/hle/kernel/thread.cpp
  2. 7 0
      src/core/hle/kernel/thread.h
  3. 4 0
      src/core/hle/svc.cpp

+ 32 - 8
src/core/hle/kernel/thread.cpp

@@ -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() {

+ 7 - 0
src/core/hle/kernel/thread.h

@@ -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

+ 4 - 0
src/core/hle/svc.cpp

@@ -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__);
 }