kernel: implement KProcess suspension
This commit is contained in:
parent
c6e7ca562a
commit
888f499188
12 changed files with 204 additions and 217 deletions
|
@ -275,11 +275,15 @@ void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr a
|
|||
shmem->Close();
|
||||
}
|
||||
|
||||
void KProcess::RegisterThread(const KThread* thread) {
|
||||
void KProcess::RegisterThread(KThread* thread) {
|
||||
KScopedLightLock lk{list_lock};
|
||||
|
||||
thread_list.push_back(thread);
|
||||
}
|
||||
|
||||
void KProcess::UnregisterThread(const KThread* thread) {
|
||||
void KProcess::UnregisterThread(KThread* thread) {
|
||||
KScopedLightLock lk{list_lock};
|
||||
|
||||
thread_list.remove(thread);
|
||||
}
|
||||
|
||||
|
@ -297,6 +301,50 @@ ResultCode KProcess::Reset() {
|
|||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KProcess::SetActivity(ProcessActivity activity) {
|
||||
// Lock ourselves and the scheduler.
|
||||
KScopedLightLock lk{state_lock};
|
||||
KScopedLightLock list_lk{list_lock};
|
||||
KScopedSchedulerLock sl{kernel};
|
||||
|
||||
// Validate our state.
|
||||
R_UNLESS(status != ProcessStatus::Exiting, ResultInvalidState);
|
||||
R_UNLESS(status != ProcessStatus::Exited, ResultInvalidState);
|
||||
|
||||
// Either pause or resume.
|
||||
if (activity == ProcessActivity::Paused) {
|
||||
// Verify that we're not suspended.
|
||||
if (is_suspended) {
|
||||
return ResultInvalidState;
|
||||
}
|
||||
|
||||
// Suspend all threads.
|
||||
for (auto* thread : GetThreadList()) {
|
||||
thread->RequestSuspend(SuspendType::Process);
|
||||
}
|
||||
|
||||
// Set ourselves as suspended.
|
||||
SetSuspended(true);
|
||||
} else {
|
||||
ASSERT(activity == ProcessActivity::Runnable);
|
||||
|
||||
// Verify that we're suspended.
|
||||
if (!is_suspended) {
|
||||
return ResultInvalidState;
|
||||
}
|
||||
|
||||
// Resume all threads.
|
||||
for (auto* thread : GetThreadList()) {
|
||||
thread->Resume(SuspendType::Process);
|
||||
}
|
||||
|
||||
// Set ourselves as resumed.
|
||||
SetSuspended(false);
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
|
||||
std::size_t code_size) {
|
||||
program_id = metadata.GetTitleID();
|
||||
|
@ -556,9 +604,10 @@ bool KProcess::IsSignaled() const {
|
|||
}
|
||||
|
||||
KProcess::KProcess(KernelCore& kernel_)
|
||||
: KAutoObjectWithSlabHeapAndContainer{kernel_},
|
||||
page_table{std::make_unique<KPageTable>(kernel_.System())}, handle_table{kernel_},
|
||||
address_arbiter{kernel_.System()}, condition_var{kernel_.System()}, state_lock{kernel_} {}
|
||||
: KAutoObjectWithSlabHeapAndContainer{kernel_}, page_table{std::make_unique<KPageTable>(
|
||||
kernel_.System())},
|
||||
handle_table{kernel_}, address_arbiter{kernel_.System()}, condition_var{kernel_.System()},
|
||||
state_lock{kernel_}, list_lock{kernel_} {}
|
||||
|
||||
KProcess::~KProcess() = default;
|
||||
|
||||
|
|
|
@ -63,6 +63,11 @@ enum class ProcessStatus {
|
|||
DebugBreak,
|
||||
};
|
||||
|
||||
enum class ProcessActivity : u32 {
|
||||
Runnable,
|
||||
Paused,
|
||||
};
|
||||
|
||||
class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> {
|
||||
KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
|
||||
|
||||
|
@ -282,17 +287,17 @@ public:
|
|||
u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const;
|
||||
|
||||
/// Gets the list of all threads created with this process as their owner.
|
||||
const std::list<const KThread*>& GetThreadList() const {
|
||||
std::list<KThread*>& GetThreadList() {
|
||||
return thread_list;
|
||||
}
|
||||
|
||||
/// Registers a thread as being created under this process,
|
||||
/// adding it to this process' thread list.
|
||||
void RegisterThread(const KThread* thread);
|
||||
void RegisterThread(KThread* thread);
|
||||
|
||||
/// Unregisters a thread from this process, removing it
|
||||
/// from this process' thread list.
|
||||
void UnregisterThread(const KThread* thread);
|
||||
void UnregisterThread(KThread* thread);
|
||||
|
||||
/// Clears the signaled state of the process if and only if it's signaled.
|
||||
///
|
||||
|
@ -347,6 +352,8 @@ public:
|
|||
|
||||
void DoWorkerTaskImpl();
|
||||
|
||||
ResultCode SetActivity(ProcessActivity activity);
|
||||
|
||||
void PinCurrentThread(s32 core_id);
|
||||
void UnpinCurrentThread(s32 core_id);
|
||||
void UnpinThread(KThread* thread);
|
||||
|
@ -442,7 +449,7 @@ private:
|
|||
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{};
|
||||
|
||||
/// List of threads that are running with this process as their owner.
|
||||
std::list<const KThread*> thread_list;
|
||||
std::list<KThread*> thread_list;
|
||||
|
||||
/// List of shared memory that are running with this process as their owner.
|
||||
std::list<KSharedMemoryInfo*> shared_memory_list;
|
||||
|
@ -475,6 +482,7 @@ private:
|
|||
KThread* exception_thread{};
|
||||
|
||||
KLightLock state_lock;
|
||||
KLightLock list_lock;
|
||||
|
||||
using TLPTree =
|
||||
Common::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>;
|
||||
|
|
|
@ -267,15 +267,15 @@ ResultCode KThread::InitializeDummyThread(KThread* thread) {
|
|||
ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
|
||||
return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
|
||||
Core::CpuManager::GetIdleThreadStartFunc(),
|
||||
system.GetCpuManager().GetStartFuncParamater());
|
||||
system.GetCpuManager().GetStartFuncParameter());
|
||||
}
|
||||
|
||||
ResultCode KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
|
||||
KThreadFunction func, uintptr_t arg,
|
||||
s32 virt_core) {
|
||||
return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority,
|
||||
Core::CpuManager::GetSuspendThreadStartFunc(),
|
||||
system.GetCpuManager().GetStartFuncParamater());
|
||||
Core::CpuManager::GetShutdownThreadStartFunc(),
|
||||
system.GetCpuManager().GetStartFuncParameter());
|
||||
}
|
||||
|
||||
ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread,
|
||||
|
@ -284,7 +284,7 @@ ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread,
|
|||
system.Kernel().GlobalSchedulerContext().AddThread(thread);
|
||||
return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
|
||||
ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(),
|
||||
system.GetCpuManager().GetStartFuncParamater());
|
||||
system.GetCpuManager().GetStartFuncParameter());
|
||||
}
|
||||
|
||||
void KThread::PostDestroy(uintptr_t arg) {
|
||||
|
|
|
@ -76,7 +76,7 @@ struct KernelCore::Impl {
|
|||
InitializeMemoryLayout();
|
||||
Init::InitializeKPageBufferSlabHeap(system);
|
||||
InitializeSchedulers();
|
||||
InitializeSuspendThreads();
|
||||
InitializeShutdownThreads();
|
||||
InitializePreemption(kernel);
|
||||
|
||||
RegisterHostThread();
|
||||
|
@ -143,9 +143,9 @@ struct KernelCore::Impl {
|
|||
CleanupObject(system_resource_limit);
|
||||
|
||||
for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
|
||||
if (suspend_threads[core_id]) {
|
||||
suspend_threads[core_id]->Close();
|
||||
suspend_threads[core_id] = nullptr;
|
||||
if (shutdown_threads[core_id]) {
|
||||
shutdown_threads[core_id]->Close();
|
||||
shutdown_threads[core_id] = nullptr;
|
||||
}
|
||||
|
||||
schedulers[core_id]->Finalize();
|
||||
|
@ -247,14 +247,14 @@ struct KernelCore::Impl {
|
|||
system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
|
||||
}
|
||||
|
||||
void InitializeSuspendThreads() {
|
||||
void InitializeShutdownThreads() {
|
||||
for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
|
||||
suspend_threads[core_id] = KThread::Create(system.Kernel());
|
||||
ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id], {}, {},
|
||||
shutdown_threads[core_id] = KThread::Create(system.Kernel());
|
||||
ASSERT(KThread::InitializeHighPriorityThread(system, shutdown_threads[core_id], {}, {},
|
||||
core_id)
|
||||
.IsSuccess());
|
||||
suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id));
|
||||
suspend_threads[core_id]->DisableDispatch();
|
||||
shutdown_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id));
|
||||
shutdown_threads[core_id]->DisableDispatch();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -769,7 +769,7 @@ struct KernelCore::Impl {
|
|||
std::weak_ptr<ServiceThread> default_service_thread;
|
||||
Common::ThreadWorker service_threads_manager;
|
||||
|
||||
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads;
|
||||
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads;
|
||||
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
|
||||
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
|
||||
|
||||
|
@ -920,6 +920,12 @@ const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const {
|
|||
return *impl->global_object_list_container;
|
||||
}
|
||||
|
||||
void KernelCore::InterruptAllPhysicalCores() {
|
||||
for (auto& physical_core : impl->cores) {
|
||||
physical_core.Interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
void KernelCore::InvalidateAllInstructionCaches() {
|
||||
for (auto& physical_core : impl->cores) {
|
||||
physical_core.ArmInterface().ClearInstructionCache();
|
||||
|
@ -1067,19 +1073,22 @@ const Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() const {
|
|||
return *impl->hidbus_shared_mem;
|
||||
}
|
||||
|
||||
void KernelCore::Suspend(bool in_suspention) {
|
||||
const bool should_suspend = exception_exited || in_suspention;
|
||||
{
|
||||
KScopedSchedulerLock lock(*this);
|
||||
const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting;
|
||||
for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
|
||||
impl->suspend_threads[core_id]->SetState(state);
|
||||
impl->suspend_threads[core_id]->SetWaitReasonForDebugging(
|
||||
ThreadWaitReasonForDebugging::Suspended);
|
||||
}
|
||||
void KernelCore::Suspend(bool suspended) {
|
||||
const bool should_suspend{exception_exited || suspended};
|
||||
const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable;
|
||||
|
||||
for (auto* process : GetProcessList()) {
|
||||
process->SetActivity(activity);
|
||||
}
|
||||
}
|
||||
|
||||
void KernelCore::ShutdownCores() {
|
||||
for (auto* thread : impl->shutdown_threads) {
|
||||
void(thread->Run());
|
||||
}
|
||||
InterruptAllPhysicalCores();
|
||||
}
|
||||
|
||||
bool KernelCore::IsMulticore() const {
|
||||
return impl->is_multicore;
|
||||
}
|
||||
|
|
|
@ -184,6 +184,8 @@ public:
|
|||
|
||||
const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const;
|
||||
|
||||
void InterruptAllPhysicalCores();
|
||||
|
||||
void InvalidateAllInstructionCaches();
|
||||
|
||||
void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
|
||||
|
@ -269,12 +271,15 @@ public:
|
|||
/// Gets the shared memory object for HIDBus services.
|
||||
const Kernel::KSharedMemory& GetHidBusSharedMem() const;
|
||||
|
||||
/// Suspend/unsuspend the OS.
|
||||
void Suspend(bool in_suspention);
|
||||
/// Suspend/unsuspend all processes.
|
||||
void Suspend(bool suspend);
|
||||
|
||||
/// Exceptional exit the OS.
|
||||
/// Exceptional exit all processes.
|
||||
void ExceptionalExit();
|
||||
|
||||
/// Notify emulated CPU cores to shut down.
|
||||
void ShutdownCores();
|
||||
|
||||
bool IsMulticore() const;
|
||||
|
||||
bool IsShuttingDown() const;
|
||||
|
|
|
@ -2530,7 +2530,7 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd
|
|||
return ResultOutOfRange;
|
||||
}
|
||||
|
||||
const auto* const current_process = system.Kernel().CurrentProcess();
|
||||
auto* const current_process = system.Kernel().CurrentProcess();
|
||||
const auto total_copy_size = out_thread_ids_size * sizeof(u64);
|
||||
|
||||
if (out_thread_ids_size > 0 &&
|
||||
|
|
|
@ -150,9 +150,9 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
|
|||
event.event->GetWritableEvent().Clear();
|
||||
if (events_interface.failed[event_id]) {
|
||||
{
|
||||
auto lk = system.StallCPU();
|
||||
auto lk = system.StallProcesses();
|
||||
gpu.WaitFence(params.syncpt_id, target_value);
|
||||
system.UnstallCPU();
|
||||
system.UnstallProcesses();
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
events_interface.failed[event_id] = false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue