pineapple-src/src/core/hle/service/os/process.cpp

153 lines
3.6 KiB
C++
Executable File

// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc_types.h"
#include "core/hle/service/os/process.h"
#include "core/loader/loader.h"
namespace Service {
Process::Process(Core::System& system)
: m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(),
m_process_started() {}
Process::~Process() {
this->Finalize();
}
bool Process::Initialize(Loader::AppLoader& loader, Loader::ResultStatus& out_load_result) {
// First, ensure we are not holding another process.
this->Finalize();
// Create the process.
auto* const process = Kernel::KProcess::Create(m_system.Kernel());
Kernel::KProcess::Register(m_system.Kernel(), process);
// On exit, ensure we free the additional reference to the process.
SCOPE_EXIT {
process->Close();
};
// Insert process modules into memory.
const auto [load_result, load_parameters] = loader.Load(*process, m_system);
out_load_result = load_result;
// Ensure loading was successful.
if (load_result != Loader::ResultStatus::Success) {
return false;
}
// TODO: remove this, kernel already tracks this
m_system.Kernel().AppendNewProcess(process);
// Note the load parameters from NPDM.
m_main_thread_priority = load_parameters->main_thread_priority;
m_main_thread_stack_size = load_parameters->main_thread_stack_size;
// This process has not started yet.
m_process_started = false;
// Take ownership of the process object.
m_process = process;
m_process->Open();
// We succeeded.
return true;
}
void Process::Finalize() {
// Terminate, if we are currently holding a process.
this->Terminate();
// Close the process.
if (m_process) {
m_process->Close();
// TODO: remove this, kernel already tracks this
m_system.Kernel().RemoveProcess(m_process);
}
// Clean up.
m_process = nullptr;
m_main_thread_priority = 0;
m_main_thread_stack_size = 0;
m_process_started = false;
}
bool Process::Run() {
// If we already started the process, don't start again.
if (m_process_started) {
return false;
}
// Start.
if (m_process) {
m_process->Run(m_main_thread_priority, m_main_thread_stack_size);
}
// Mark as started.
m_process_started = true;
// We succeeded.
return true;
}
void Process::Terminate() {
if (m_process) {
m_process->Terminate();
}
}
void Process::ResetSignal() {
if (m_process) {
m_process->Reset();
}
}
bool Process::IsRunning() const {
if (m_process) {
const auto state = m_process->GetState();
return state == Kernel::KProcess::State::Running ||
state == Kernel::KProcess::State::RunningAttached ||
state == Kernel::KProcess::State::DebugBreak;
}
return false;
}
bool Process::IsTerminated() const {
if (m_process) {
return m_process->IsTerminated();
}
return false;
}
u64 Process::GetProcessId() const {
if (m_process) {
return m_process->GetProcessId();
}
return 0;
}
u64 Process::GetProgramId() const {
if (m_process) {
return m_process->GetProgramId();
}
return 0;
}
void Process::Suspend(bool suspended) {
if (m_process) {
m_process->SetActivity(suspended ? Kernel::Svc::ProcessActivity::Paused
: Kernel::Svc::ProcessActivity::Runnable);
}
}
} // namespace Service