Browse Source

Scheduler: Release old thread fiber before trying to switch to the next thread fiber.

nce_cpp
Fernando Sahmkow 6 years ago
parent
commit
8c30c20863
  1. 35
      src/core/hle/kernel/scheduler.cpp
  2. 9
      src/core/hle/kernel/scheduler.h

35
src/core/hle/kernel/scheduler.cpp

@ -53,7 +53,8 @@ u32 GlobalScheduler::SelectThreads() {
} }
sched.selected_thread_set = SharedFrom(thread); sched.selected_thread_set = SharedFrom(thread);
} }
const bool reschedule_pending = sched.selected_thread_set != sched.current_thread;
const bool reschedule_pending =
sched.is_context_switch_pending || (sched.selected_thread_set != sched.current_thread);
sched.is_context_switch_pending = reschedule_pending; sched.is_context_switch_pending = reschedule_pending;
std::atomic_thread_fence(std::memory_order_seq_cst); std::atomic_thread_fence(std::memory_order_seq_cst);
sched.guard.unlock(); sched.guard.unlock();
@ -552,7 +553,9 @@ void GlobalScheduler::Unlock() {
} }
Scheduler::Scheduler(Core::System& system, std::size_t core_id) Scheduler::Scheduler(Core::System& system, std::size_t core_id)
: system{system}, core_id{core_id} {}
: system(system), core_id(core_id) {
switch_fiber = std::make_shared<Common::Fiber>(std::function<void(void*)>(OnSwitch), this);
}
Scheduler::~Scheduler() = default; Scheduler::~Scheduler() = default;
@ -636,8 +639,9 @@ void Scheduler::SwitchContext() {
current_thread = selected_thread; current_thread = selected_thread;
is_context_switch_pending = false; is_context_switch_pending = false;
guard.unlock();
if (new_thread == previous_thread) { if (new_thread == previous_thread) {
guard.unlock();
return; return;
} }
@ -669,18 +673,29 @@ void Scheduler::SwitchContext() {
} else { } else {
old_context = idle_thread->GetHostContext(); old_context = idle_thread->GetHostContext();
} }
guard.unlock();
Common::Fiber::YieldTo(old_context, switch_fiber);
/// When a thread wakes up, the scheduler may have changed to other in another core.
auto& next_scheduler = system.Kernel().CurrentScheduler();
next_scheduler.SwitchContextStep2();
}
void Scheduler::OnSwitch(void* this_scheduler) {
Scheduler* sched = static_cast<Scheduler*>(this_scheduler);
sched->SwitchToCurrent();
}
void Scheduler::SwitchToCurrent() {
while (true) {
std::shared_ptr<Common::Fiber> next_context; std::shared_ptr<Common::Fiber> next_context;
if (new_thread != nullptr) {
next_context = new_thread->GetHostContext();
if (current_thread != nullptr) {
next_context = current_thread->GetHostContext();
} else { } else {
next_context = idle_thread->GetHostContext(); next_context = idle_thread->GetHostContext();
} }
Common::Fiber::YieldTo(old_context, next_context);
/// When a thread wakes up, the scheduler may have changed to other in another core.
auto& next_scheduler = system.Kernel().CurrentScheduler();
next_scheduler.SwitchContextStep2();
Common::Fiber::YieldTo(switch_fiber, next_context);
}
} }
void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {

9
src/core/hle/kernel/scheduler.h

@ -15,6 +15,10 @@
#include "core/hardware_properties.h" #include "core/hardware_properties.h"
#include "core/hle/kernel/thread.h" #include "core/hle/kernel/thread.h"
namespace Common {
class Fiber;
}
namespace Core { namespace Core {
class ARM_Interface; class ARM_Interface;
class System; class System;
@ -247,12 +251,17 @@ private:
*/ */
void UpdateLastContextSwitchTime(Thread* thread, Process* process); void UpdateLastContextSwitchTime(Thread* thread, Process* process);
static void OnSwitch(void* this_scheduler);
void SwitchToCurrent();
std::shared_ptr<Thread> current_thread = nullptr; std::shared_ptr<Thread> current_thread = nullptr;
std::shared_ptr<Thread> selected_thread = nullptr; std::shared_ptr<Thread> selected_thread = nullptr;
std::shared_ptr<Thread> current_thread_prev = nullptr; std::shared_ptr<Thread> current_thread_prev = nullptr;
std::shared_ptr<Thread> selected_thread_set = nullptr; std::shared_ptr<Thread> selected_thread_set = nullptr;
std::shared_ptr<Thread> idle_thread = nullptr; std::shared_ptr<Thread> idle_thread = nullptr;
std::shared_ptr<Common::Fiber> switch_fiber = nullptr;
Core::System& system; Core::System& system;
u64 last_context_switch_time = 0; u64 last_context_switch_time = 0;
u64 idle_selection_count = 0; u64 idle_selection_count = 0;

Loading…
Cancel
Save