From aa7c824ea422152e3e8ac4586a9b94d2c755c23d Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 1 Jan 2018 14:38:34 -0500 Subject: [PATCH] svc: Implement svcExitProcess. --- src/core/hle/kernel/process.cpp | 32 ++++++++++++++++++++---- src/core/hle/kernel/process.h | 13 ++++++++-- src/core/hle/svc.cpp | 43 ++++++++++++++++++++++++++++++--- 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 35cf6dc955..8e74059eaa 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include "common/assert.h" #include "common/common_funcs.h" @@ -16,6 +17,9 @@ namespace Kernel { +// Lists all processes that exist in the current session. +static std::vector> process_list; + SharedPtr CodeSet::Create(std::string name, u64 program_id) { SharedPtr codeset(new CodeSet); @@ -36,7 +40,9 @@ SharedPtr Process::Create(std::string&& name) { process->name = std::move(name); process->flags.raw = 0; process->flags.memory_region.Assign(MemoryRegion::APPLICATION); + process->status = ProcessStatus::Created; + process_list.push_back(process); return process; } @@ -129,6 +135,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { } vm_manager.LogLayout(Log::Level::Debug); + status = ProcessStatus::Running; Kernel::SetupMainThread(entry_point, main_thread_priority, this); } @@ -137,11 +144,11 @@ void Process::LoadModule(SharedPtr module_, VAddr base_addr) { memory_region = GetMemoryRegion(flags.memory_region); auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, - MemoryState memory_state) { + MemoryState memory_state) { auto vma = vm_manager - .MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset, segment.size, - memory_state) - .Unwrap(); + .MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset, + segment.size, memory_state) + .Unwrap(); vm_manager.Reprotect(vma, permissions); misc_memory_used += segment.size; memory_region->used += segment.size; @@ -299,5 +306,20 @@ ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) { Kernel::Process::Process() {} Kernel::Process::~Process() {} -SharedPtr g_current_process; +void ClearProcessList() { + process_list.clear(); } + +SharedPtr GetProcessById(u32 process_id) { + auto itr = std::find_if( + process_list.begin(), process_list.end(), + [&](const SharedPtr& process) { return process->process_id == process_id; }); + + if (itr == process_list.end()) + return nullptr; + + return *itr; +} + +SharedPtr g_current_process; +} // namespace Kernel diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 3ea8c298f4..305275387a 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "common/bit_field.h" #include "common/common_types.h" @@ -48,6 +49,8 @@ union ProcessFlags { BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000). }; +enum class ProcessStatus { Created, Running, Exited }; + class ResourceLimit; struct MemoryRegionInfo; @@ -124,6 +127,8 @@ public: u16 kernel_version = 0; /// The default CPU for this process, threads are scheduled on this cpu by default. u8 ideal_processor = 0; + /// Current status of the process + ProcessStatus status; /// The id of this process u32 process_id = next_process_id++; @@ -181,11 +186,15 @@ public: ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); - private: Process(); ~Process() override; }; +void ClearProcessList(); + +/// Retrieves a process from the current list of processes. +SharedPtr GetProcessById(u32 process_id); + extern SharedPtr g_current_process; -} +} // namespace Kernel diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index cba94eac33..1ba61d8072 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -9,6 +9,8 @@ #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" #include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/mutex.h" +#include "core/hle/kernel/object_address_table.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/sync_object.h" @@ -45,7 +47,7 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { /// Unmaps a region that was previously mapped with svcMapMemory static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { LOG_TRACE(Kernel_SVC, "called, dst_addr=0x%llx, src_addr=0x%llx, size=0x%llx", dst_addr, - src_addr, size); + src_addr, size); return Kernel::g_current_process->UnmapMemory(dst_addr, src_addr, size); } @@ -99,7 +101,8 @@ static ResultCode SendSyncRequest(Kernel::Handle handle) { static ResultCode GetThreadId(u32* thread_id, Kernel::Handle thread_handle) { LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); - const SharedPtr thread = Kernel::g_handle_table.Get(thread_handle); + const SharedPtr thread = + Kernel::g_handle_table.Get(thread_handle); if (!thread) { return ERR_INVALID_HANDLE; } @@ -177,7 +180,7 @@ static void Break(u64 unk_0, u64 unk_1, u64 unk_2) { } /// Used to output a message on a debug hardware unit - does nothing on a retail unit -static void OutputDebugString(VAddr address, int len) { +static void OutputDebugString(VAddr address, s32 len) { std::vector string(len); Memory::ReadBlock(address, string.data(), len); LOG_DEBUG(Debug_Emulated, "%.*s", len, string.data()); @@ -272,6 +275,38 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAdd return QueryProcessMemory(memory_info, page_info, Kernel::CurrentProcess, addr); } +/// Exits the current process +static void ExitProcess() { + LOG_INFO(Kernel_SVC, "Process %u exiting", Kernel::g_current_process->process_id); + + ASSERT_MSG(Kernel::g_current_process->status == Kernel::ProcessStatus::Running, + "Process has already exited"); + + Kernel::g_current_process->status = Kernel::ProcessStatus::Exited; + + // Stop all the process threads that are currently waiting for objects. + auto& thread_list = Kernel::GetThreadList(); + for (auto& thread : thread_list) { + if (thread->owner_process != Kernel::g_current_process) + continue; + + if (thread == Kernel::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"); + + thread->Stop(); + } + + // Kill the current thread + Kernel::GetCurrentThread()->Stop(); + + Core::System::GetInstance().PrepareReschedule(); +} + /// Creates a new thread static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, u32 priority, s32 processor_id) { @@ -400,7 +435,7 @@ static const FunctionDef SVC_Table[] = { {0x04, HLE::Wrap, "svcMapMemory"}, {0x05, HLE::Wrap, "svcUnmapMemory"}, {0x06, HLE::Wrap, "svcQueryMemory"}, - {0x07, nullptr, "svcExitProcess"}, + {0x07, HLE::Wrap, "svcExitProcess"}, {0x08, HLE::Wrap, "svcCreateThread"}, {0x09, HLE::Wrap, "svcStartThread"}, {0x0A, HLE::Wrap, "svcExitThread"},