mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-15 13:10:27 +01:00
add rx/fork utility
This commit is contained in:
parent
1efd4248ab
commit
498b580345
|
|
@ -7,6 +7,7 @@ add_library(${PROJECT_NAME} OBJECT
|
|||
src/die.cpp
|
||||
src/FileLock.cpp
|
||||
src/filesystem.cpp
|
||||
src/fork.cpp
|
||||
src/hexdump.cpp
|
||||
src/Mappable.cpp
|
||||
src/mem.cpp
|
||||
|
|
|
|||
8
rx/include/rx/fork.hpp
Normal file
8
rx/include/rx/fork.hpp
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <rx/Process.hpp>
|
||||
|
||||
namespace rx {
|
||||
// Fork result: -1 on error, 0 in child, child PID in parent
|
||||
ProcessId fork();
|
||||
} // namespace rx
|
||||
149
rx/src/fork.cpp
Normal file
149
rx/src/fork.cpp
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
#include <rx/fork.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <mutex>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
namespace {
|
||||
struct ClientId {
|
||||
HANDLE UniqueProcess;
|
||||
HANDLE UniqueThread;
|
||||
};
|
||||
|
||||
struct SECTION_IMAGE_INFORMATION {
|
||||
PVOID TransferAddress; // The address of the image entry point function.
|
||||
ULONG ZeroBits; // The number of high-order address bits that must be zero in
|
||||
// the image base address.
|
||||
SIZE_T MaximumStackSize; // The maximum stack size of threads from the PE file
|
||||
// header.
|
||||
SIZE_T CommittedStackSize; // The initial stack size of threads from the PE
|
||||
// file header.
|
||||
ULONG SubSystemType; // The image subsystem from the PE file header (e.g.,
|
||||
// Windows GUI, Windows CUI, POSIX).
|
||||
union {
|
||||
struct {
|
||||
USHORT SubSystemMinorVersion;
|
||||
USHORT SubSystemMajorVersion;
|
||||
};
|
||||
ULONG SubSystemVersion;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
USHORT MajorOperatingSystemVersion;
|
||||
USHORT MinorOperatingSystemVersion;
|
||||
};
|
||||
ULONG OperatingSystemVersion;
|
||||
};
|
||||
USHORT ImageCharacteristics; // The image characteristics from the PE file
|
||||
// header.
|
||||
USHORT DllCharacteristics; // The DLL characteristics flags (e.g., ASLR, NX
|
||||
// compatibility).
|
||||
USHORT Machine; // The image architecture (e.g., x86, x64, ARM).
|
||||
BOOLEAN ImageContainsCode; // The image contains native executable code.
|
||||
union {
|
||||
UCHAR ImageFlags;
|
||||
struct {
|
||||
UCHAR ComPlusNativeReady
|
||||
: 1; // The image contains precompiled .NET assembly generated by NGEN
|
||||
// (Native Image Generator).
|
||||
UCHAR ComPlusILOnly : 1; // the image contains only Microsoft Intermediate
|
||||
// Language (IL) assembly.
|
||||
UCHAR ImageDynamicallyRelocated
|
||||
: 1; // The image was mapped using a random base address rather than
|
||||
// the preferred base address.
|
||||
UCHAR ImageMappedFlat
|
||||
: 1; // The image was mapped using a single contiguous region, rather
|
||||
// than separate regions for each section.
|
||||
UCHAR BaseBelow4gb : 1; // The image was mapped using a base address below
|
||||
// the 4 GB boundary.
|
||||
UCHAR ComPlusPrefer32bit : 1; // The image prefers to run as a 32-bit
|
||||
// process, even on a 64-bit system.
|
||||
UCHAR Reserved : 2;
|
||||
};
|
||||
};
|
||||
ULONG LoaderFlags; // Reserved by ntdll.dll for the Windows loader.
|
||||
ULONG
|
||||
ImageFileSize; // The size of the image, in bytes, including all headers.
|
||||
ULONG CheckSum; // The image file checksum, from the PE optional header.
|
||||
};
|
||||
|
||||
struct RtlUserProcessInformation {
|
||||
ULONG Length;
|
||||
HANDLE Process;
|
||||
HANDLE Thread;
|
||||
ClientId ClientId;
|
||||
SECTION_IMAGE_INFORMATION ImageInformation;
|
||||
};
|
||||
|
||||
#define RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED 0x00000001
|
||||
#define RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES 0x00000002
|
||||
#define RTL_CLONE_PROCESS_FLAGS_NO_SYNCHRONIZE 0x00000004
|
||||
|
||||
using RtlCloneUserProcessFn = long(__stdcall *)(
|
||||
ULONG Flags, PSECURITY_DESCRIPTOR ProcessSecurityDescriptor,
|
||||
PSECURITY_DESCRIPTOR ThreadSecurityDescriptor, HANDLE DebugPort,
|
||||
RtlUserProcessInformation *ProcessInformation);
|
||||
|
||||
RtlCloneUserProcessFn getRtlClone() {
|
||||
static auto fn = []() -> RtlCloneUserProcessFn {
|
||||
if (auto mod = ::GetModuleHandleW(L"ntdll.dll")) {
|
||||
return reinterpret_cast<RtlCloneUserProcessFn>(
|
||||
::GetProcAddress(mod, "RtlCloneUserProcess"));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
return fn;
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
rx::ProcessId rx::fork() {
|
||||
#ifdef _WIN32
|
||||
auto rtlClone = getRtlClone();
|
||||
if (!rtlClone) {
|
||||
return static_cast<ProcessId>(-1);
|
||||
}
|
||||
|
||||
auto parentPid = ::GetCurrentProcessId();
|
||||
|
||||
RtlUserProcessInformation procInfo{};
|
||||
procInfo.Length = sizeof(procInfo);
|
||||
|
||||
ULONG rtlFlags = RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED |
|
||||
RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES;
|
||||
|
||||
const long status = rtlClone(rtlFlags, nullptr, nullptr, nullptr, &procInfo);
|
||||
|
||||
if (status < 0) {
|
||||
return static_cast<ProcessId>(-1);
|
||||
}
|
||||
|
||||
if (status == 0) {
|
||||
// parent process
|
||||
const DWORD childPid = ::GetProcessId(procInfo.Process);
|
||||
|
||||
if (procInfo.Thread) {
|
||||
::ResumeThread(procInfo.Thread);
|
||||
::CloseHandle(procInfo.Thread);
|
||||
}
|
||||
|
||||
::CloseHandle(procInfo.Process);
|
||||
return static_cast<ProcessId>(childPid);
|
||||
}
|
||||
|
||||
FreeConsole();
|
||||
AttachConsole(parentPid);
|
||||
|
||||
// child process
|
||||
return ProcessId{};
|
||||
#else
|
||||
return static_cast<ProcessId>(::fork());
|
||||
#endif
|
||||
}
|
||||
Loading…
Reference in a new issue