mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	svc: Implement yield types 0 and -1
This commit is contained in:
		
							parent
							
								
									f02b125ac8
								
							
						
					
					
						commit
						409dcf0e0a
					
				@ -6,6 +6,7 @@
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <deque>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <boost/range/algorithm_ext/erase.hpp>
 | 
			
		||||
 | 
			
		||||
namespace Common {
 | 
			
		||||
@ -49,6 +50,21 @@ struct ThreadQueueList {
 | 
			
		||||
        return T();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    T get_first_filter(std::function<bool(T)> filter) const {
 | 
			
		||||
        const Queue* cur = first;
 | 
			
		||||
        while (cur != nullptr) {
 | 
			
		||||
            if (!cur->data.empty()) {
 | 
			
		||||
                for (const auto& item : cur->data) {
 | 
			
		||||
                    if (filter(item))
 | 
			
		||||
                        return item;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            cur = cur->next_nonempty;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return T();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    T pop_first() {
 | 
			
		||||
        Queue* cur = first;
 | 
			
		||||
        while (cur != nullptr) {
 | 
			
		||||
 | 
			
		||||
@ -169,6 +169,16 @@ void Scheduler::UnscheduleThread(Thread* thread, u32 priority) {
 | 
			
		||||
    ready_queue.remove(priority, thread);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Scheduler::RescheduleThread(Thread* thread, u32 priority) {
 | 
			
		||||
    std::lock_guard<std::mutex> lock(scheduler_mutex);
 | 
			
		||||
 | 
			
		||||
    // Thread is not in queue
 | 
			
		||||
    ASSERT(ready_queue.contains(thread) != -1);
 | 
			
		||||
 | 
			
		||||
    ready_queue.remove(priority, thread);
 | 
			
		||||
    ready_queue.push_back(priority, thread);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
 | 
			
		||||
    std::lock_guard<std::mutex> lock(scheduler_mutex);
 | 
			
		||||
 | 
			
		||||
@ -179,4 +189,12 @@ void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
 | 
			
		||||
        ready_queue.prepare(priority);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Thread* Scheduler::GetNextSuggestedThread(u32 core) {
 | 
			
		||||
    std::lock_guard<std::mutex> lock(scheduler_mutex);
 | 
			
		||||
 | 
			
		||||
    const auto mask = 1 << core;
 | 
			
		||||
    return ready_queue.get_first_filter(
 | 
			
		||||
        [&mask](Thread* thread) { return (thread->GetAffinityMask() & mask) != 0; });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
 | 
			
		||||
@ -48,9 +48,15 @@ public:
 | 
			
		||||
    /// Unschedules a thread that was already scheduled
 | 
			
		||||
    void UnscheduleThread(Thread* thread, u32 priority);
 | 
			
		||||
 | 
			
		||||
    /// Moves a thread to the back of the current priority queue
 | 
			
		||||
    void RescheduleThread(Thread* thread, u32 priority);
 | 
			
		||||
 | 
			
		||||
    /// Sets the priority of a thread in the scheduler
 | 
			
		||||
    void SetThreadPriority(Thread* thread, u32 priority);
 | 
			
		||||
 | 
			
		||||
    /// Gets the next suggested thread for load balancing
 | 
			
		||||
    Thread* GetNextSuggestedThread(u32 core);
 | 
			
		||||
 | 
			
		||||
    /// Returns a list of all threads managed by the scheduler
 | 
			
		||||
    const std::vector<SharedPtr<Thread>>& GetThreadList() const {
 | 
			
		||||
        return thread_list;
 | 
			
		||||
 | 
			
		||||
@ -962,16 +962,39 @@ static void SleepThread(s64 nanoseconds) {
 | 
			
		||||
 | 
			
		||||
    // Don't attempt to yield execution if there are no available threads to run,
 | 
			
		||||
    // this way we avoid a useless reschedule to the idle thread.
 | 
			
		||||
    if (nanoseconds == 0 && !Core::System::GetInstance().CurrentScheduler().HaveReadyThreads())
 | 
			
		||||
    if (!Core::System::GetInstance().CurrentScheduler().HaveReadyThreads())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (nanoseconds <= 0) {
 | 
			
		||||
        switch (nanoseconds) {
 | 
			
		||||
        case 0:
 | 
			
		||||
            GetCurrentThread()->YieldNormal();
 | 
			
		||||
            break;
 | 
			
		||||
        case -1:
 | 
			
		||||
            GetCurrentThread()->YieldWithLoadBalancing();
 | 
			
		||||
            break;
 | 
			
		||||
        case -2:
 | 
			
		||||
            GetCurrentThread()->YieldAndWaitForLoadBalancing();
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            UNREACHABLE_MSG(
 | 
			
		||||
                "Unimplemented sleep yield type '{:016X}'! Falling back to forced reschedule...",
 | 
			
		||||
                nanoseconds);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        nanoseconds = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Sleep current thread and check for next thread to schedule
 | 
			
		||||
    WaitCurrentThread_Sleep();
 | 
			
		||||
 | 
			
		||||
    // Create an event to wake the thread up after the specified nanosecond delay has passed
 | 
			
		||||
    GetCurrentThread()->WakeAfterDelay(nanoseconds);
 | 
			
		||||
 | 
			
		||||
    Core::System::GetInstance().PrepareReschedule();
 | 
			
		||||
    Core::System::GetInstance().CpuCore(0).PrepareReschedule();
 | 
			
		||||
    Core::System::GetInstance().CpuCore(1).PrepareReschedule();
 | 
			
		||||
    Core::System::GetInstance().CpuCore(2).PrepareReschedule();
 | 
			
		||||
    Core::System::GetInstance().CpuCore(3).PrepareReschedule();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Wait process wide key atomic
 | 
			
		||||
 | 
			
		||||
@ -388,6 +388,66 @@ bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, SharedPtr<Thread> t
 | 
			
		||||
    return wakeup_callback(reason, std::move(thread), std::move(object), index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Thread::YieldNormal() {
 | 
			
		||||
    // Avoid yielding if the thread isn't even running.
 | 
			
		||||
    if (status != ThreadStatus::Running) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (nominal_priority < THREADPRIO_COUNT) {
 | 
			
		||||
        scheduler->RescheduleThread(this, nominal_priority);
 | 
			
		||||
        scheduler->Reschedule();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Thread::YieldWithLoadBalancing() {
 | 
			
		||||
    auto priority = nominal_priority;
 | 
			
		||||
    auto core = processor_id;
 | 
			
		||||
 | 
			
		||||
    // Avoid yielding if the thread isn't even running.
 | 
			
		||||
    if (status != ThreadStatus::Running) {
 | 
			
		||||
        Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SharedPtr<Thread> next;
 | 
			
		||||
    const auto& threads = scheduler->GetThreadList();
 | 
			
		||||
 | 
			
		||||
    if (priority < THREADPRIO_COUNT) {
 | 
			
		||||
        // Reschedule thread to end of queue.
 | 
			
		||||
        scheduler->RescheduleThread(this, priority);
 | 
			
		||||
 | 
			
		||||
        const auto iter = std::find_if(threads.begin(), threads.end(),
 | 
			
		||||
                                       [&priority](const SharedPtr<Thread>& thread) {
 | 
			
		||||
                                           return thread->GetNominalPriority() == priority;
 | 
			
		||||
                                       });
 | 
			
		||||
 | 
			
		||||
        if (iter != threads.end())
 | 
			
		||||
            next = iter->get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Thread* suggested_thread = nullptr;
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 4; ++i) {
 | 
			
		||||
        if (i == core)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        const auto res =
 | 
			
		||||
            Core::System::GetInstance().CpuCore(i).Scheduler().GetNextSuggestedThread(core);
 | 
			
		||||
        if (res != nullptr) {
 | 
			
		||||
            suggested_thread = res;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (suggested_thread != nullptr)
 | 
			
		||||
        suggested_thread->ChangeCore(core, suggested_thread->GetAffinityMask());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Thread::YieldAndWaitForLoadBalancing() {
 | 
			
		||||
    UNIMPLEMENTED_MSG("Wait for load balancing thread yield type is not implemented!");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,7 @@ enum ThreadPriority : u32 {
 | 
			
		||||
    THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps
 | 
			
		||||
    THREADPRIO_DEFAULT = 44,      ///< Default thread priority for userland apps
 | 
			
		||||
    THREADPRIO_LOWEST = 63,       ///< Lowest thread priority
 | 
			
		||||
    THREADPRIO_COUNT = 64,        ///< Total number of possible thread priorities.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ThreadProcessorId : s32 {
 | 
			
		||||
@ -370,6 +371,10 @@ public:
 | 
			
		||||
        return affinity_mask;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void YieldNormal();
 | 
			
		||||
    void YieldWithLoadBalancing();
 | 
			
		||||
    void YieldAndWaitForLoadBalancing();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    explicit Thread(KernelCore& kernel);
 | 
			
		||||
    ~Thread() override;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user