ProcessManager: Implement almost all of pm:shell

This commit is contained in:
Michael Scire 2018-05-04 19:56:59 -06:00
parent bceb00ad8d
commit e596fd0de5
4 changed files with 197 additions and 42 deletions

View file

@ -39,6 +39,24 @@ static u64 g_resource_limits[3][5] = {
static Handle g_resource_limit_handles[3] = {0}; static Handle g_resource_limit_handles[3] = {0};
Registration::AutoProcessListLock::AutoProcessListLock() {
g_process_list.Lock();
this->has_lock = true;
}
Registration::AutoProcessListLock::~AutoProcessListLock() {
if (this->has_lock) {
this->Unlock();
}
}
void Registration::AutoProcessListLock::Unlock() {
if (this->has_lock) {
g_process_list.Unlock();
}
this->has_lock = false;
}
void Registration::InitializeSystemResources() { void Registration::InitializeSystemResources() {
g_process_event = new SystemEvent(&IEvent::PanicCallback); g_process_event = new SystemEvent(&IEvent::PanicCallback);
g_debug_title_event = new SystemEvent(&IEvent::PanicCallback); g_debug_title_event = new SystemEvent(&IEvent::PanicCallback);
@ -124,7 +142,7 @@ void Registration::HandleProcessLaunch() {
/* Get the resource limit handle, ensure that we can launch the program. */ /* Get the resource limit handle, ensure that we can launch the program. */
if ((program_info.application_type & 3) == 1) { if ((program_info.application_type & 3) == 1) {
if (HasApplicationProcess()) { if (HasApplicationProcess(NULL)) {
rc = 0xA0F; rc = 0xA0F;
goto HANDLE_PROCESS_LAUNCH_END; goto HANDLE_PROCESS_LAUNCH_END;
} }
@ -310,8 +328,8 @@ void Registration::HandleSignaledProcess(Process *process) {
} }
void Registration::FinalizeExitedProcess(Process *process) { void Registration::FinalizeExitedProcess(Process *process) {
AutoProcessListLock auto_lock;
bool signal_debug_process_5x = kernelAbove500() && process->flags & 1; bool signal_debug_process_5x = kernelAbove500() && process->flags & 1;
g_process_list.Lock();
/* Unregister with FS. */ /* Unregister with FS. */
if (R_FAILED(fsprUnregisterProgram(process->pid))) { if (R_FAILED(fsprUnregisterProgram(process->pid))) {
/* TODO: Panic. */ /* TODO: Panic. */
@ -338,20 +356,20 @@ void Registration::FinalizeExitedProcess(Process *process) {
/* Remove NOTE: This probably frees process. */ /* Remove NOTE: This probably frees process. */
RemoveProcessFromList(process->pid); RemoveProcessFromList(process->pid);
g_process_list.Unlock(); auto_lock.Unlock();
if (signal_debug_process_5x) { if (signal_debug_process_5x) {
g_process_event->signal_event(); g_process_event->signal_event();
} }
} }
void Registration::AddProcessToList(Process *process) { void Registration::AddProcessToList(Process *process) {
g_process_list.Lock(); AutoProcessListLock auto_lock;
g_process_list.process_waiters.push_back(new ProcessWaiter(process)); g_process_list.process_waiters.push_back(new ProcessWaiter(process));
g_process_list.Unlock();
} }
void Registration::RemoveProcessFromList(u64 pid) { void Registration::RemoveProcessFromList(u64 pid) {
g_process_list.Lock(); AutoProcessListLock auto_lock;
/* Remove process from list. */ /* Remove process from list. */
for (unsigned int i = 0; i < g_process_list.process_waiters.size(); i++) { for (unsigned int i = 0; i < g_process_list.process_waiters.size(); i++) {
ProcessWaiter *pw = g_process_list.process_waiters[i]; ProcessWaiter *pw = g_process_list.process_waiters[i];
@ -363,36 +381,120 @@ void Registration::RemoveProcessFromList(u64 pid) {
break; break;
} }
} }
g_process_list.Unlock();
} }
void Registration::SetProcessState(u64 pid, ProcessState new_state) { void Registration::SetProcessState(u64 pid, ProcessState new_state) {
g_process_list.Lock(); AutoProcessListLock auto_lock;
/* Set process state. */ /* Set process state. */
for (unsigned int i = 0; i < g_process_list.process_waiters.size(); i++) { for (auto &pw : g_process_list.process_waiters) {
ProcessWaiter *pw = g_process_list.process_waiters[i];
Registration::Process *process = pw->get_process(); Registration::Process *process = pw->get_process();
if (process->pid == pid) { if (process->pid == pid) {
process->state = new_state; process->state = new_state;
break; break;
} }
} }
g_process_list.Unlock();
} }
bool Registration::HasApplicationProcess() { bool Registration::HasApplicationProcess(Process **out) {
bool has_app = false; AutoProcessListLock auto_lock;
g_process_list.Lock();
for (auto &pw : g_process_list.process_waiters) { for (auto &pw : g_process_list.process_waiters) {
if (pw->get_process()->flags & 0x40) { Registration::Process *process = pw->get_process();
has_app = true; if (process->flags & 0x40) {
break; if (out != NULL) {
*out = process;
}
return true;
} }
} }
g_process_list.Unlock(); return false;
return has_app; }
Registration::Process *Registration::GetProcess(u64 pid) {
AutoProcessListLock auto_lock;
for (auto &pw : g_process_list.process_waiters) {
Process *p = pw->get_process();
if (p->pid == pid) {
return p;
}
}
return NULL;
}
Registration::Process *Registration::GetProcessByTitleId(u64 tid) {
AutoProcessListLock auto_lock;
for (auto &pw : g_process_list.process_waiters) {
Process *p = pw->get_process();
if (p->tid_sid.title_id == tid) {
return p;
}
}
return NULL;
}
Handle Registration::GetProcessEventHandle() {
return g_process_event->get_handle();
}
void Registration::GetProcessEventType(u64 *out_pid, u64 *out_type) {
AutoProcessListLock auto_lock;
for (auto &pw : g_process_list.process_waiters) {
Process *p = pw->get_process();
if (kernelAbove200() && p->state >= ProcessState_DebugDetached && p->flags & 0x100) {
p->flags &= ~0x100;
*out_pid = p->pid;
*out_type = kernelAbove500() ? 2 : 5;
return;
}
if (p->flags & 0x10) {
p->flags &= ~0x10;
*out_pid = p->pid;
*out_type = kernelAbove500() ? (((p->flags >> 5) & 1) | 4) : (((p->flags >> 5) & 1) + 3);
return;
}
if (p->flags & 2) {
*out_pid = p->pid;
*out_type = kernelAbove500() ? 3 : 1;
return;
}
if (!kernelAbove500() && p->flags & 1 && p->state == ProcessState_Exited) {
*out_pid = p->pid;
*out_type = 2;
return;
}
}
if (kernelAbove500()) {
auto_lock.Unlock();
g_dead_process_list.Lock();
if (g_dead_process_list.process_waiters.size()) {
ProcessWaiter *pw = g_dead_process_list.process_waiters[0];
Registration::Process *process = pw->get_process();
g_dead_process_list.process_waiters.erase(g_dead_process_list.process_waiters.begin());
*out_pid = process->pid;
*out_type = 1;
delete pw;
g_dead_process_list.Unlock();
return;
}
g_dead_process_list.Unlock();
}
*out_pid = 0;
*out_type = 0;
}
Handle Registration::GetDebugTitleEventHandle() {
return g_debug_title_event->get_handle();
}
Handle Registration::GetDebugApplicationEventHandle() {
return g_debug_application_event->get_handle();
} }
void Registration::EnsureApplicationResourcesAvailable() { void Registration::EnsureApplicationResourcesAvailable() {

View file

@ -31,6 +31,14 @@ class Registration {
u64* out_pid; u64* out_pid;
Result result; Result result;
}; };
class AutoProcessListLock {
private:
bool has_lock;
public:
AutoProcessListLock();
~AutoProcessListLock();
void Unlock();
};
static void InitializeSystemResources(); static void InitializeSystemResources();
static IWaitable *GetProcessLaunchStartEvent(); static IWaitable *GetProcessLaunchStartEvent();
@ -44,12 +52,19 @@ class Registration {
static void RemoveProcessFromList(u64 pid); static void RemoveProcessFromList(u64 pid);
static void SetProcessState(u64 pid, ProcessState new_state); static void SetProcessState(u64 pid, ProcessState new_state);
static Process *GetProcess(u64 pid);
static Process *GetProcessByTitleId(u64 tid);
static Handle GetProcessEventHandle();
static void GetProcessEventType(u64 *out_pid, u64 *out_type);
static Handle GetDebugTitleEventHandle();
static Handle GetDebugApplicationEventHandle();
static void HandleProcessLaunch(); static void HandleProcessLaunch();
static void SignalFinishLaunchProcess(); static void SignalFinishLaunchProcess();
static Result LaunchProcess(u64 title_id, FsStorageId storage_id, u64 launch_flags, u64 *out_pid); static Result LaunchProcess(u64 title_id, FsStorageId storage_id, u64 launch_flags, u64 *out_pid);
static Result LaunchProcessByTidSid(TidSid tid_sid, u64 launch_flags, u64 *out_pid); static Result LaunchProcessByTidSid(TidSid tid_sid, u64 launch_flags, u64 *out_pid);
static bool HasApplicationProcess(); static bool HasApplicationProcess(Process **out);
static void EnsureApplicationResourcesAvailable(); static void EnsureApplicationResourcesAvailable();
}; };

View file

@ -50,7 +50,7 @@ Result ShellService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id
case Shell_Cmd_GetProcessEventType: case Shell_Cmd_GetProcessEventType:
rc = WrapIpcCommandImpl<&ShellService::get_process_event_type>(this, r, out_c, pointer_buffer, pointer_buffer_size); rc = WrapIpcCommandImpl<&ShellService::get_process_event_type>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break; break;
case Shell_Cmd_FinalizeDeadProcess: case Shell_Cmd_FinalizeExitedProcess:
rc = WrapIpcCommandImpl<&ShellService::finalize_dead_process>(this, r, out_c, pointer_buffer, pointer_buffer_size); rc = WrapIpcCommandImpl<&ShellService::finalize_dead_process>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break; break;
case Shell_Cmd_ClearProcessNotificationFlag: case Shell_Cmd_ClearProcessNotificationFlag:
@ -78,55 +78,93 @@ Result ShellService::handle_deferred() {
} }
std::tuple<Result, u64> launch_process(u64 launch_flags, Registration::TidSid tid_sid) { std::tuple<Result, u64> launch_process(u64 launch_flags, Registration::TidSid tid_sid) {
/* TODO */ u64 pid = 0;
return {0xF601, 0}; Result rc = Registration::LaunchProcessByTidSid(tid_sid, launch_flags, &pid);
return {rc, pid};
} }
std::tuple<Result> terminate_process_id(u64 pid) { std::tuple<Result> terminate_process_id(u64 pid) {
/* TODO */ Registration::AutoProcessListLock auto_lock;
return {0xF601};
Registration::Process *proc = Registration::GetProcess(pid);
if (proc != NULL) {
return {svcCloseHandle(proc->handle)};
} else {
return {0x20F};
}
} }
std::tuple<Result> terminate_title_id(u64 tid) { std::tuple<Result> terminate_title_id(u64 tid) {
/* TODO */ Registration::AutoProcessListLock auto_lock;
return {0xF601};
Registration::Process *proc = Registration::GetProcessByTitleId(tid);
if (proc != NULL) {
return {svcCloseHandle(proc->handle)};
} else {
return {0x20F};
}
} }
std::tuple<Result, CopiedHandle> get_process_wait_event() { std::tuple<Result, CopiedHandle> get_process_wait_event() {
/* TODO */ return {0x0, Registration::GetProcessEventHandle()};
return {0xF601, 0};
} }
std::tuple<Result, u64, u64> get_process_event_type() { std::tuple<Result, u64, u64> get_process_event_type() {
/* TODO */ u64 type, pid;
return {0xF601, 0, 0}; Registration::GetProcessEventType(&pid, &type);
return {0x0, type, pid};
} }
std::tuple<Result> finalize_dead_process(u64 pid) { std::tuple<Result> finalize_exited_process(u64 pid) {
/* TODO */ Registration::AutoProcessListLock auto_lock;
return {0xF601};
Registration::Process *proc = Registration::GetProcess(pid);
if (proc == NULL) {
return {0x20F};
} else if (proc->state != ProcessState_Exited) {
return {0x60F};
} else {
Registration::FinalizeExitedProcess(proc);
return {0x0};
}
} }
std::tuple<Result> clear_process_notification_flag(u64 pid) { std::tuple<Result> clear_process_notification_flag(u64 pid) {
/* TODO */ Registration::AutoProcessListLock auto_lock;
return {0xF601};
Registration::Process *proc = Registration::GetProcess(pid);
if (proc != NULL) {
proc->flags &= ~2;
return {0x0};
} else {
return {0x20F};
}
} }
std::tuple<Result> notify_boot_finished() { std::tuple<Result> notify_boot_finished() {
u64 boot_pid; u64 boot2_pid;
if (!g_has_boot_finished) { if (!g_has_boot_finished) {
Registration::LaunchProcess(BOOT2_TITLE_ID, FsStorageId_NandSystem, 0, &boot_pid);
g_has_boot_finished = true; g_has_boot_finished = true;
return {Registration::LaunchProcess(BOOT2_TITLE_ID, FsStorageId_NandSystem, 0, &boot2_pid)};
} }
return {0}; return {0};
} }
std::tuple<Result, u64> get_application_process_id() { std::tuple<Result, u64> get_application_process_id() {
/* TODO */ Registration::AutoProcessListLock auto_lock;
return {0xF601, 0};
Registration::Process *app_proc;
if (Registration::HasApplicationProcess(&app_proc)) {
return {0, app_proc->pid};
}
return {0x20F, 0};
} }
std::tuple<Result> boost_system_memory_resource_limit() { std::tuple<Result> boost_system_memory_resource_limit() {
if (!kernelAbove400()) {
return {0xF601};
}
/* TODO */ /* TODO */
return {0xF601}; return {0xF601};
} }

View file

@ -12,7 +12,7 @@ enum ShellCmd {
Shell_Cmd_TerminateTitleId = 2, Shell_Cmd_TerminateTitleId = 2,
Shell_Cmd_GetProcessWaitEvent = 3, Shell_Cmd_GetProcessWaitEvent = 3,
Shell_Cmd_GetProcessEventType = 4, Shell_Cmd_GetProcessEventType = 4,
Shell_Cmd_FinalizeDeadProcess = 5, Shell_Cmd_FinalizeExitedProcess = 5,
Shell_Cmd_ClearProcessNotificationFlag = 6, Shell_Cmd_ClearProcessNotificationFlag = 6,
Shell_Cmd_NotifyBootFinished = 7, Shell_Cmd_NotifyBootFinished = 7,
Shell_Cmd_GetApplicationProcessId = 8, Shell_Cmd_GetApplicationProcessId = 8,