Esempio n. 1
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. 2
0
void Thread::ResumeFromWait() {
    // Cancel any outstanding wakeup events for this thread
    CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);

    switch (status) {
        case THREADSTATUS_WAIT_SYNCH:
            // Remove this thread from all other WaitObjects
            for (auto wait_object : wait_objects)
                wait_object->RemoveWaitingThread(this);
            break;
        case THREADSTATUS_WAIT_ARB:
        case THREADSTATUS_WAIT_SLEEP:
            break;
        case THREADSTATUS_RUNNING:
        case THREADSTATUS_READY:
            DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId());
            return;
        case THREADSTATUS_DEAD:
            // This should never happen, as threads must complete before being stopped.
            DEBUG_ASSERT_MSG(false, "Thread with object id %u cannot be resumed because it's DEAD.",
                GetObjectId());
            return;
    }
    
    ready_queue.push_back(current_priority, this);
    status = THREADSTATUS_READY;
}
Esempio n. 3
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. 4
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. 5
0
ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority,
        u32 arg, s32 processor_id, VAddr stack_top) {
    if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
        s32 new_priority = MathUtil::Clamp<s32>(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
        LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d",
            name.c_str(), priority, new_priority);
        // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
        // validity of this
        priority = new_priority;
    }

    if (!Memory::GetPointer(entry_point)) {
        LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point);
        // TODO: Verify error
        return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
                ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
    }

    SharedPtr<Thread> thread(new Thread);

    thread_list.push_back(thread);
    ready_queue.prepare(priority);

    thread->thread_id = NewThreadId();
    thread->status = THREADSTATUS_DORMANT;
    thread->entry_point = entry_point;
    thread->stack_top = stack_top;
    thread->initial_priority = thread->current_priority = priority;
    thread->processor_id = processor_id;
    thread->wait_set_output = false;
    thread->wait_all = false;
    thread->wait_objects.clear();
    thread->wait_address = 0;
    thread->name = std::move(name);
    thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom();

    // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
    // to initialize the context
    Core::g_app_core->ResetContext(thread->context, stack_top, entry_point, arg);

    ready_queue.push_back(thread->current_priority, thread.get());
    thread->status = THREADSTATUS_READY;

    return MakeResult<SharedPtr<Thread>>(std::move(thread));
}