/// Stops the current thread void StopThread(Handle handle, const char* reason) { Thread* thread = g_object_pool.GetFast<Thread>(handle); _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); ChangeReadyState(thread, false); thread->status = THREADSTATUS_DORMANT; for (size_t i = 0; i < thread->waiting_threads.size(); ++i) { const Handle waiting_thread = thread->waiting_threads[i]; if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { ResumeThreadFromWait(waiting_thread); } } thread->waiting_threads.clear(); // Stopped threads are never waiting. thread->wait_type = WAITTYPE_NONE; thread->wait_handle = 0; }
/// Reschedules to the next available thread (call after current thread is suspended) void Reschedule() { Thread* prev = GetCurrentThread(); Thread* next = NextThread(); HLE::g_reschedule = false; if (next > 0) { INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); SwitchContext(next); // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again. // This results in the current thread yielding on a VBLANK once, and then it will be // immediately placed back in the queue for execution. if (prev->wait_type == WAITTYPE_VBLANK) { ResumeThreadFromWait(prev->GetHandle()); } } }
/** * Signals an event * @param handle Handle to event to signal * @return Result of operation, 0 on success, otherwise error code */ Result SignalEvent(const Handle handle) { Event* evt = g_object_pool.GetFast<Event>(handle); _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); // Resume threads waiting for event to signal bool event_caught = false; for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { ResumeThreadFromWait( evt->waiting_threads[i]); // If any thread is signalled awake by this event, assume the event was "caught" and reset // the event. This will result in the next thread waiting on the event to block. Otherwise, // the event will not be reset, and the next thread to call WaitSynchronization on it will // not block. Not sure if this is correct behavior, but it seems to work. event_caught = true; } evt->waiting_threads.clear(); if (!evt->permanent_locked) { evt->locked = event_caught; } return 0; }