diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 4786805509..a66a4bc164 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -40,6 +40,7 @@ SharedPtr Process::Create(SharedPtr code_set) { process->codeset = std::move(code_set); process->flags.raw = 0; process->flags.memory_region.Assign(MemoryRegion::APPLICATION); + process->status = ProcessStatus::Created; process_list.push_back(process); return process; @@ -151,6 +152,8 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { HandleSpecialMapping(vm_manager, mapping); } + status = ProcessStatus::Running; + vm_manager.LogLayout(Log::Level::Debug); Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority, this); } diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 461391fd37..a21b8e704c 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -49,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; @@ -122,6 +124,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++; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 06c9052848..cb5dbad5d3 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -143,6 +143,36 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add return RESULT_SUCCESS; } +static void ExitProcess() { + LOG_INFO(Kernel_SVC, "Process %u exiting", g_current_process->process_id); + + ASSERT_MSG(g_current_process->status == ProcessStatus::Running, "Process has already exited"); + + g_current_process->status = ProcessStatus::Exited; + + // Stop all the process threads that are currently waiting for objects. + auto& thread_list = GetThreadList(); + for (auto& thread : thread_list) { + if (thread->owner_process != g_current_process) + continue; + + if (thread == 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 + GetCurrentThread()->Stop(); + + Core::System::GetInstance().PrepareReschedule(); +} + /// Maps a memory block to specified address static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { LOG_TRACE(Kernel_SVC, @@ -1232,7 +1262,7 @@ static const FunctionDef SVC_Table[] = { {0x00, nullptr, "Unknown"}, {0x01, HLE::Wrap, "ControlMemory"}, {0x02, HLE::Wrap, "QueryMemory"}, - {0x03, nullptr, "ExitProcess"}, + {0x03, ExitProcess, "ExitProcess"}, {0x04, nullptr, "GetProcessAffinityMask"}, {0x05, nullptr, "SetProcessAffinityMask"}, {0x06, nullptr, "GetProcessIdealProcessor"}, @@ -1373,6 +1403,9 @@ void CallSVC(u32 immediate) { // Lock the global kernel mutex when we enter the kernel HLE. std::lock_guard lock(HLE::g_hle_lock); + ASSERT_MSG(g_current_process->status == ProcessStatus::Running, + "Running threads from exiting processes is unimplemented"); + const FunctionDef* info = GetSVCInfo(immediate); if (info) { if (info->func) {