move POSIX spawn, exec and child tracking into posixsrv, keep process transactions alive across reconnects and preserve stable PIDs across image replacement, flesh out spawn with ordered file actions, process-group selection and signal inheritance, implement execve with bootstrap validation and rollback before retiring the old process, add vfork children that share the native process while keeping separate POSIX descriptor and signal state, replace local spawn bookkeeping with child reaping, nonblocking and process-group waits and orphan cleanup, add signal dispositions, per-thread masks, pending delivery, process/group signalling and alarms, translate native exceptions into POSIX signals and inherit masks when creating threads, make pipe waits interruptible and raise SIGPIPE for broken pipes, pass arguments and environment into main and add getenv/environ, add direct user APC notifications that can run without an alertable wait, add current-thread capabilities and resume-and-wait, let accepted IPC endpoints open restricted peer process capabilities and preserve caller security during spawn and exec, make process preparation reusable and improve DLL lookup across current, executable and fallback directories, move keyboard repeat into RSSRV so PS/2 and USB share one repeat policy, fix video presentation, report launch failure stages and status codes, mooaaar tests.
This commit is contained in:
1 parent
73abd6f90d
commit
899225f551
57 files changed
+8817
-1216
No files matched your search
@@ -12,6 +12,159 @@
|
||||
|
||||
static POSIX_PROCESS_STATE* gPosixProcessState;
|
||||
static int gEmergencyErrno;
|
||||
NTL_POSIX_API char** environ;
|
||||
|
||||
// Reports one startup failure without depending on the POSIX descriptor layer.
|
||||
static void PosixRuntimeReportStartupFailure(const char* stage, KSTATUS status) {
|
||||
static const char hex[] = "0123456789ABCDEF";
|
||||
char buffer[128];
|
||||
const char* prefix = "posix startup: ";
|
||||
size_t position = 0;
|
||||
while (*prefix && position + 1u < sizeof(buffer)) buffer[position++] = *prefix++;
|
||||
while (stage && *stage && position + 1u < sizeof(buffer)) buffer[position++] = *stage++;
|
||||
const char* middle = " failed status=0x";
|
||||
while (*middle && position + 1u < sizeof(buffer)) buffer[position++] = *middle++;
|
||||
for (int shift = 28; shift >= 0 && position + 1u < sizeof(buffer); shift -= 4)
|
||||
buffer[position++] = hex[(status >> shift) & 0xFu];
|
||||
if (position + 1u < sizeof(buffer)) buffer[position++] = '\n';
|
||||
buffer[position] = '\0';
|
||||
SYS_WRITE_CONSOLE_REQUEST write;
|
||||
memset(&write, 0, sizeof(write));
|
||||
write.Size = sizeof(write);
|
||||
write.Text = SysSvFromParts(buffer, position);
|
||||
(void)SysWriteConsole(&write);
|
||||
}
|
||||
|
||||
static void PosixRuntimeDestroyVectors(POSIX_PROCESS_STATE* process);
|
||||
|
||||
// Copies one immutable loader vector into mutable process-local POSIX strings.
|
||||
static KSTATUS PosixRuntimeCopyVector(int environment, char*** vectorOut, int* countOut) {
|
||||
if (!vectorOut || !countOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*vectorOut = (char**)0;
|
||||
*countOut = 0;
|
||||
|
||||
uint32_t count = 0;
|
||||
KSTATUS status = environment ? NtlGetProcessEnvironmentCount(&count)
|
||||
: NtlGetProcessArgumentCount(&count);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
if (count > INT32_MAX) return NTLSTATUS_LIMIT_REACHED;
|
||||
|
||||
char** vector = (char**)calloc((size_t)count + 1u, sizeof(char*));
|
||||
if (!vector) return NTLSTATUS_NO_MEMORY;
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
SYS_STRING_VIEW view = SYS_SV_NULL;
|
||||
status = environment ? NtlGetProcessEnvironment(i, &view)
|
||||
: NtlGetProcessArgument(i, &view);
|
||||
if (!KSUCCESS(status)) {
|
||||
for (uint32_t j = 0; j < i; ++j) free(vector[j]);
|
||||
free(vector);
|
||||
return status;
|
||||
}
|
||||
vector[i] = (char*)malloc(view.Length + 1u);
|
||||
if (!vector[i]) {
|
||||
for (uint32_t j = 0; j < i; ++j) free(vector[j]);
|
||||
free(vector);
|
||||
return NTLSTATUS_NO_MEMORY;
|
||||
}
|
||||
if (view.Length) memcpy(vector[i], view.Data, view.Length);
|
||||
vector[i][view.Length] = '\0';
|
||||
}
|
||||
*vectorOut = vector;
|
||||
*countOut = (int)count;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Builds the compatibility command-line view from the loader-owned argv vector.
|
||||
static KSTATUS PosixRuntimeBuildCommandLine(POSIX_PROCESS_STATE* process) {
|
||||
if (!process) return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (process->ArgumentCount <= 0 || !process->Arguments) return NTLSTATUS_SUCCESS;
|
||||
|
||||
size_t required = 1u;
|
||||
for (int i = 0; i < process->ArgumentCount; ++i) {
|
||||
const char* argument = process->Arguments[i] ? process->Arguments[i] : "";
|
||||
int quote = 0;
|
||||
for (const char* cursor = argument; *cursor; ++cursor) {
|
||||
if (*cursor == ' ' || *cursor == '\t') quote = 1;
|
||||
if (*cursor == '"') {
|
||||
if (required == (size_t)-1) return NTLSTATUS_LIMIT_REACHED;
|
||||
++required;
|
||||
}
|
||||
if (required == (size_t)-1) return NTLSTATUS_LIMIT_REACHED;
|
||||
++required;
|
||||
}
|
||||
if (quote) {
|
||||
if (required > (size_t)-1 - 2u) return NTLSTATUS_LIMIT_REACHED;
|
||||
required += 2u;
|
||||
}
|
||||
if (i != 0) {
|
||||
if (required == (size_t)-1) return NTLSTATUS_LIMIT_REACHED;
|
||||
++required;
|
||||
}
|
||||
}
|
||||
|
||||
char* commandLine = (char*)malloc(required);
|
||||
if (!commandLine) return NTLSTATUS_NO_MEMORY;
|
||||
size_t position = 0;
|
||||
for (int i = 0; i < process->ArgumentCount; ++i) {
|
||||
const char* argument = process->Arguments[i] ? process->Arguments[i] : "";
|
||||
int quote = 0;
|
||||
for (const char* cursor = argument; *cursor; ++cursor) {
|
||||
if (*cursor == ' ' || *cursor == '\t') { quote = 1; break; }
|
||||
}
|
||||
if (i != 0) commandLine[position++] = ' ';
|
||||
if (quote) commandLine[position++] = '"';
|
||||
for (const char* cursor = argument; *cursor; ++cursor) {
|
||||
if (*cursor == '"') commandLine[position++] = '\\';
|
||||
commandLine[position++] = *cursor;
|
||||
}
|
||||
if (quote) commandLine[position++] = '"';
|
||||
}
|
||||
commandLine[position] = '\0';
|
||||
process->CommandLine = commandLine;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Materializes argv and environ before application entry executes.
|
||||
static KSTATUS PosixRuntimeInitializeVectors(POSIX_PROCESS_STATE* process) {
|
||||
if (!process) return NTLSTATUS_INVALID_PARAMETER;
|
||||
int environmentCount = 0;
|
||||
KSTATUS status = PosixRuntimeCopyVector(0, &process->Arguments, &process->ArgumentCount);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
status = PosixRuntimeCopyVector(1, &process->Environment, &environmentCount);
|
||||
if (!KSUCCESS(status)) {
|
||||
for (int i = 0; i < process->ArgumentCount; ++i) free(process->Arguments[i]);
|
||||
free(process->Arguments);
|
||||
process->Arguments = (char**)0;
|
||||
process->ArgumentCount = 0;
|
||||
return status;
|
||||
}
|
||||
environ = process->Environment;
|
||||
status = PosixRuntimeBuildCommandLine(process);
|
||||
if (!KSUCCESS(status)) {
|
||||
PosixRuntimeDestroyVectors(process);
|
||||
return status;
|
||||
}
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Releases process-local argv/environ storage during initialization rollback.
|
||||
static void PosixRuntimeDestroyVectors(POSIX_PROCESS_STATE* process) {
|
||||
if (!process) return;
|
||||
if (process->Arguments) {
|
||||
for (int i = 0; i < process->ArgumentCount; ++i) free(process->Arguments[i]);
|
||||
free(process->Arguments);
|
||||
}
|
||||
if (process->Environment) {
|
||||
for (char** entry = process->Environment; *entry; ++entry) free(*entry);
|
||||
free(process->Environment);
|
||||
}
|
||||
free(process->CommandLine);
|
||||
process->Arguments = (char**)0;
|
||||
process->Environment = (char**)0;
|
||||
process->CommandLine = (char*)0;
|
||||
process->ArgumentCount = 0;
|
||||
environ = (char**)0;
|
||||
}
|
||||
|
||||
// Resolves the published POSIX service and opens one private client endpoint.
|
||||
static KSTATUS PosixRuntimeConnectServer(SYS_HANDLE* endpointOut) {
|
||||
@@ -154,6 +307,65 @@ KSTATUS PosixRuntimeCallServer(const NTL_POSIX_REQUEST* request, NTL_POSIX_REPLY
|
||||
replyOut);
|
||||
}
|
||||
|
||||
// Registers a temporary endpoint to the current native/POSIX process identity.
|
||||
static KSTATUS PosixRuntimeRegisterAuxiliaryEndpoint(SYS_HANDLE endpoint) {
|
||||
POSIX_PROCESS_STATE* process = gPosixProcessState;
|
||||
if (!process || process->Magic != POSIX_PROCESS_STATE_MAGIC || endpoint == SYS_HANDLE_INVALID)
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Version = NTL_POSIX_PROTOCOL_VERSION;
|
||||
request.Operation = NTL_POSIX_OP_REGISTER_PROCESS;
|
||||
|
||||
size_t currentDirectorySize = 0;
|
||||
KSTATUS status = NtlGetCurrentDirectory(request.Path, sizeof(request.Path), ¤tDirectorySize);
|
||||
if (!KSUCCESS(status) || currentDirectorySize == 0 || currentDirectorySize > sizeof(request.Path))
|
||||
return KSUCCESS(status) ? NTLSTATUS_FAILURE : status;
|
||||
request.PathLength = (uint32_t)strlen(request.Path);
|
||||
|
||||
NTL_POSIX_REPLY reply;
|
||||
status = PosixRuntimeCallEndpoint(endpoint, &request, (const SYS_PORT_HANDLE_TRANSFER*)0, 0,
|
||||
(SYS_HANDLE*)0, 0, 0, (uint32_t*)0, &reply);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
if (!KSUCCESS(reply.Status)) return reply.Status;
|
||||
if (reply.PosixPid != process->DefaultIdentity.PosixPid ||
|
||||
reply.NativeGeneration != process->DefaultIdentity.Generation ||
|
||||
(reply.ProcessState != NTL_POSIX_PROCESS_STATE_RUNNING &&
|
||||
reply.ProcessState != NTL_POSIX_PROCESS_STATE_EXEC_PREPARING))
|
||||
return NTLSTATUS_ACCESS_DENIED;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Uses an auxiliary registered connection so one blocking request cannot stall ordinary POSIX calls.
|
||||
KSTATUS PosixRuntimeCallServerBlockingWithHandles(const NTL_POSIX_REQUEST* request,
|
||||
const SYS_PORT_HANDLE_TRANSFER* handles,
|
||||
uint32_t handleCount,
|
||||
NTL_POSIX_REPLY* replyOut) {
|
||||
if (!request || !replyOut || (handleCount != 0 && !handles) ||
|
||||
handleCount > SYS_PORT_MAX_TRANSFER_HANDLES)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
SYS_HANDLE endpoint = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = PosixRuntimeConnectServer(&endpoint);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
status = PosixRuntimeRegisterAuxiliaryEndpoint(endpoint);
|
||||
if (KSUCCESS(status))
|
||||
status = PosixRuntimeCallEndpoint(endpoint, request, handles, handleCount,
|
||||
(SYS_HANDLE*)0, 0, 0, (uint32_t*)0, replyOut);
|
||||
(void)SysDisconnectPort(endpoint);
|
||||
(void)SysCloseHandle(endpoint);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Uses an auxiliary registered connection without transferring capabilities.
|
||||
KSTATUS PosixRuntimeCallServerBlocking(const NTL_POSIX_REQUEST* request, NTL_POSIX_REPLY* replyOut) {
|
||||
return PosixRuntimeCallServerBlockingWithHandles(
|
||||
request, (const SYS_PORT_HANDLE_TRANSFER*)0, 0, replyOut);
|
||||
}
|
||||
|
||||
// Queries the current server-owned POSIX process attributes.
|
||||
KSTATUS PosixRuntimeGetProcessAttributes(NTL_POSIX_REPLY* replyOut) {
|
||||
if (!replyOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
@@ -180,8 +392,12 @@ static KSTATUS PosixRuntimeReadBootstrap(NTL_POSIX_BOOTSTRAP_DATA* bootstrapOut)
|
||||
if (!KSUCCESS(status)) return status;
|
||||
if (size != sizeof(*bootstrapOut) || bootstrapOut->Magic != NTL_POSIX_BOOTSTRAP_MAGIC ||
|
||||
bootstrapOut->Version != NTL_POSIX_BOOTSTRAP_VERSION ||
|
||||
bootstrapOut->Size != sizeof(*bootstrapOut) || bootstrapOut->Reserved != 0)
|
||||
bootstrapOut->Size != sizeof(*bootstrapOut) || bootstrapOut->Reserved != 0 ||
|
||||
(bootstrapOut->InitialSignalMask & ~NTL_POSIX_SIGNAL_VALID_MASK) != 0 ||
|
||||
(bootstrapOut->IgnoredSignals & ~NTL_POSIX_SIGNAL_VALID_MASK) != 0)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
bootstrapOut->InitialSignalMask &= ~NTL_POSIX_SIGNAL_UNBLOCKABLE_MASK;
|
||||
bootstrapOut->IgnoredSignals &= ~NTL_POSIX_SIGNAL_UNBLOCKABLE_MASK;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -195,16 +411,6 @@ static KSTATUS PosixRuntimeRegisterProcess(POSIX_PROCESS_STATE* process,
|
||||
status = PosixRuntimeConnectServer(&endpoint);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
SYS_HANDLE selfProcess = SYS_HANDLE_INVALID;
|
||||
status = SysOpenProcess(SysGetCurrentPid(),
|
||||
SYS_RIGHT_QUERY | SYS_RIGHT_WAIT | SYS_RIGHT_TRANSFER,
|
||||
&selfProcess);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)SysDisconnectPort(endpoint);
|
||||
(void)SysCloseHandle(endpoint);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
@@ -221,21 +427,13 @@ static KSTATUS PosixRuntimeRegisterProcess(POSIX_PROCESS_STATE* process,
|
||||
if (!KSUCCESS(status) || currentDirectorySize == 0 || currentDirectorySize > sizeof(request.Path)) {
|
||||
(void)SysDisconnectPort(endpoint);
|
||||
(void)SysCloseHandle(endpoint);
|
||||
(void)SysCloseHandle(selfProcess);
|
||||
return KSUCCESS(status) ? NTLSTATUS_FAILURE : status;
|
||||
}
|
||||
request.PathLength = (uint32_t)strlen(request.Path);
|
||||
|
||||
SYS_PORT_HANDLE_TRANSFER transfer;
|
||||
memset(&transfer, 0, sizeof(transfer));
|
||||
transfer.Handle = selfProcess;
|
||||
transfer.DesiredRights = SYS_RIGHT_QUERY | SYS_RIGHT_WAIT;
|
||||
transfer.Flags = SYS_PORT_TRANSFER_FLAG_NONE;
|
||||
|
||||
NTL_POSIX_REPLY reply;
|
||||
status = PosixRuntimeCallEndpoint(endpoint, &request, &transfer, 1u,
|
||||
status = PosixRuntimeCallEndpoint(endpoint, &request, (const SYS_PORT_HANDLE_TRANSFER*)0, 0,
|
||||
(SYS_HANDLE*)0, 0, 0, (uint32_t*)0, &reply);
|
||||
(void)SysCloseHandle(selfProcess);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)SysDisconnectPort(endpoint);
|
||||
(void)SysCloseHandle(endpoint);
|
||||
@@ -249,7 +447,10 @@ static KSTATUS PosixRuntimeRegisterProcess(POSIX_PROCESS_STATE* process,
|
||||
}
|
||||
if (reply.ClientProcessId != SysGetCurrentPid() || reply.PosixPid == 0 ||
|
||||
reply.PosixPid > 0x7FFFFFFFu || reply.NativeGeneration == 0 ||
|
||||
reply.ProcessState != NTL_POSIX_PROCESS_STATE_RUNNING) {
|
||||
(reply.ProcessState != NTL_POSIX_PROCESS_STATE_RUNNING &&
|
||||
reply.ProcessState != NTL_POSIX_PROCESS_STATE_CONSTRUCTING &&
|
||||
reply.ProcessState != NTL_POSIX_PROCESS_STATE_EXEC_PREPARING &&
|
||||
reply.ProcessState != NTL_POSIX_PROCESS_STATE_EXEC_COMMITTING)) {
|
||||
(void)SysDisconnectPort(endpoint);
|
||||
(void)SysCloseHandle(endpoint);
|
||||
return NTLSTATUS_FAILURE;
|
||||
@@ -277,7 +478,7 @@ uint32_t PosixRuntimeInitializeProcess(void) {
|
||||
process->Magic = POSIX_PROCESS_STATE_MAGIC;
|
||||
process->Peb = peb;
|
||||
process->ServerEndpoint = SYS_HANDLE_INVALID;
|
||||
process->FdLock = SYS_HANDLE_INVALID;
|
||||
process->DefaultIdentity.FdLock = SYS_HANDLE_INVALID;
|
||||
gPosixProcessState = process;
|
||||
|
||||
NTL_POSIX_BOOTSTRAP_DATA bootstrap;
|
||||
@@ -290,13 +491,18 @@ uint32_t PosixRuntimeInitializeProcess(void) {
|
||||
|
||||
status = PosixRuntimeRegisterProcess(process, &bootstrap);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
PosixRuntimeReportStartupFailure("register-process", status);
|
||||
gPosixProcessState = (POSIX_PROCESS_STATE*)0;
|
||||
free(process);
|
||||
return status;
|
||||
}
|
||||
process->BootstrapToken = bootstrap.Token;
|
||||
process->BootstrapPosixPid = bootstrap.PosixPid;
|
||||
process->BootstrapGeneration = bootstrap.Generation;
|
||||
|
||||
status = PosixFdInitializeProcess(process, bootstrap.FdInheritanceToken);
|
||||
status = PosixRuntimeInitializeVectors(process);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
PosixRuntimeReportStartupFailure("vectors", status);
|
||||
(void)SysDisconnectPort(process->ServerEndpoint);
|
||||
(void)SysCloseHandle(process->ServerEndpoint);
|
||||
process->ServerEndpoint = SYS_HANDLE_INVALID;
|
||||
@@ -305,9 +511,30 @@ uint32_t PosixRuntimeInitializeProcess(void) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = PosixRuntimeAttachThread();
|
||||
for (int signalNumber = NTL_POSIX_SIGNAL_HUP;
|
||||
signalNumber <= NTL_POSIX_SIGNAL_MAX; ++signalNumber) {
|
||||
uint64_t bit = NTL_POSIX_SIGNAL_BIT(signalNumber);
|
||||
if (bootstrap.IgnoredSignals & bit)
|
||||
process->DefaultIdentity.SignalActions[signalNumber].Handler = (uintptr_t)SIG_IGN;
|
||||
}
|
||||
|
||||
status = PosixFdInitializeLogicalProcess(&process->DefaultIdentity, bootstrap.FdInheritanceToken);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
PosixFdDestroyProcess(process);
|
||||
PosixRuntimeReportStartupFailure("fd-init", status);
|
||||
PosixRuntimeDestroyVectors(process);
|
||||
(void)SysDisconnectPort(process->ServerEndpoint);
|
||||
(void)SysCloseHandle(process->ServerEndpoint);
|
||||
process->ServerEndpoint = SYS_HANDLE_INVALID;
|
||||
gPosixProcessState = (POSIX_PROCESS_STATE*)0;
|
||||
free(process);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = PosixRuntimeAttachThreadWithSignalMask(bootstrap.InitialSignalMask);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
PosixRuntimeReportStartupFailure("thread-attach", status);
|
||||
PosixFdDestroyLogicalProcess(&process->DefaultIdentity);
|
||||
PosixRuntimeDestroyVectors(process);
|
||||
(void)SysDisconnectPort(process->ServerEndpoint);
|
||||
(void)SysCloseHandle(process->ServerEndpoint);
|
||||
process->ServerEndpoint = SYS_HANDLE_INVALID;
|
||||
@@ -327,8 +554,61 @@ POSIX_PROCESS_STATE* PosixRuntimeProcessState(void) {
|
||||
return process;
|
||||
}
|
||||
|
||||
// Attaches the native thread to the process's default logical POSIX identity.
|
||||
uint32_t PosixRuntimeAttachThread(void) {
|
||||
// Registers the current native thread capability with posixsrv.
|
||||
static KSTATUS PosixRuntimeRegisterThread(POSIX_PROCESS_STATE* process, POSIX_THREAD_STATE* thread) {
|
||||
if (!process || process->Magic != POSIX_PROCESS_STATE_MAGIC || !thread)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS status = SysSetUserApcDispatcher((void*)SysUserApcDispatcher);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
SYS_HANDLE selfThread = SYS_HANDLE_INVALID;
|
||||
status = SysOpenCurrentThread(SYS_RIGHT_QUERY | SYS_RIGHT_TRANSFER | SYS_THREAD_RIGHT_NOTIFY,
|
||||
&selfThread);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
SYS_PORT_HANDLE_TRANSFER transfer;
|
||||
memset(&transfer, 0, sizeof(transfer));
|
||||
transfer.Handle = selfThread;
|
||||
transfer.DesiredRights = SYS_RIGHT_QUERY | SYS_THREAD_RIGHT_NOTIFY;
|
||||
transfer.Flags = SYS_PORT_TRANSFER_FLAG_NONE;
|
||||
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Version = NTL_POSIX_PROTOCOL_VERSION;
|
||||
request.Operation = NTL_POSIX_OP_REGISTER_THREAD;
|
||||
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
||||
request.SignalMask = thread->SignalBlocked;
|
||||
request.SignalApcRoutine = (uint64_t)(uintptr_t)PosixSignalApc;
|
||||
|
||||
NTL_POSIX_REPLY reply;
|
||||
status = PosixRuntimeCallServerWithHandles(&request, &transfer, 1u, &reply);
|
||||
(void)SysCloseHandle(selfThread);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
return reply.Status;
|
||||
}
|
||||
|
||||
// Removes the current native thread from posixsrv's target registry.
|
||||
static void PosixRuntimeUnregisterThread(POSIX_THREAD_STATE* thread) {
|
||||
if (!thread || !thread->ServerRegistered ||
|
||||
!thread->NativeProcess || thread->NativeProcess->Magic != POSIX_PROCESS_STATE_MAGIC)
|
||||
return;
|
||||
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Version = NTL_POSIX_PROTOCOL_VERSION;
|
||||
request.Operation = NTL_POSIX_OP_UNREGISTER_THREAD;
|
||||
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
||||
|
||||
NTL_POSIX_REPLY reply;
|
||||
(void)PosixRuntimeCallServer(&request, &reply);
|
||||
thread->ServerRegistered = 0;
|
||||
}
|
||||
|
||||
// Attaches the native thread with one inherited persistent POSIX signal mask.
|
||||
uint32_t PosixRuntimeAttachThreadWithSignalMask(uint64_t signalMask) {
|
||||
SYS_TEB* teb = SysGetTeb();
|
||||
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
||||
if (!teb || teb->Magic != SYS_TEB_MAGIC || !process)
|
||||
@@ -349,10 +629,30 @@ uint32_t PosixRuntimeAttachThread(void) {
|
||||
thread->Magic = POSIX_THREAD_STATE_MAGIC;
|
||||
thread->NativeProcess = process;
|
||||
thread->LogicalProcess = &process->DefaultIdentity;
|
||||
thread->NativeThreadId = SysGetCurrentTid();
|
||||
thread->SignalBlocked = signalMask & NTL_POSIX_SIGNAL_VALID_MASK &
|
||||
~NTL_POSIX_SIGNAL_UNBLOCKABLE_MASK;
|
||||
if (thread->NativeThreadId == 0) {
|
||||
free(thread);
|
||||
return NTLSTATUS_FAILURE;
|
||||
}
|
||||
|
||||
KSTATUS status = PosixRuntimeRegisterThread(process, thread);
|
||||
if (!KSUCCESS(status)) {
|
||||
thread->Magic = 0;
|
||||
free(thread);
|
||||
return status;
|
||||
}
|
||||
thread->ServerRegistered = 1u;
|
||||
teb->SubsystemData = thread;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Attaches a native thread with the default empty signal mask.
|
||||
uint32_t PosixRuntimeAttachThread(void) {
|
||||
return PosixRuntimeAttachThreadWithSignalMask(0);
|
||||
}
|
||||
|
||||
// Returns the current thread state, attaching lazily when necessary.
|
||||
POSIX_THREAD_STATE* PosixRuntimeThreadState(void) {
|
||||
if (!PosixRuntimeProcessState()) {
|
||||
@@ -374,6 +674,13 @@ POSIX_THREAD_STATE* PosixRuntimeThreadState(void) {
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
||||
// Returns the logical POSIX process selected by the current native thread.
|
||||
POSIX_LOGICAL_PROCESS_STATE* PosixRuntimeLogicalProcessState(void) {
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
return thread ? thread->LogicalProcess : (POSIX_LOGICAL_PROCESS_STATE*)0;
|
||||
}
|
||||
|
||||
// Releases POSIX state owned by the current native TEB.
|
||||
void PosixRuntimeDetachThread(void) {
|
||||
SYS_TEB* teb = SysGetTeb();
|
||||
@@ -385,6 +692,7 @@ void PosixRuntimeDetachThread(void) {
|
||||
thread->NativeProcess != PosixRuntimeProcessState())
|
||||
return;
|
||||
|
||||
PosixRuntimeUnregisterThread(thread);
|
||||
teb->SubsystemData = (void*)0;
|
||||
thread->Magic = 0;
|
||||
free(thread);
|
||||
@@ -428,11 +736,72 @@ char* PosixRuntimeTakeDlError(void) {
|
||||
return thread->DlError;
|
||||
}
|
||||
|
||||
// Commits a server-built child only after every current personality bootstrap step succeeds.
|
||||
static KSTATUS PosixRuntimeReportBootstrapReady(POSIX_PROCESS_STATE* process) {
|
||||
if (!process || process->Magic != POSIX_PROCESS_STATE_MAGIC)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (process->BootstrapToken == 0) return NTLSTATUS_SUCCESS;
|
||||
|
||||
NTL_POSIX_REQUEST ready;
|
||||
memset(&ready, 0, sizeof(ready));
|
||||
ready.Size = sizeof(ready);
|
||||
ready.Version = NTL_POSIX_PROTOCOL_VERSION;
|
||||
ready.Operation = NTL_POSIX_OP_BOOTSTRAP_READY;
|
||||
ready.BootstrapToken = process->BootstrapToken;
|
||||
ready.BootstrapPosixPid = process->BootstrapPosixPid;
|
||||
ready.BootstrapGeneration = process->BootstrapGeneration;
|
||||
NTL_POSIX_REPLY reply;
|
||||
KSTATUS status = PosixRuntimeCallServer(&ready, &reply);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
if (!KSUCCESS(reply.Status)) return reply.Status;
|
||||
|
||||
process->BootstrapToken = 0;
|
||||
process->BootstrapPosixPid = 0;
|
||||
process->BootstrapGeneration = 0;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Initializes all POSIX process state required before application main.
|
||||
NTL_POSIX_API uint32_t __ntl_posix_process_start(void) {
|
||||
uint32_t status = PosixRuntimeInitializeProcess();
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
||||
status = PosixSignalInitializeExceptionTranslation(process);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
PosixRuntimeReportStartupFailure("signal-init", status);
|
||||
return status;
|
||||
}
|
||||
status = PosixRuntimeReportBootstrapReady(process);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
PosixRuntimeReportStartupFailure("bootstrap-ready", status);
|
||||
return status;
|
||||
}
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Returns process-local vectors to the POSIX startup shim after initialization.
|
||||
NTL_POSIX_API uint32_t __ntl_posix_process_vectors(int* argcOut,
|
||||
char*** argvOut,
|
||||
char*** envpOut) {
|
||||
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
||||
if (!process || !argcOut || !argvOut || !envpOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*argcOut = process->ArgumentCount;
|
||||
*argvOut = process->Arguments;
|
||||
*envpOut = process->Environment;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Finds one process-local environment entry by exact variable name.
|
||||
NTL_POSIX_API char* getenv(const char* name) {
|
||||
if (!name || !name[0] || strchr(name, '=')) return (char*)0;
|
||||
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
||||
if (!process || !process->Environment) return (char*)0;
|
||||
size_t nameLength = strlen(name);
|
||||
for (char** entry = process->Environment; *entry; ++entry) {
|
||||
if (strncmp(*entry, name, nameLength) == 0 && (*entry)[nameLength] == '=')
|
||||
return *entry + nameLength + 1u;
|
||||
}
|
||||
return (char*)0;
|
||||
}
|
||||
Reference in new issue
Block a user