mirror of
https://github.com/citra-emu/citra.git
synced 2024-12-18 14:40:05 +00:00
Kernel/SVC: Partially implemented svcExitProcess.
Terminating processes with ready threads is not currently implemented and will assert. It is currently unknown how the 3DS kernel stops ready threads or threads running in another core.
This commit is contained in:
parent
4b4e1861c7
commit
1856aa7b32
@ -40,6 +40,7 @@ SharedPtr<Process> Process::Create(SharedPtr<CodeSet> code_set) {
|
|||||||
process->codeset = std::move(code_set);
|
process->codeset = std::move(code_set);
|
||||||
process->flags.raw = 0;
|
process->flags.raw = 0;
|
||||||
process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
|
process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
|
||||||
|
process->status = ProcessStatus::Created;
|
||||||
|
|
||||||
process_list.push_back(process);
|
process_list.push_back(process);
|
||||||
return process;
|
return process;
|
||||||
@ -151,6 +152,8 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
|
|||||||
HandleSpecialMapping(vm_manager, mapping);
|
HandleSpecialMapping(vm_manager, mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status = ProcessStatus::Running;
|
||||||
|
|
||||||
vm_manager.LogLayout(Log::Level::Debug);
|
vm_manager.LogLayout(Log::Level::Debug);
|
||||||
Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority, this);
|
Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority, this);
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,8 @@ union ProcessFlags {
|
|||||||
BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000).
|
BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000).
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ProcessStatus { Created, Running, Exited };
|
||||||
|
|
||||||
class ResourceLimit;
|
class ResourceLimit;
|
||||||
struct MemoryRegionInfo;
|
struct MemoryRegionInfo;
|
||||||
|
|
||||||
@ -122,6 +124,8 @@ public:
|
|||||||
u16 kernel_version = 0;
|
u16 kernel_version = 0;
|
||||||
/// The default CPU for this process, threads are scheduled on this cpu by default.
|
/// The default CPU for this process, threads are scheduled on this cpu by default.
|
||||||
u8 ideal_processor = 0;
|
u8 ideal_processor = 0;
|
||||||
|
/// Current status of the process
|
||||||
|
ProcessStatus status;
|
||||||
|
|
||||||
/// The id of this process
|
/// The id of this process
|
||||||
u32 process_id = next_process_id++;
|
u32 process_id = next_process_id++;
|
||||||
|
@ -143,6 +143,36 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add
|
|||||||
return RESULT_SUCCESS;
|
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
|
/// Maps a memory block to specified address
|
||||||
static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) {
|
static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) {
|
||||||
LOG_TRACE(Kernel_SVC,
|
LOG_TRACE(Kernel_SVC,
|
||||||
@ -1232,7 +1262,7 @@ static const FunctionDef SVC_Table[] = {
|
|||||||
{0x00, nullptr, "Unknown"},
|
{0x00, nullptr, "Unknown"},
|
||||||
{0x01, HLE::Wrap<ControlMemory>, "ControlMemory"},
|
{0x01, HLE::Wrap<ControlMemory>, "ControlMemory"},
|
||||||
{0x02, HLE::Wrap<QueryMemory>, "QueryMemory"},
|
{0x02, HLE::Wrap<QueryMemory>, "QueryMemory"},
|
||||||
{0x03, nullptr, "ExitProcess"},
|
{0x03, ExitProcess, "ExitProcess"},
|
||||||
{0x04, nullptr, "GetProcessAffinityMask"},
|
{0x04, nullptr, "GetProcessAffinityMask"},
|
||||||
{0x05, nullptr, "SetProcessAffinityMask"},
|
{0x05, nullptr, "SetProcessAffinityMask"},
|
||||||
{0x06, nullptr, "GetProcessIdealProcessor"},
|
{0x06, nullptr, "GetProcessIdealProcessor"},
|
||||||
@ -1373,6 +1403,9 @@ void CallSVC(u32 immediate) {
|
|||||||
// Lock the global kernel mutex when we enter the kernel HLE.
|
// Lock the global kernel mutex when we enter the kernel HLE.
|
||||||
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
|
std::lock_guard<std::recursive_mutex> 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);
|
const FunctionDef* info = GetSVCInfo(immediate);
|
||||||
if (info) {
|
if (info) {
|
||||||
if (info->func) {
|
if (info->func) {
|
||||||
|
Loading…
Reference in New Issue
Block a user