summaryrefslogtreecommitdiffstats
path: root/src/core/hle
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2018-05-11 18:59:23 +0200
committerGitHub <noreply@github.com>2018-05-11 18:59:23 +0200
commit1b5c02fc37206bbd33715d2dde6258c3f835581c (patch)
tree1c33c66e734ff55228e4293cd2720070cd467080 /src/core/hle
parentMerge pull request #439 from ogniK5377/GetTPCMasks (diff)
parentcore: Add several missing docstrings. (diff)
downloadyuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.tar
yuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.tar.gz
yuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.tar.bz2
yuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.tar.lz
yuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.tar.xz
yuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.tar.zst
yuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.zip
Diffstat (limited to '')
-rw-r--r--src/core/hle/kernel/scheduler.cpp15
-rw-r--r--src/core/hle/kernel/scheduler.h3
-rw-r--r--src/core/hle/kernel/svc.cpp171
-rw-r--r--src/core/hle/kernel/svc_wrap.h24
-rw-r--r--src/core/hle/kernel/thread.cpp102
-rw-r--r--src/core/hle/kernel/thread.h10
-rw-r--r--src/core/hle/kernel/vm_manager.cpp23
7 files changed, 249 insertions, 99 deletions
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index ff6a0941a..9cb9e0e5c 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -9,6 +9,8 @@
namespace Kernel {
+std::mutex Scheduler::scheduler_mutex;
+
Scheduler::Scheduler(ARM_Interface* cpu_core) : cpu_core(cpu_core) {}
Scheduler::~Scheduler() {
@@ -18,6 +20,7 @@ Scheduler::~Scheduler() {
}
bool Scheduler::HaveReadyThreads() {
+ std::lock_guard<std::mutex> lock(scheduler_mutex);
return ready_queue.get_first() != nullptr;
}
@@ -90,6 +93,8 @@ void Scheduler::SwitchContext(Thread* new_thread) {
}
void Scheduler::Reschedule() {
+ std::lock_guard<std::mutex> lock(scheduler_mutex);
+
Thread* cur = GetCurrentThread();
Thread* next = PopNextReadyThread();
@@ -105,26 +110,36 @@ void Scheduler::Reschedule() {
}
void Scheduler::AddThread(SharedPtr<Thread> thread, u32 priority) {
+ std::lock_guard<std::mutex> lock(scheduler_mutex);
+
thread_list.push_back(thread);
ready_queue.prepare(priority);
}
void Scheduler::RemoveThread(Thread* thread) {
+ std::lock_guard<std::mutex> lock(scheduler_mutex);
+
thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
thread_list.end());
}
void Scheduler::ScheduleThread(Thread* thread, u32 priority) {
+ std::lock_guard<std::mutex> lock(scheduler_mutex);
+
ASSERT(thread->status == THREADSTATUS_READY);
ready_queue.push_back(priority, thread);
}
void Scheduler::UnscheduleThread(Thread* thread, u32 priority) {
+ std::lock_guard<std::mutex> lock(scheduler_mutex);
+
ASSERT(thread->status == THREADSTATUS_READY);
ready_queue.remove(priority, thread);
}
void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
+ std::lock_guard<std::mutex> lock(scheduler_mutex);
+
// If thread was ready, adjust queues
if (thread->status == THREADSTATUS_READY)
ready_queue.move(thread, thread->current_priority, priority);
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 27d0247d6..a3b5fb8ca 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -4,6 +4,7 @@
#pragma once
+#include <mutex>
#include <vector>
#include "common/common_types.h"
#include "common/thread_queue_list.h"
@@ -68,6 +69,8 @@ private:
SharedPtr<Thread> current_thread = nullptr;
ARM_Interface* cpu_core;
+
+ static std::mutex scheduler_mutex;
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 72b5c05f2..1ae530c90 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -401,8 +401,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
/// Get which CPU core is executing the current thread
static u32 GetCurrentProcessorNumber() {
- NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, defaulting to processor 0");
- return 0;
+ NGLOG_TRACE(Kernel_SVC, "called");
+ return GetCurrentThread()->processor_id;
}
static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size,
@@ -485,22 +485,28 @@ static void ExitProcess() {
Core::CurrentProcess()->status = ProcessStatus::Exited;
- // Stop all the process threads that are currently waiting for objects.
- auto& thread_list = Core::System::GetInstance().Scheduler().GetThreadList();
- for (auto& thread : thread_list) {
- if (thread->owner_process != Core::CurrentProcess())
- continue;
+ auto stop_threads = [](const std::vector<SharedPtr<Thread>>& thread_list) {
+ for (auto& thread : thread_list) {
+ if (thread->owner_process != Core::CurrentProcess())
+ continue;
- if (thread == GetCurrentThread())
- continue;
+ if (thread == GetCurrentThread())
+ continue;
- // TODO(Subv): When are the other running/ready threads terminated?
- ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
- thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
- "Exiting processes with non-waiting threads is currently unimplemented");
+ // TODO(Subv): When are the other running/ready threads terminated?
+ ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
+ thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
+ "Exiting processes with non-waiting threads is currently unimplemented");
- thread->Stop();
- }
+ thread->Stop();
+ }
+ };
+
+ auto& system = Core::System::GetInstance();
+ stop_threads(system.Scheduler(0)->GetThreadList());
+ stop_threads(system.Scheduler(1)->GetThreadList());
+ stop_threads(system.Scheduler(2)->GetThreadList());
+ stop_threads(system.Scheduler(3)->GetThreadList());
// Kill the current thread
GetCurrentThread()->Stop();
@@ -530,14 +536,9 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
switch (processor_id) {
case THREADPROCESSORID_0:
- break;
case THREADPROCESSORID_1:
case THREADPROCESSORID_2:
case THREADPROCESSORID_3:
- // TODO(bunnei): Implement support for other processor IDs
- NGLOG_ERROR(Kernel_SVC,
- "Newly created thread must run in another thread ({}), unimplemented.",
- processor_id);
break;
default:
ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id);
@@ -576,7 +577,7 @@ static ResultCode StartThread(Handle thread_handle) {
/// Called when a thread exits
static void ExitThread() {
- NGLOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CPU().GetPC());
+ NGLOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CurrentArmInterface().GetPC());
ExitCurrentThread();
Core::System::GetInstance().PrepareReschedule();
@@ -588,7 +589,7 @@ 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().Scheduler().HaveReadyThreads())
+ if (nanoseconds == 0 && !Core::System::GetInstance().CurrentScheduler().HaveReadyThreads())
return;
// Sleep current thread and check for next thread to schedule
@@ -624,7 +625,7 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
// Note: Deliberately don't attempt to inherit the lock owner's priority.
- Core::System::GetInstance().PrepareReschedule();
+ Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule();
return RESULT_SUCCESS;
}
@@ -634,53 +635,60 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
condition_variable_addr, target);
u32 processed = 0;
- auto& thread_list = Core::System::GetInstance().Scheduler().GetThreadList();
-
- for (auto& thread : thread_list) {
- if (thread->condvar_wait_address != condition_variable_addr)
- continue;
-
- // Only process up to 'target' threads, unless 'target' is -1, in which case process
- // them all.
- if (target != -1 && processed >= target)
- break;
-
- // If the mutex is not yet acquired, acquire it.
- u32 mutex_val = Memory::Read32(thread->mutex_wait_address);
-
- if (mutex_val == 0) {
- // We were able to acquire the mutex, resume this thread.
- Memory::Write32(thread->mutex_wait_address, thread->wait_handle);
- ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
- thread->ResumeFromWait();
-
- auto lock_owner = thread->lock_owner;
- if (lock_owner)
- lock_owner->RemoveMutexWaiter(thread);
-
- thread->lock_owner = nullptr;
- thread->mutex_wait_address = 0;
- thread->condvar_wait_address = 0;
- thread->wait_handle = 0;
- } else {
- // Couldn't acquire the mutex, block the thread.
- Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
- auto owner = g_handle_table.Get<Thread>(owner_handle);
- ASSERT(owner);
- ASSERT(thread->status != THREADSTATUS_RUNNING);
- thread->status = THREADSTATUS_WAIT_MUTEX;
- thread->wakeup_callback = nullptr;
- // Signal that the mutex now has a waiting thread.
- Memory::Write32(thread->mutex_wait_address, mutex_val | Mutex::MutexHasWaitersFlag);
-
- owner->AddMutexWaiter(thread);
-
- Core::System::GetInstance().PrepareReschedule();
+ auto signal_process_wide_key = [&](size_t core_index) {
+ const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
+ for (auto& thread : scheduler->GetThreadList()) {
+ if (thread->condvar_wait_address != condition_variable_addr)
+ continue;
+
+ // Only process up to 'target' threads, unless 'target' is -1, in which case process
+ // them all.
+ if (target != -1 && processed >= target)
+ break;
+
+ // If the mutex is not yet acquired, acquire it.
+ u32 mutex_val = Memory::Read32(thread->mutex_wait_address);
+
+ if (mutex_val == 0) {
+ // We were able to acquire the mutex, resume this thread.
+ Memory::Write32(thread->mutex_wait_address, thread->wait_handle);
+ ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
+ thread->ResumeFromWait();
+
+ auto lock_owner = thread->lock_owner;
+ if (lock_owner)
+ lock_owner->RemoveMutexWaiter(thread);
+
+ thread->lock_owner = nullptr;
+ thread->mutex_wait_address = 0;
+ thread->condvar_wait_address = 0;
+ thread->wait_handle = 0;
+ } else {
+ // Couldn't acquire the mutex, block the thread.
+ Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
+ auto owner = g_handle_table.Get<Thread>(owner_handle);
+ ASSERT(owner);
+ ASSERT(thread->status != THREADSTATUS_RUNNING);
+ thread->status = THREADSTATUS_WAIT_MUTEX;
+ thread->wakeup_callback = nullptr;
+
+ // Signal that the mutex now has a waiting thread.
+ Memory::Write32(thread->mutex_wait_address, mutex_val | Mutex::MutexHasWaitersFlag);
+
+ owner->AddMutexWaiter(thread);
+
+ Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
+ }
+
+ ++processed;
}
+ };
- ++processed;
- }
+ signal_process_wide_key(0);
+ signal_process_wide_key(1);
+ signal_process_wide_key(2);
+ signal_process_wide_key(3);
return RESULT_SUCCESS;
}
@@ -718,16 +726,31 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
return RESULT_SUCCESS;
}
-static ResultCode GetThreadCoreMask(Handle handle, u32* mask, u64* unknown) {
- NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}", handle);
- *mask = 0x0;
- *unknown = 0xf;
+static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) {
+ NGLOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
+
+ const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
+ if (!thread) {
+ return ERR_INVALID_HANDLE;
+ }
+
+ *core = thread->ideal_core;
+ *mask = thread->affinity_mask;
+
return RESULT_SUCCESS;
}
-static ResultCode SetThreadCoreMask(Handle handle, u32 mask, u64 unknown) {
- NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, mask=0x{:08X}, unknown=0x{:X}",
- handle, mask, unknown);
+static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
+ NGLOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:08X}, core=0x{:X}", thread_handle,
+ mask, core);
+
+ const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
+ if (!thread) {
+ return ERR_INVALID_HANDLE;
+ }
+
+ thread->ChangeCore(core, mask);
+
return RESULT_SUCCESS;
}
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index c86ad3e04..40aa88cc1 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -13,14 +13,14 @@
namespace Kernel {
-#define PARAM(n) Core::CPU().GetReg(n)
+#define PARAM(n) Core::CurrentArmInterface().GetReg(n)
/**
* HLE a function return from the current ARM userland process
* @param res Result to return
*/
static inline void FuncReturn(u64 res) {
- Core::CPU().SetReg(0, res);
+ Core::CurrentArmInterface().SetReg(0, res);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -45,7 +45,7 @@ template <ResultCode func(u32*, u32)>
void SvcWrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, (u32)PARAM(1)).raw;
- Core::CPU().SetReg(1, param_1);
+ Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -53,7 +53,7 @@ template <ResultCode func(u32*, u64)>
void SvcWrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1)).raw;
- Core::CPU().SetReg(1, param_1);
+ Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -66,7 +66,7 @@ template <ResultCode func(u64*, u64)>
void SvcWrap() {
u64 param_1 = 0;
u32 retval = func(&param_1, PARAM(1)).raw;
- Core::CPU().SetReg(1, param_1);
+ Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -85,8 +85,8 @@ void SvcWrap() {
u32 param_1 = 0;
u64 param_2 = 0;
ResultCode retval = func((u32)(PARAM(2) & 0xFFFFFFFF), &param_1, &param_2);
- Core::CPU().SetReg(1, param_1);
- Core::CPU().SetReg(2, param_2);
+ Core::CurrentArmInterface().SetReg(1, param_1);
+ Core::CurrentArmInterface().SetReg(2, param_2);
FuncReturn(retval.raw);
}
@@ -120,7 +120,7 @@ template <ResultCode func(u32*, u64, u64, s64)>
void SvcWrap() {
u32 param_1 = 0;
ResultCode retval = func(&param_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (s64)PARAM(3));
- Core::CPU().SetReg(1, param_1);
+ Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval.raw);
}
@@ -133,7 +133,7 @@ template <ResultCode func(u64*, u64, u64, u64)>
void SvcWrap() {
u64 param_1 = 0;
u32 retval = func(&param_1, PARAM(1), PARAM(2), PARAM(3)).raw;
- Core::CPU().SetReg(1, param_1);
+ Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -143,7 +143,7 @@ void SvcWrap() {
u32 retval =
func(&param_1, PARAM(1), PARAM(2), PARAM(3), (u32)PARAM(4), (s32)(PARAM(5) & 0xFFFFFFFF))
.raw;
- Core::CPU().SetReg(1, param_1);
+ Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -166,7 +166,7 @@ template <ResultCode func(u32*, u64, u64, u32)>
void SvcWrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1), PARAM(2), (u32)(PARAM(3) & 0xFFFFFFFF)).raw;
- Core::CPU().SetReg(1, param_1);
+ Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -175,7 +175,7 @@ void SvcWrap() {
u32 param_1 = 0;
u32 retval =
func(&param_1, PARAM(1), (u32)(PARAM(2) & 0xFFFFFFFF), (u32)(PARAM(3) & 0xFFFFFFFF)).raw;
- Core::CPU().SetReg(1, param_1);
+ Core::CurrentArmInterface().SetReg(1, param_1);
FuncReturn(retval);
}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 1bd5d9ebf..46fcdefb8 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -64,7 +64,7 @@ void Thread::Stop() {
// Clean up thread from ready queue
// This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
if (status == THREADSTATUS_READY) {
- Core::System::GetInstance().Scheduler().UnscheduleThread(this, current_priority);
+ scheduler->UnscheduleThread(this, current_priority);
}
status = THREADSTATUS_DEAD;
@@ -92,7 +92,7 @@ void WaitCurrentThread_Sleep() {
void ExitCurrentThread() {
Thread* thread = GetCurrentThread();
thread->Stop();
- Core::System::GetInstance().Scheduler().RemoveThread(thread);
+ Core::System::GetInstance().CurrentScheduler().RemoveThread(thread);
}
/**
@@ -154,6 +154,18 @@ void Thread::CancelWakeupTimer() {
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
}
+static boost::optional<s32> GetNextProcessorId(u64 mask) {
+ for (s32 index = 0; index < Core::NUM_CPU_CORES; ++index) {
+ if (mask & (1ULL << index)) {
+ if (!Core::System().GetInstance().Scheduler(index)->GetCurrentThread()) {
+ // Core is enabled and not running any threads, use this one
+ return index;
+ }
+ }
+ }
+ return {};
+}
+
void Thread::ResumeFromWait() {
ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects");
@@ -188,8 +200,37 @@ void Thread::ResumeFromWait() {
wakeup_callback = nullptr;
status = THREADSTATUS_READY;
- Core::System::GetInstance().Scheduler().ScheduleThread(this, current_priority);
- Core::System::GetInstance().PrepareReschedule();
+
+ boost::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask);
+ if (!new_processor_id) {
+ new_processor_id = processor_id;
+ }
+ if (ideal_core != -1 &&
+ Core::System().GetInstance().Scheduler(ideal_core)->GetCurrentThread() == nullptr) {
+ new_processor_id = ideal_core;
+ }
+
+ ASSERT(*new_processor_id < 4);
+
+ // Add thread to new core's scheduler
+ auto& next_scheduler = Core::System().GetInstance().Scheduler(*new_processor_id);
+
+ if (*new_processor_id != processor_id) {
+ // Remove thread from previous core's scheduler
+ scheduler->RemoveThread(this);
+ next_scheduler->AddThread(this, current_priority);
+ }
+
+ processor_id = *new_processor_id;
+
+ // If the thread was ready, unschedule from the previous core and schedule on the new core
+ scheduler->UnscheduleThread(this, current_priority);
+ next_scheduler->ScheduleThread(this, current_priority);
+
+ // Change thread's scheduler
+ scheduler = next_scheduler;
+
+ Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
}
/**
@@ -259,8 +300,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
SharedPtr<Thread> thread(new Thread);
- Core::System::GetInstance().Scheduler().AddThread(thread, priority);
-
thread->thread_id = NewThreadId();
thread->status = THREADSTATUS_DORMANT;
thread->entry_point = entry_point;
@@ -268,6 +307,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->nominal_priority = thread->current_priority = priority;
thread->last_running_ticks = CoreTiming::GetTicks();
thread->processor_id = processor_id;
+ thread->ideal_core = processor_id;
+ thread->affinity_mask = 1ULL << processor_id;
thread->wait_objects.clear();
thread->mutex_wait_address = 0;
thread->condvar_wait_address = 0;
@@ -275,6 +316,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->name = std::move(name);
thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap();
thread->owner_process = owner_process;
+ thread->scheduler = Core::System().GetInstance().Scheduler(processor_id);
+ thread->scheduler->AddThread(thread, priority);
// Find the next available TLS index, and mark it as used
auto& tls_slots = owner_process->tls_slots;
@@ -337,7 +380,7 @@ void Thread::SetPriority(u32 priority) {
}
void Thread::BoostPriority(u32 priority) {
- Core::System::GetInstance().Scheduler().SetThreadPriority(this, priority);
+ scheduler->SetThreadPriority(this, priority);
current_priority = priority;
}
@@ -406,7 +449,7 @@ void Thread::UpdatePriority() {
if (new_priority == current_priority)
return;
- Core::System::GetInstance().Scheduler().SetThreadPriority(this, new_priority);
+ scheduler->SetThreadPriority(this, new_priority);
current_priority = new_priority;
@@ -415,13 +458,54 @@ void Thread::UpdatePriority() {
lock_owner->UpdatePriority();
}
+void Thread::ChangeCore(u32 core, u64 mask) {
+ ideal_core = core;
+ mask = mask;
+
+ if (status != THREADSTATUS_READY) {
+ return;
+ }
+
+ boost::optional<s32> new_processor_id{GetNextProcessorId(mask)};
+
+ if (!new_processor_id) {
+ new_processor_id = processor_id;
+ }
+ if (ideal_core != -1 &&
+ Core::System().GetInstance().Scheduler(ideal_core)->GetCurrentThread() == nullptr) {
+ new_processor_id = ideal_core;
+ }
+
+ ASSERT(new_processor_id < 4);
+
+ // Add thread to new core's scheduler
+ auto& next_scheduler = Core::System().GetInstance().Scheduler(*new_processor_id);
+
+ if (*new_processor_id != processor_id) {
+ // Remove thread from previous core's scheduler
+ scheduler->RemoveThread(this);
+ next_scheduler->AddThread(this, current_priority);
+ }
+
+ processor_id = *new_processor_id;
+
+ // If the thread was ready, unschedule from the previous core and schedule on the new core
+ scheduler->UnscheduleThread(this, current_priority);
+ next_scheduler->ScheduleThread(this, current_priority);
+
+ // Change thread's scheduler
+ scheduler = next_scheduler;
+
+ Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Gets the current thread
*/
Thread* GetCurrentThread() {
- return Core::System::GetInstance().Scheduler().GetCurrentThread();
+ return Core::System::GetInstance().CurrentScheduler().GetCurrentThread();
}
void ThreadingInit() {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index e0a3c0934..1d2da6d50 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -4,6 +4,7 @@
#pragma once
+#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
@@ -56,6 +57,7 @@ enum class ThreadWakeupReason {
namespace Kernel {
class Process;
+class Scheduler;
class Thread final : public WaitObject {
public:
@@ -118,6 +120,9 @@ public:
/// Recalculates the current priority taking into account priority inheritance.
void UpdatePriority();
+ /// Changes the core that the thread is running or scheduled to run on.
+ void ChangeCore(u32 core, u64 mask);
+
/**
* Gets the thread's thread ID
* @return The thread's ID
@@ -240,6 +245,11 @@ public:
// available. In case of a timeout, the object will be nullptr.
std::function<WakeupCallback> wakeup_callback;
+ std::shared_ptr<Scheduler> scheduler;
+
+ u32 ideal_core{0xFFFFFFFF};
+ u64 affinity_mask{0x1};
+
private:
Thread();
~Thread() override;
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 2f0044c11..676e5b282 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -104,8 +104,15 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
VirtualMemoryArea& final_vma = vma_handle->second;
ASSERT(final_vma.size == size);
- Core::CPU().MapBackingMemory(target, size, block->data() + offset,
- VMAPermission::ReadWriteExecute);
+ auto& system = Core::System::GetInstance();
+ system.ArmInterface(0).MapBackingMemory(target, size, block->data() + offset,
+ VMAPermission::ReadWriteExecute);
+ system.ArmInterface(1).MapBackingMemory(target, size, block->data() + offset,
+ VMAPermission::ReadWriteExecute);
+ system.ArmInterface(2).MapBackingMemory(target, size, block->data() + offset,
+ VMAPermission::ReadWriteExecute);
+ system.ArmInterface(3).MapBackingMemory(target, size, block->data() + offset,
+ VMAPermission::ReadWriteExecute);
final_vma.type = VMAType::AllocatedMemoryBlock;
final_vma.permissions = VMAPermission::ReadWrite;
@@ -126,7 +133,11 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me
VirtualMemoryArea& final_vma = vma_handle->second;
ASSERT(final_vma.size == size);
- Core::CPU().MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
+ auto& system = Core::System::GetInstance();
+ system.ArmInterface(0).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
+ system.ArmInterface(1).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
+ system.ArmInterface(2).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
+ system.ArmInterface(3).MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
final_vma.type = VMAType::BackingMemory;
final_vma.permissions = VMAPermission::ReadWrite;
@@ -184,7 +195,11 @@ ResultCode VMManager::UnmapRange(VAddr target, u64 size) {
ASSERT(FindVMA(target)->second.size >= size);
- Core::CPU().UnmapMemory(target, size);
+ auto& system = Core::System::GetInstance();
+ system.ArmInterface(0).UnmapMemory(target, size);
+ system.ArmInterface(1).UnmapMemory(target, size);
+ system.ArmInterface(2).UnmapMemory(target, size);
+ system.ArmInterface(3).UnmapMemory(target, size);
return RESULT_SUCCESS;
}