|
@@ -401,8 +401,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
|
|
|
|
|
|
|
|
/// Get which CPU core is executing the current thread
|
|
/// Get which CPU core is executing the current thread
|
|
|
static u32 GetCurrentProcessorNumber() {
|
|
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,
|
|
static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size,
|
|
@@ -485,22 +485,28 @@ static void ExitProcess() {
|
|
|
|
|
|
|
|
Core::CurrentProcess()->status = ProcessStatus::Exited;
|
|
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
|
|
// Kill the current thread
|
|
|
GetCurrentThread()->Stop();
|
|
GetCurrentThread()->Stop();
|
|
@@ -530,14 +536,9 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
|
|
|
|
|
|
|
|
switch (processor_id) {
|
|
switch (processor_id) {
|
|
|
case THREADPROCESSORID_0:
|
|
case THREADPROCESSORID_0:
|
|
|
- break;
|
|
|
|
|
case THREADPROCESSORID_1:
|
|
case THREADPROCESSORID_1:
|
|
|
case THREADPROCESSORID_2:
|
|
case THREADPROCESSORID_2:
|
|
|
case THREADPROCESSORID_3:
|
|
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;
|
|
break;
|
|
|
default:
|
|
default:
|
|
|
ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id);
|
|
ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id);
|
|
@@ -576,7 +577,7 @@ static ResultCode StartThread(Handle thread_handle) {
|
|
|
|
|
|
|
|
/// Called when a thread exits
|
|
/// Called when a thread exits
|
|
|
static void ExitThread() {
|
|
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();
|
|
ExitCurrentThread();
|
|
|
Core::System::GetInstance().PrepareReschedule();
|
|
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,
|
|
// 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().Scheduler().HaveReadyThreads())
|
|
|
|
|
|
|
+ if (nanoseconds == 0 && !Core::System::GetInstance().CurrentScheduler().HaveReadyThreads())
|
|
|
return;
|
|
return;
|
|
|
|
|
|
|
|
// Sleep current thread and check for next thread to schedule
|
|
// 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.
|
|
// 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;
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -634,53 +635,60 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
|
|
|
condition_variable_addr, target);
|
|
condition_variable_addr, target);
|
|
|
|
|
|
|
|
u32 processed = 0;
|
|
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;
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
}
|
|
@@ -718,16 +726,31 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
|
|
|
return RESULT_SUCCESS;
|
|
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;
|
|
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;
|
|
return RESULT_SUCCESS;
|
|
|
}
|
|
}
|
|
|
|
|
|