Merge pull request #12611 from liamwhite/resource-management-is-hard
kernel: fix resource management issues
This commit is contained in:
commit
0127cec371
15 changed files with 212 additions and 138 deletions
|
@ -28,14 +28,14 @@ Result KMemoryBlockManager::Initialize(KProcessAddress st, KProcessAddress nd,
|
|||
}
|
||||
|
||||
void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager,
|
||||
HostUnmapCallback&& host_unmap_callback) {
|
||||
BlockCallback&& block_callback) {
|
||||
// Erase every block until we have none left.
|
||||
auto it = m_memory_block_tree.begin();
|
||||
while (it != m_memory_block_tree.end()) {
|
||||
KMemoryBlock* block = std::addressof(*it);
|
||||
it = m_memory_block_tree.erase(it);
|
||||
block_callback(block->GetAddress(), block->GetSize());
|
||||
slab_manager->Free(block);
|
||||
host_unmap_callback(block->GetAddress(), block->GetSize());
|
||||
}
|
||||
|
||||
ASSERT(m_memory_block_tree.empty());
|
||||
|
|
|
@ -85,11 +85,11 @@ public:
|
|||
public:
|
||||
KMemoryBlockManager();
|
||||
|
||||
using HostUnmapCallback = std::function<void(Common::ProcessAddress, u64)>;
|
||||
using BlockCallback = std::function<void(Common::ProcessAddress, u64)>;
|
||||
|
||||
Result Initialize(KProcessAddress st, KProcessAddress nd,
|
||||
KMemoryBlockSlabManager* slab_manager);
|
||||
void Finalize(KMemoryBlockSlabManager* slab_manager, HostUnmapCallback&& host_unmap_callback);
|
||||
void Finalize(KMemoryBlockSlabManager* slab_manager, BlockCallback&& block_callback);
|
||||
|
||||
iterator end() {
|
||||
return m_memory_block_tree.end();
|
||||
|
|
|
@ -431,15 +431,43 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
|
|||
m_memory_block_slab_manager));
|
||||
}
|
||||
|
||||
Result KPageTableBase::FinalizeProcess() {
|
||||
// Only process tables should be finalized.
|
||||
ASSERT(!this->IsKernel());
|
||||
|
||||
// NOTE: Here Nintendo calls an unknown OnFinalize function.
|
||||
// this->OnFinalize();
|
||||
|
||||
// NOTE: Here Nintendo calls a second unknown OnFinalize function.
|
||||
// this->OnFinalize2();
|
||||
|
||||
// NOTE: Here Nintendo does a page table walk to discover heap pages to free.
|
||||
// We will use the block manager finalization below to free them.
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void KPageTableBase::Finalize() {
|
||||
auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) {
|
||||
if (Settings::IsFastmemEnabled()) {
|
||||
this->FinalizeProcess();
|
||||
|
||||
auto BlockCallback = [&](KProcessAddress addr, u64 size) {
|
||||
if (m_impl->fastmem_arena) {
|
||||
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false);
|
||||
}
|
||||
|
||||
// Get physical pages.
|
||||
KPageGroup pg(m_kernel, m_block_info_manager);
|
||||
this->MakePageGroup(pg, addr, size / PageSize);
|
||||
|
||||
// Free the pages.
|
||||
pg.CloseAndReset();
|
||||
};
|
||||
|
||||
// Finalize memory blocks.
|
||||
m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(HostUnmapCallback));
|
||||
{
|
||||
KScopedLightLock lk(m_general_lock);
|
||||
m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(BlockCallback));
|
||||
}
|
||||
|
||||
// Free any unsafe mapped memory.
|
||||
if (m_mapped_unsafe_physical_memory) {
|
||||
|
|
|
@ -241,6 +241,7 @@ public:
|
|||
KResourceLimit* resource_limit, Core::Memory::Memory& memory,
|
||||
KProcessAddress aslr_space_start);
|
||||
|
||||
Result FinalizeProcess();
|
||||
void Finalize();
|
||||
|
||||
bool IsKernel() const {
|
||||
|
|
|
@ -171,6 +171,12 @@ void KProcess::Finalize() {
|
|||
m_resource_limit->Close();
|
||||
}
|
||||
|
||||
// Clear expensive resources, as the destructor is not called for guest objects.
|
||||
for (auto& interface : m_arm_interfaces) {
|
||||
interface.reset();
|
||||
}
|
||||
m_exclusive_monitor.reset();
|
||||
|
||||
// Perform inherited finalization.
|
||||
KSynchronizationObject::Finalize();
|
||||
}
|
||||
|
|
|
@ -112,7 +112,14 @@ struct KernelCore::Impl {
|
|||
old_process->Close();
|
||||
}
|
||||
|
||||
process_list.clear();
|
||||
{
|
||||
std::scoped_lock lk{process_list_lock};
|
||||
for (auto* const process : process_list) {
|
||||
process->Terminate();
|
||||
process->Close();
|
||||
}
|
||||
process_list.clear();
|
||||
}
|
||||
|
||||
next_object_id = 0;
|
||||
next_kernel_process_id = KProcess::InitialProcessIdMin;
|
||||
|
@ -770,6 +777,7 @@ struct KernelCore::Impl {
|
|||
std::atomic<u64> next_thread_id{1};
|
||||
|
||||
// Lists all processes that exist in the current session.
|
||||
std::mutex process_list_lock;
|
||||
std::vector<KProcess*> process_list;
|
||||
std::atomic<KProcess*> application_process{};
|
||||
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
|
||||
|
@ -869,9 +877,19 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() {
|
|||
}
|
||||
|
||||
void KernelCore::AppendNewProcess(KProcess* process) {
|
||||
process->Open();
|
||||
|
||||
std::scoped_lock lk{impl->process_list_lock};
|
||||
impl->process_list.push_back(process);
|
||||
}
|
||||
|
||||
void KernelCore::RemoveProcess(KProcess* process) {
|
||||
std::scoped_lock lk{impl->process_list_lock};
|
||||
if (std::erase(impl->process_list, process)) {
|
||||
process->Close();
|
||||
}
|
||||
}
|
||||
|
||||
void KernelCore::MakeApplicationProcess(KProcess* process) {
|
||||
impl->MakeApplicationProcess(process);
|
||||
}
|
||||
|
@ -884,8 +902,15 @@ const KProcess* KernelCore::ApplicationProcess() const {
|
|||
return impl->application_process;
|
||||
}
|
||||
|
||||
const std::vector<KProcess*>& KernelCore::GetProcessList() const {
|
||||
return impl->process_list;
|
||||
std::list<KScopedAutoObject<KProcess>> KernelCore::GetProcessList() {
|
||||
std::list<KScopedAutoObject<KProcess>> processes;
|
||||
std::scoped_lock lk{impl->process_list_lock};
|
||||
|
||||
for (auto* const process : impl->process_list) {
|
||||
processes.emplace_back(process);
|
||||
}
|
||||
|
||||
return processes;
|
||||
}
|
||||
|
||||
Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
@ -116,8 +117,9 @@ public:
|
|||
/// Retrieves a shared pointer to the system resource limit instance.
|
||||
KResourceLimit* GetSystemResourceLimit();
|
||||
|
||||
/// Adds the given shared pointer to an internal list of active processes.
|
||||
/// Adds/removes the given pointer to an internal list of active processes.
|
||||
void AppendNewProcess(KProcess* process);
|
||||
void RemoveProcess(KProcess* process);
|
||||
|
||||
/// Makes the given process the new application process.
|
||||
void MakeApplicationProcess(KProcess* process);
|
||||
|
@ -129,7 +131,7 @@ public:
|
|||
const KProcess* ApplicationProcess() const;
|
||||
|
||||
/// Retrieves the list of processes.
|
||||
const std::vector<KProcess*>& GetProcessList() const;
|
||||
std::list<KScopedAutoObject<KProcess>> GetProcessList();
|
||||
|
||||
/// Gets the sole instance of the global scheduler
|
||||
Kernel::GlobalSchedulerContext& GlobalSchedulerContext();
|
||||
|
|
|
@ -74,13 +74,15 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc
|
|||
}
|
||||
|
||||
auto& memory = GetCurrentMemory(kernel);
|
||||
const auto& process_list = kernel.GetProcessList();
|
||||
auto process_list = kernel.GetProcessList();
|
||||
auto it = process_list.begin();
|
||||
|
||||
const auto num_processes = process_list.size();
|
||||
const auto copy_amount =
|
||||
std::min(static_cast<std::size_t>(out_process_ids_size), num_processes);
|
||||
|
||||
for (std::size_t i = 0; i < copy_amount; ++i) {
|
||||
memory.Write64(out_process_ids, process_list[i]->GetProcessId());
|
||||
for (std::size_t i = 0; i < copy_amount && it != process_list.end(); ++i, ++it) {
|
||||
memory.Write64(out_process_ids, (*it)->GetProcessId());
|
||||
out_process_ids += sizeof(u64);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
namespace Service::Glue {
|
||||
|
||||
namespace {
|
||||
std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 process_id) {
|
||||
const auto& list = system.Kernel().GetProcessList();
|
||||
const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) {
|
||||
std::optional<u64> GetTitleIDForProcessID(Core::System& system, u64 process_id) {
|
||||
auto list = system.Kernel().GetProcessList();
|
||||
|
||||
const auto iter = std::find_if(list.begin(), list.end(), [&process_id](auto& process) {
|
||||
return process->GetProcessId() == process_id;
|
||||
});
|
||||
|
||||
|
|
|
@ -22,12 +22,10 @@ void LoopProcess(Core::System& system) {
|
|||
std::shared_ptr<HidFirmwareSettings> firmware_settings =
|
||||
std::make_shared<HidFirmwareSettings>();
|
||||
|
||||
// TODO: Remove this hack until this service is emulated properly.
|
||||
const auto process_list = system.Kernel().GetProcessList();
|
||||
if (!process_list.empty()) {
|
||||
resource_manager->Initialize();
|
||||
resource_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true);
|
||||
}
|
||||
// TODO: Remove this hack when am is emulated properly.
|
||||
resource_manager->Initialize();
|
||||
resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(),
|
||||
true);
|
||||
|
||||
server_manager->RegisterNamedService(
|
||||
"hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings));
|
||||
|
|
|
@ -22,27 +22,26 @@ constexpr Result ResultProcessNotFound{ErrorModule::PM, 1};
|
|||
|
||||
constexpr u64 NO_PROCESS_FOUND_PID{0};
|
||||
|
||||
std::optional<Kernel::KProcess*> SearchProcessList(
|
||||
const std::vector<Kernel::KProcess*>& process_list,
|
||||
std::function<bool(Kernel::KProcess*)> predicate) {
|
||||
using ProcessList = std::list<Kernel::KScopedAutoObject<Kernel::KProcess>>;
|
||||
|
||||
template <typename F>
|
||||
Kernel::KScopedAutoObject<Kernel::KProcess> SearchProcessList(ProcessList& process_list,
|
||||
F&& predicate) {
|
||||
const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate);
|
||||
|
||||
if (iter == process_list.end()) {
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return *iter;
|
||||
return iter->GetPointerUnsafe();
|
||||
}
|
||||
|
||||
void GetApplicationPidGeneric(HLERequestContext& ctx,
|
||||
const std::vector<Kernel::KProcess*>& process_list) {
|
||||
const auto process = SearchProcessList(process_list, [](const auto& proc) {
|
||||
return proc->GetProcessId() == Kernel::KProcess::ProcessIdMin;
|
||||
});
|
||||
void GetApplicationPidGeneric(HLERequestContext& ctx, ProcessList& process_list) {
|
||||
auto process = SearchProcessList(process_list, [](auto& p) { return p->IsApplication(); });
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(process.has_value() ? (*process)->GetProcessId() : NO_PROCESS_FOUND_PID);
|
||||
rb.Push(process.IsNull() ? NO_PROCESS_FOUND_PID : process->GetProcessId());
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
@ -80,8 +79,7 @@ private:
|
|||
|
||||
class DebugMonitor final : public ServiceFramework<DebugMonitor> {
|
||||
public:
|
||||
explicit DebugMonitor(Core::System& system_)
|
||||
: ServiceFramework{system_, "pm:dmnt"}, kernel{system_.Kernel()} {
|
||||
explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "pm:dmnt"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetJitDebugProcessIdList"},
|
||||
|
@ -106,12 +104,11 @@ private:
|
|||
|
||||
LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);
|
||||
|
||||
const auto process =
|
||||
SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) {
|
||||
return proc->GetProgramId() == program_id;
|
||||
});
|
||||
auto list = kernel.GetProcessList();
|
||||
auto process = SearchProcessList(
|
||||
list, [program_id](auto& p) { return p->GetProgramId() == program_id; });
|
||||
|
||||
if (!process.has_value()) {
|
||||
if (process.IsNull()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultProcessNotFound);
|
||||
return;
|
||||
|
@ -119,12 +116,13 @@ private:
|
|||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push((*process)->GetProcessId());
|
||||
rb.Push(process->GetProcessId());
|
||||
}
|
||||
|
||||
void GetApplicationProcessId(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PM, "called");
|
||||
GetApplicationPidGeneric(ctx, kernel.GetProcessList());
|
||||
auto list = kernel.GetProcessList();
|
||||
GetApplicationPidGeneric(ctx, list);
|
||||
}
|
||||
|
||||
void AtmosphereGetProcessInfo(HLERequestContext& ctx) {
|
||||
|
@ -135,11 +133,10 @@ private:
|
|||
|
||||
LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid);
|
||||
|
||||
const auto process = SearchProcessList(kernel.GetProcessList(), [pid](const auto& proc) {
|
||||
return proc->GetProcessId() == pid;
|
||||
});
|
||||
auto list = kernel.GetProcessList();
|
||||
auto process = SearchProcessList(list, [pid](auto& p) { return p->GetProcessId() == pid; });
|
||||
|
||||
if (!process.has_value()) {
|
||||
if (process.IsNull()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultProcessNotFound);
|
||||
return;
|
||||
|
@ -159,7 +156,7 @@ private:
|
|||
|
||||
OverrideStatus override_status{};
|
||||
ProgramLocation program_location{
|
||||
.program_id = (*process)->GetProgramId(),
|
||||
.program_id = process->GetProgramId(),
|
||||
.storage_id = 0,
|
||||
};
|
||||
|
||||
|
@ -169,14 +166,11 @@ private:
|
|||
rb.PushRaw(program_location);
|
||||
rb.PushRaw(override_status);
|
||||
}
|
||||
|
||||
const Kernel::KernelCore& kernel;
|
||||
};
|
||||
|
||||
class Info final : public ServiceFramework<Info> {
|
||||
public:
|
||||
explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_)
|
||||
: ServiceFramework{system_, "pm:info"}, process_list{process_list_} {
|
||||
explicit Info(Core::System& system_) : ServiceFramework{system_, "pm:info"} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &Info::GetProgramId, "GetProgramId"},
|
||||
{65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"},
|
||||
|
@ -193,11 +187,11 @@ private:
|
|||
|
||||
LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
|
||||
|
||||
const auto process = SearchProcessList(process_list, [process_id](const auto& proc) {
|
||||
return proc->GetProcessId() == process_id;
|
||||
});
|
||||
auto list = kernel.GetProcessList();
|
||||
auto process = SearchProcessList(
|
||||
list, [process_id](auto& p) { return p->GetProcessId() == process_id; });
|
||||
|
||||
if (!process.has_value()) {
|
||||
if (process.IsNull()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultProcessNotFound);
|
||||
return;
|
||||
|
@ -205,7 +199,7 @@ private:
|
|||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push((*process)->GetProgramId());
|
||||
rb.Push(process->GetProgramId());
|
||||
}
|
||||
|
||||
void AtmosphereGetProcessId(HLERequestContext& ctx) {
|
||||
|
@ -214,11 +208,11 @@ private:
|
|||
|
||||
LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);
|
||||
|
||||
const auto process = SearchProcessList(process_list, [program_id](const auto& proc) {
|
||||
return proc->GetProgramId() == program_id;
|
||||
});
|
||||
auto list = system.Kernel().GetProcessList();
|
||||
auto process = SearchProcessList(
|
||||
list, [program_id](auto& p) { return p->GetProgramId() == program_id; });
|
||||
|
||||
if (!process.has_value()) {
|
||||
if (process.IsNull()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultProcessNotFound);
|
||||
return;
|
||||
|
@ -226,16 +220,13 @@ private:
|
|||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push((*process)->GetProcessId());
|
||||
rb.Push(process->GetProcessId());
|
||||
}
|
||||
|
||||
const std::vector<Kernel::KProcess*>& process_list;
|
||||
};
|
||||
|
||||
class Shell final : public ServiceFramework<Shell> {
|
||||
public:
|
||||
explicit Shell(Core::System& system_)
|
||||
: ServiceFramework{system_, "pm:shell"}, kernel{system_.Kernel()} {
|
||||
explicit Shell(Core::System& system_) : ServiceFramework{system_, "pm:shell"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "LaunchProgram"},
|
||||
|
@ -257,10 +248,9 @@ public:
|
|||
private:
|
||||
void GetApplicationProcessIdForShell(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_PM, "called");
|
||||
GetApplicationPidGeneric(ctx, kernel.GetProcessList());
|
||||
auto list = kernel.GetProcessList();
|
||||
GetApplicationPidGeneric(ctx, list);
|
||||
}
|
||||
|
||||
const Kernel::KernelCore& kernel;
|
||||
};
|
||||
|
||||
void LoopProcess(Core::System& system) {
|
||||
|
@ -268,8 +258,7 @@ void LoopProcess(Core::System& system) {
|
|||
|
||||
server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system));
|
||||
server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system));
|
||||
server_manager->RegisterNamedService(
|
||||
"pm:info", std::make_shared<Info>(system, system.Kernel().GetProcessList()));
|
||||
server_manager->RegisterNamedService("pm:info", std::make_shared<Info>(system));
|
||||
server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system));
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue