mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-12 22:59:04 +00:00
Impl sceSystemServiceLoadExec (#3647)
* Add support for restarting the emulator with new configurations - Implement `Restart` function in `Emulator` to enable process relaunch with updated parameters. - Modify `sceSystemServiceLoadExec` to use the restart functionality. * Add logging for emulator restart and system service load execution * Add IPC emulator PID output command Impl `PID` output command to return the emulator process ID - required for launches supporting emulator restart * Add log file append mode support (used after restarting to keep the same log file) * Keep game root between restarts * add --wait-for-debugger option flag * add --wait-for-pid flag used for sync between parent & child process during restart * impl restart via ipc * fix override game root * add qt flags to allow restart
This commit is contained in:
99
src/core/debugger.cpp
Normal file
99
src/core/debugger.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "debugger.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <Windows.h>
|
||||
#include <debugapi.h>
|
||||
#elif defined(__linux__)
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#elif defined(__APPLE__)
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
bool Core::Debugger::IsDebuggerAttached() {
|
||||
#if defined(_WIN32)
|
||||
return IsDebuggerPresent();
|
||||
#elif defined(__linux__)
|
||||
std::ifstream status_file("/proc/self/status");
|
||||
std::string line;
|
||||
while (std::getline(status_file, line)) {
|
||||
if (line.starts_with("TracerPid:")) {
|
||||
std::string tracer_pid = line.substr(10);
|
||||
tracer_pid.erase(0, tracer_pid.find_first_not_of(" \t"));
|
||||
return tracer_pid != "0";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
#elif defined(__APPLE__)
|
||||
int mib[4];
|
||||
struct kinfo_proc info;
|
||||
size_t size = sizeof(info);
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = getpid();
|
||||
|
||||
if (sysctl(mib, 4, &info, &size, nullptr, 0) == 0) {
|
||||
return (info.kp_proc.p_flag & P_TRACED) != 0;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
void Core::Debugger::WaitForDebuggerAttach() {
|
||||
int count = 0;
|
||||
while (!IsDebuggerAttached()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
if (--count <= 0) {
|
||||
count = 10;
|
||||
std::cerr << "Waiting for debugger to attach..." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
int Core::Debugger::GetCurrentPid() {
|
||||
#if defined(_WIN32)
|
||||
return GetCurrentProcessId();
|
||||
#elif defined(__APPLE__) || defined(__linux__)
|
||||
return getpid();
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
void Core::Debugger::WaitForPid(int pid) {
|
||||
#if defined(_WIN32)
|
||||
HANDLE process_handle = OpenProcess(SYNCHRONIZE, FALSE, pid);
|
||||
if (process_handle != nullptr) {
|
||||
std::cerr << "Waiting for process " << pid << " to exit..." << std::endl;
|
||||
WaitForSingleObject(process_handle, INFINITE);
|
||||
CloseHandle(process_handle);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
std::string proc_path = "/proc/" + std::to_string(pid);
|
||||
|
||||
while (std::filesystem::exists(proc_path)) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
std::cerr << "Waiting for process " << pid << " to exit..." << std::endl;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
while (kill(pid, 0) == 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
std::cerr << "Waiting for process " << pid << " to exit..." << std::endl;
|
||||
}
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
}
|
||||
16
src/core/debugger.h
Normal file
16
src/core/debugger.h
Normal file
@@ -0,0 +1,16 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Core::Debugger {
|
||||
|
||||
bool IsDebuggerAttached();
|
||||
|
||||
void WaitForDebuggerAttach();
|
||||
|
||||
int GetCurrentPid();
|
||||
|
||||
void WaitForPid(int pid);
|
||||
|
||||
} // namespace Core::Debugger
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "ipc.h"
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "common/thread.h"
|
||||
#include "common/types.h"
|
||||
#include "core/debug_state.h"
|
||||
#include "core/debugger.h"
|
||||
#include "input/input_handler.h"
|
||||
#include "sdl_window.h"
|
||||
|
||||
@@ -40,6 +41,7 @@
|
||||
* Command list:
|
||||
* - CAPABILITIES:
|
||||
* - ENABLE_MEMORY_PATCH: enables PATCH_MEMORY command
|
||||
* - ENABLE_EMU_CONTROL: enables PAUSE, RESUME, STOP, TOGGLE_FULLSCREEN commands
|
||||
* - INPUT CMD:
|
||||
* - RUN: start the emulator execution
|
||||
* - START: start the game execution
|
||||
@@ -53,7 +55,7 @@
|
||||
* - STOP: stop and quit the emulator
|
||||
* - TOGGLE_FULLSCREEN: enable / disable fullscreen
|
||||
* - OUTPUT CMD:
|
||||
* - N/A
|
||||
* - RESTART(argn: number, argv: ...string): Request restart of the emulator, must call STOP
|
||||
**/
|
||||
|
||||
void IPC::Init() {
|
||||
@@ -81,6 +83,15 @@ void IPC::Init() {
|
||||
}
|
||||
}
|
||||
|
||||
void IPC::SendRestart(const std::vector<std::string>& args) {
|
||||
std::cerr << ";RESTART\n";
|
||||
std::cerr << ";" << args.size() << "\n";
|
||||
for (const auto& arg : args) {
|
||||
std::cerr << ";" << arg << "\n";
|
||||
}
|
||||
std::cerr.flush();
|
||||
}
|
||||
|
||||
void IPC::InputLoop() {
|
||||
auto next_str = [&] -> const std::string& {
|
||||
static std::string line_buffer;
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
#include "common/singleton.h"
|
||||
|
||||
#include <semaphore>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
class IPC {
|
||||
bool enabled{false};
|
||||
@@ -34,6 +36,8 @@ public:
|
||||
start_semaphore.acquire();
|
||||
}
|
||||
|
||||
void SendRestart(const std::vector<std::string>& args);
|
||||
|
||||
private:
|
||||
[[noreturn]] void InputLoop();
|
||||
};
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/file_sys/fs.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/system/systemservice.h"
|
||||
#include "core/libraries/system/systemservice_error.h"
|
||||
#include "emulator.h"
|
||||
|
||||
namespace Libraries::SystemService {
|
||||
|
||||
@@ -1866,8 +1869,18 @@ int PS4_SYSV_ABI sceSystemServiceLaunchWebBrowser() {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceSystemServiceLoadExec() {
|
||||
LOG_ERROR(Lib_SystemService, "(STUBBED) called");
|
||||
int PS4_SYSV_ABI sceSystemServiceLoadExec(const char* path, const char* argv[]) {
|
||||
LOG_DEBUG(Lib_SystemService, "called");
|
||||
auto emu = Common::Singleton<Core::Emulator>::Instance();
|
||||
auto mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
auto hostPath = mnt->GetHostPath(std::string_view(path));
|
||||
std::vector<std::string> args;
|
||||
if (argv != nullptr) {
|
||||
for (const char** ptr = argv; *ptr != nullptr; ptr++) {
|
||||
args.push_back(std::string(*ptr));
|
||||
}
|
||||
}
|
||||
emu->Restart(hostPath, args);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -501,7 +501,7 @@ int PS4_SYSV_ABI sceSystemServiceLaunchEventDetails();
|
||||
int PS4_SYSV_ABI sceSystemServiceLaunchTournamentList();
|
||||
int PS4_SYSV_ABI sceSystemServiceLaunchTournamentsTeamProfile();
|
||||
int PS4_SYSV_ABI sceSystemServiceLaunchWebBrowser();
|
||||
int PS4_SYSV_ABI sceSystemServiceLoadExec();
|
||||
int PS4_SYSV_ABI sceSystemServiceLoadExec(const char* path, const char* argv[]);
|
||||
int PS4_SYSV_ABI sceSystemServiceNavigateToAnotherApp();
|
||||
int PS4_SYSV_ABI sceSystemServiceNavigateToGoBack();
|
||||
int PS4_SYSV_ABI sceSystemServiceNavigateToGoBackWithValue();
|
||||
|
||||
@@ -55,7 +55,7 @@ Linker::Linker() : memory{Memory::Instance()} {}
|
||||
|
||||
Linker::~Linker() = default;
|
||||
|
||||
void Linker::Execute(const std::vector<std::string> args) {
|
||||
void Linker::Execute(const std::vector<std::string>& args) {
|
||||
if (Config::debugDump()) {
|
||||
DebugDump();
|
||||
}
|
||||
@@ -115,7 +115,7 @@ void Linker::Execute(const std::vector<std::string> args) {
|
||||
0, "SceKernelInternalMemory");
|
||||
ASSERT_MSG(ret == 0, "Unable to perform sceKernelInternalMemory mapping");
|
||||
|
||||
main_thread.Run([this, module, args](std::stop_token) {
|
||||
main_thread.Run([this, module, &args](std::stop_token) {
|
||||
Common::SetCurrentThreadName("GAME_MainThread");
|
||||
if (auto& ipc = IPC::Instance()) {
|
||||
ipc.WaitForStart();
|
||||
@@ -140,9 +140,9 @@ void Linker::Execute(const std::vector<std::string> args) {
|
||||
params.argc = 1;
|
||||
params.argv[0] = "eboot.bin";
|
||||
if (!args.empty()) {
|
||||
params.argc = args.size() + 1;
|
||||
for (int i = 0; i < args.size() && i < 32; i++) {
|
||||
params.argv[i + 1] = args[i].c_str();
|
||||
params.argc = args.size();
|
||||
for (int i = 0; i < args.size() && i < 33; i++) {
|
||||
params.argv[i] = args[i].c_str();
|
||||
}
|
||||
}
|
||||
params.entry_addr = module->GetEntryAddress();
|
||||
|
||||
@@ -151,7 +151,7 @@ public:
|
||||
void Relocate(Module* module);
|
||||
bool Resolve(const std::string& name, Loader::SymbolType type, Module* module,
|
||||
Loader::SymbolRecord* return_info);
|
||||
void Execute(const std::vector<std::string> args = {});
|
||||
void Execute(const std::vector<std::string>& args = {});
|
||||
void DebugDump();
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user