From aa7c824ea422152e3e8ac4586a9b94d2c755c23d Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
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 <algorithm>
 #include <memory>
 #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<SharedPtr<Process>> process_list;
+
 SharedPtr<CodeSet> CodeSet::Create(std::string name, u64 program_id) {
     SharedPtr<CodeSet> codeset(new CodeSet);
 
@@ -36,7 +40,9 @@ SharedPtr<Process> 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<CodeSet> 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<Process> g_current_process;
+void ClearProcessList() {
+    process_list.clear();
 }
+
+SharedPtr<Process> GetProcessById(u32 process_id) {
+    auto itr = std::find_if(
+        process_list.begin(), process_list.end(),
+        [&](const SharedPtr<Process>& process) { return process->process_id == process_id; });
+
+    if (itr == process_list.end())
+        return nullptr;
+
+    return *itr;
+}
+
+SharedPtr<Process> 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 <cstddef>
 #include <memory>
 #include <string>
+#include <vector>
 #include <boost/container/static_vector.hpp>
 #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<Process> GetProcessById(u32 process_id);
+
 extern SharedPtr<Process> 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<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(thread_handle);
+    const SharedPtr<Kernel::Thread> thread =
+        Kernel::g_handle_table.Get<Kernel::Thread>(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<char> 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<MapMemory>, "svcMapMemory"},
     {0x05, HLE::Wrap<UnmapMemory>, "svcUnmapMemory"},
     {0x06, HLE::Wrap<QueryMemory>, "svcQueryMemory"},
-    {0x07, nullptr, "svcExitProcess"},
+    {0x07, HLE::Wrap<ExitProcess>, "svcExitProcess"},
     {0x08, HLE::Wrap<CreateThread>, "svcCreateThread"},
     {0x09, HLE::Wrap<StartThread>, "svcStartThread"},
     {0x0A, HLE::Wrap<ExitThread>, "svcExitThread"},