Esempio n. 1
0
void Thread::Stop() {
    // Release all the mutexes that this thread holds
    ReleaseThreadMutexes(this);

    // Cancel any outstanding wakeup events for this thread
    CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
    wakeup_callback_handle_table.Close(callback_handle);
    callback_handle = 0;

    // Clean up thread from ready queue
    // This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
    if (status == THREADSTATUS_READY){
        ready_queue.remove(current_priority, this);
    }

    status = THREADSTATUS_DEAD;

    WakeupAllWaitingThreads();

    // Clean up any dangling references in objects that this thread was waiting for
    for (auto& wait_object : wait_objects) {
        wait_object->RemoveWaitingThread(this);
    }
    wait_objects.clear();

    // Mark the TLS slot in the thread's page as free.
    u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
    u32 tls_slot = ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
    Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot);

    HLE::Reschedule(__func__);
}
Esempio n. 2
0
/** 
 * Switches the CPU's active thread context to that of the specified thread
 * @param new_thread The thread to switch to
 */
static void SwitchContext(Thread* new_thread) {
    DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running.");

    Thread* previous_thread = GetCurrentThread();

    // Save context for previous thread
    if (previous_thread) {
        Core::g_app_core->SaveContext(previous_thread->context);

        if (previous_thread->status == THREADSTATUS_RUNNING) {
            // This is only the case when a reschedule is triggered without the current thread
            // yielding execution (i.e. an event triggered, system core time-sliced, etc)
            ready_queue.push_front(previous_thread->current_priority, previous_thread);
            previous_thread->status = THREADSTATUS_READY;
        }
    }

    // Load context of new thread
    if (new_thread) {
        current_thread = new_thread;

        ready_queue.remove(new_thread->current_priority, new_thread);
        new_thread->status = THREADSTATUS_RUNNING;

        Core::g_app_core->LoadContext(new_thread->context);
    } else {
        current_thread = nullptr;
    }
}
Esempio n. 3
0
/// Set the priority of the thread specified by handle
Result SetThreadPriority(Handle handle, s32 priority) {
    Thread* thread = nullptr;
    if (!handle) {
        thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
    } else {
        thread = g_object_pool.GetFast<Thread>(handle);
    }
    _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");

    // If priority is invalid, clamp to valid range
    if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
        s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
        WARN_LOG(KERNEL, "invalid priority=0x%08X, clamping to %08X", priority, new_priority);
        // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
        // validity of this
        priority = new_priority;
    }

    // Change thread priority
    s32 old = thread->current_priority;
    g_thread_ready_queue.remove(old, handle);
    thread->current_priority = priority;
    g_thread_ready_queue.prepare(thread->current_priority);

    // Change thread status to "ready" and push to ready queue
    if (thread->IsRunning()) {
        thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY;
    }
    if (thread->IsReady()) {
        g_thread_ready_queue.push_back(thread->current_priority, handle);
    }

    return 0;
}
Esempio n. 4
0
/// Change a thread to "ready" state
void ChangeReadyState(Thread* t, bool ready) {
    Handle handle = t->GetHandle();
    if (t->IsReady()) {
        if (!ready) {
            g_thread_ready_queue.remove(t->current_priority, handle);
        }
    }  else if (ready) {
        if (t->IsRunning()) {
            g_thread_ready_queue.push_front(t->current_priority, handle);
        } else {
            g_thread_ready_queue.push_back(t->current_priority, handle);
        }
        t->status = THREADSTATUS_READY;
    }
}
Esempio n. 5
0
void Thread::SetPriority(s32 priority) {
    ClampPriority(this, &priority);

    if (current_priority == priority) {
        return;
    }

    if (status == THREADSTATUS_READY) {
        // If thread was ready, adjust queues
        ready_queue.remove(current_priority, this);
        ready_queue.prepare(priority);
        ready_queue.push_back(priority, this);
    }
    
    current_priority = priority;
}
Esempio n. 6
0
void Thread::Stop() {
    // Release all the mutexes that this thread holds
    ReleaseThreadMutexes(this);

    // Cancel any outstanding wakeup events for this thread
    CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);

    // Clean up thread from ready queue
    // This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
    if (status == THREADSTATUS_READY){
        ready_queue.remove(current_priority, this);
    }

    status = THREADSTATUS_DEAD;
    
    WakeupAllWaitingThreads();

    // Clean up any dangling references in objects that this thread was waiting for
    for (auto& wait_object : wait_objects) {
        wait_object->RemoveWaitingThread(this);
    }
}