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 <array>
 | 
				
			||||||
#include <deque>
 | 
					#include <deque>
 | 
				
			||||||
 | 
					#include <functional>
 | 
				
			||||||
#include <boost/range/algorithm_ext/erase.hpp>
 | 
					#include <boost/range/algorithm_ext/erase.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Common {
 | 
					namespace Common {
 | 
				
			||||||
@ -49,6 +50,21 @@ struct ThreadQueueList {
 | 
				
			|||||||
        return T();
 | 
					        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() {
 | 
					    T pop_first() {
 | 
				
			||||||
        Queue* cur = first;
 | 
					        Queue* cur = first;
 | 
				
			||||||
        while (cur != nullptr) {
 | 
					        while (cur != nullptr) {
 | 
				
			||||||
 | 
				
			|||||||
@ -169,6 +169,16 @@ void Scheduler::UnscheduleThread(Thread* thread, u32 priority) {
 | 
				
			|||||||
    ready_queue.remove(priority, thread);
 | 
					    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) {
 | 
					void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
 | 
				
			||||||
    std::lock_guard<std::mutex> lock(scheduler_mutex);
 | 
					    std::lock_guard<std::mutex> lock(scheduler_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -179,4 +189,12 @@ void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
 | 
				
			|||||||
        ready_queue.prepare(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
 | 
					} // namespace Kernel
 | 
				
			||||||
 | 
				
			|||||||
@ -48,9 +48,15 @@ public:
 | 
				
			|||||||
    /// Unschedules a thread that was already scheduled
 | 
					    /// Unschedules a thread that was already scheduled
 | 
				
			||||||
    void UnscheduleThread(Thread* thread, u32 priority);
 | 
					    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
 | 
					    /// Sets the priority of a thread in the scheduler
 | 
				
			||||||
    void SetThreadPriority(Thread* thread, u32 priority);
 | 
					    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
 | 
					    /// Returns a list of all threads managed by the scheduler
 | 
				
			||||||
    const std::vector<SharedPtr<Thread>>& GetThreadList() const {
 | 
					    const std::vector<SharedPtr<Thread>>& GetThreadList() const {
 | 
				
			||||||
        return thread_list;
 | 
					        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,
 | 
					    // 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.
 | 
					    // 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;
 | 
					        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
 | 
					    // Sleep current thread and check for next thread to schedule
 | 
				
			||||||
    WaitCurrentThread_Sleep();
 | 
					    WaitCurrentThread_Sleep();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Create an event to wake the thread up after the specified nanosecond delay has passed
 | 
					    // Create an event to wake the thread up after the specified nanosecond delay has passed
 | 
				
			||||||
    GetCurrentThread()->WakeAfterDelay(nanoseconds);
 | 
					    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
 | 
					/// 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);
 | 
					    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_USERLAND_MAX = 24, ///< Highest thread priority for userland apps
 | 
				
			||||||
    THREADPRIO_DEFAULT = 44,      ///< Default thread priority for userland apps
 | 
					    THREADPRIO_DEFAULT = 44,      ///< Default thread priority for userland apps
 | 
				
			||||||
    THREADPRIO_LOWEST = 63,       ///< Lowest thread priority
 | 
					    THREADPRIO_LOWEST = 63,       ///< Lowest thread priority
 | 
				
			||||||
 | 
					    THREADPRIO_COUNT = 64,        ///< Total number of possible thread priorities.
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum ThreadProcessorId : s32 {
 | 
					enum ThreadProcessorId : s32 {
 | 
				
			||||||
@ -370,6 +371,10 @@ public:
 | 
				
			|||||||
        return affinity_mask;
 | 
					        return affinity_mask;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void YieldNormal();
 | 
				
			||||||
 | 
					    void YieldWithLoadBalancing();
 | 
				
			||||||
 | 
					    void YieldAndWaitForLoadBalancing();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    explicit Thread(KernelCore& kernel);
 | 
					    explicit Thread(KernelCore& kernel);
 | 
				
			||||||
    ~Thread() override;
 | 
					    ~Thread() override;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user