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
@@ -0,0 +1,476 @@
|
||||
// POSIX signal policy and user-mode dispatch over generic thread APC delivery.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <ntlite/exception.h>
|
||||
#include <ntlite/syscall.h>
|
||||
#include "posix_internal.h"
|
||||
|
||||
// Returns one signal bit after validating its public signal number.
|
||||
static uint64_t PosixSignalBit(int signalNumber) {
|
||||
return NtlPosixSignalValid(signalNumber) ? NTL_POSIX_SIGNAL_BIT(signalNumber) : 0;
|
||||
}
|
||||
|
||||
// Converts the process-local action snapshot into the server's routing view.
|
||||
static uint32_t PosixSignalDisposition(const POSIX_SIGNAL_ACTION_STATE* action) {
|
||||
uintptr_t handler = action ? action->Handler : 0;
|
||||
if (handler == (uintptr_t)SIG_IGN) return NTL_POSIX_SIGNAL_DISPOSITION_IGNORE;
|
||||
if (handler == (uintptr_t)SIG_DFL) return NTL_POSIX_SIGNAL_DISPOSITION_DEFAULT;
|
||||
return NTL_POSIX_SIGNAL_DISPOSITION_CAUGHT;
|
||||
}
|
||||
|
||||
// Sends one signal-control request through the authoritative POSIX server.
|
||||
static KSTATUS PosixSignalCallServer(NTL_POSIX_REQUEST* request, NTL_POSIX_REPLY* reply) {
|
||||
if (!request || !reply) return NTLSTATUS_INVALID_PARAMETER;
|
||||
request->Size = sizeof(*request);
|
||||
request->Version = NTL_POSIX_PROTOCOL_VERSION;
|
||||
request->Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
||||
KSTATUS status = PosixRuntimeCallServer(request, reply);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
return reply->Status;
|
||||
}
|
||||
|
||||
// Applies one caught/default/ignored signal on the current POSIX thread.
|
||||
static int PosixSignalDeliver(POSIX_THREAD_STATE* thread, int signalNumber) {
|
||||
if (!thread || !thread->NativeProcess || !NtlPosixSignalValid(signalNumber)) return 0;
|
||||
uint64_t bit = PosixSignalBit(signalNumber);
|
||||
uint64_t effectiveMask = thread->SignalBlocked | thread->SignalHandlerBlocked;
|
||||
if (signalNumber != SIGKILL && (effectiveMask & bit) != 0) {
|
||||
thread->SignalPending |= bit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
thread->SignalPending &= ~bit;
|
||||
POSIX_SIGNAL_ACTION_STATE* state = &thread->LogicalProcess->SignalActions[signalNumber];
|
||||
uintptr_t handlerValue = state->Handler;
|
||||
if (signalNumber == SIGKILL) handlerValue = (uintptr_t)SIG_DFL;
|
||||
|
||||
if (handlerValue == (uintptr_t)SIG_IGN ||
|
||||
(handlerValue == (uintptr_t)SIG_DFL && signalNumber == SIGCHLD))
|
||||
return 0;
|
||||
if (handlerValue == (uintptr_t)SIG_DFL) {
|
||||
_exit(128 + signalNumber);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t previousHandlerMask = thread->SignalHandlerBlocked;
|
||||
thread->SignalHandlerBlocked = (previousHandlerMask | state->Mask | bit) &
|
||||
NTL_POSIX_SIGNAL_VALID_MASK &
|
||||
~NTL_POSIX_SIGNAL_UNBLOCKABLE_MASK;
|
||||
++thread->SignalDeliveryCount;
|
||||
if (thread->SignalWaitEvent != SYS_HANDLE_INVALID)
|
||||
(void)SysSignalEvent(thread->SignalWaitEvent);
|
||||
((sighandler_t)handlerValue)(signalNumber);
|
||||
thread->SignalHandlerBlocked = previousHandlerMask;
|
||||
PosixSignalDispatchLocalPending(thread);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Maps one personality-neutral native exception class to a POSIX signal.
|
||||
static int PosixSignalForNativeException(uint32_t code) {
|
||||
switch (code) {
|
||||
case SYS_EXCEPTION_CODE_ACCESS_VIOLATION:
|
||||
case SYS_EXCEPTION_CODE_DATATYPE_MISALIGNMENT:
|
||||
case SYS_EXCEPTION_CODE_STACK_OVERFLOW:
|
||||
case SYS_EXCEPTION_CODE_GUARD_PAGE_VIOLATION:
|
||||
return SIGSEGV;
|
||||
case SYS_EXCEPTION_CODE_ILLEGAL_INSTRUCTION:
|
||||
case SYS_EXCEPTION_CODE_PRIVILEGED_INSTRUCTION:
|
||||
return SIGILL;
|
||||
case SYS_EXCEPTION_CODE_INT_DIVIDE_BY_ZERO:
|
||||
case SYS_EXCEPTION_CODE_INT_OVERFLOW:
|
||||
case SYS_EXCEPTION_CODE_FLT_DENORMAL_OPERAND:
|
||||
case SYS_EXCEPTION_CODE_FLT_DIVIDE_BY_ZERO:
|
||||
case SYS_EXCEPTION_CODE_FLT_INEXACT_RESULT:
|
||||
case SYS_EXCEPTION_CODE_FLT_INVALID_OPERATION:
|
||||
case SYS_EXCEPTION_CODE_FLT_OVERFLOW:
|
||||
case SYS_EXCEPTION_CODE_FLT_STACK_CHECK:
|
||||
case SYS_EXCEPTION_CODE_FLT_UNDERFLOW:
|
||||
return SIGFPE;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Translates selected native faults at the POSIX personality boundary.
|
||||
static int PosixSignalNativeException(SYS_EXCEPTION_RECORD* record,
|
||||
SYS_USER_CONTEXT* context,
|
||||
void* userContext) {
|
||||
(void)context;
|
||||
(void)userContext;
|
||||
if (!record) return NTL_EXCEPTION_CONTINUE_SEARCH;
|
||||
int signalNumber = PosixSignalForNativeException(record->Code);
|
||||
if (!signalNumber) return NTL_EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread) return NTL_EXCEPTION_CONTINUE_SEARCH;
|
||||
uint64_t bit = PosixSignalBit(signalNumber);
|
||||
if ((thread->SignalBlocked | thread->SignalHandlerBlocked) & bit)
|
||||
return NTL_EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
POSIX_SIGNAL_ACTION_STATE* state = &thread->LogicalProcess->SignalActions[signalNumber];
|
||||
if (state->Handler == (uintptr_t)SIG_IGN)
|
||||
return NTL_EXCEPTION_CONTINUE_SEARCH;
|
||||
return PosixSignalDeliver(thread, signalNumber)
|
||||
? NTL_EXCEPTION_CONTINUE_EXECUTION
|
||||
: NTL_EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// Installs the native-exception adapter exactly once for one POSIX image.
|
||||
KSTATUS PosixSignalInitializeExceptionTranslation(POSIX_PROCESS_STATE* process) {
|
||||
if (!process) return NTLSTATUS_INVALID_PARAMETER;
|
||||
if (process->ExceptionHandlerHandle) return NTLSTATUS_SUCCESS;
|
||||
void* handle = NtlAddExceptionHandler(1, PosixSignalNativeException, (void*)0);
|
||||
if (!handle) return NTLSTATUS_LIMIT_REACHED;
|
||||
process->ExceptionHandlerHandle = handle;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Delivers one POSIX signal from the generic user-APC substrate.
|
||||
void PosixSignalApc(void* signalValue, void* routeValue, void* reserved) {
|
||||
(void)routeValue;
|
||||
(void)reserved;
|
||||
int signalNumber = (int)(uintptr_t)signalValue;
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread || !NtlPosixSignalValid(signalNumber)) return;
|
||||
PosixSignalDeliver(thread, signalNumber);
|
||||
}
|
||||
|
||||
// Dispatches thread-pending signals made deliverable by a mask change.
|
||||
void PosixSignalDispatchLocalPending(POSIX_THREAD_STATE* thread) {
|
||||
if (!thread) return;
|
||||
for (;;) {
|
||||
uint64_t deliverable = thread->SignalPending &
|
||||
~(thread->SignalBlocked | thread->SignalHandlerBlocked) &
|
||||
NTL_POSIX_SIGNAL_VALID_MASK;
|
||||
deliverable |= thread->SignalPending & NTL_POSIX_SIGNAL_UNBLOCKABLE_MASK;
|
||||
if (deliverable == 0) return;
|
||||
int signalNumber = NTL_POSIX_SIGNAL_HUP;
|
||||
while (signalNumber <= NTL_POSIX_SIGNAL_MAX &&
|
||||
(deliverable & PosixSignalBit(signalNumber)) == 0)
|
||||
++signalNumber;
|
||||
if (signalNumber > NTL_POSIX_SIGNAL_MAX) return;
|
||||
PosixSignalDeliver(thread, signalNumber);
|
||||
}
|
||||
}
|
||||
|
||||
// Initializes an empty signal set.
|
||||
__declspec(dllexport) int sigemptyset(sigset_t* set) {
|
||||
if (!set) { errno = EINVAL; return -1; }
|
||||
*set = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initializes a signal set containing every supported signal.
|
||||
__declspec(dllexport) int sigfillset(sigset_t* set) {
|
||||
if (!set) { errno = EINVAL; return -1; }
|
||||
*set = NTL_POSIX_SIGNAL_VALID_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Adds one signal to a signal set.
|
||||
__declspec(dllexport) int sigaddset(sigset_t* set, int signalNumber) {
|
||||
uint64_t bit = PosixSignalBit(signalNumber);
|
||||
if (!set || bit == 0) { errno = EINVAL; return -1; }
|
||||
*set |= bit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Removes one signal from a signal set.
|
||||
__declspec(dllexport) int sigdelset(sigset_t* set, int signalNumber) {
|
||||
uint64_t bit = PosixSignalBit(signalNumber);
|
||||
if (!set || bit == 0) { errno = EINVAL; return -1; }
|
||||
*set &= ~bit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Tests whether one signal belongs to a signal set.
|
||||
__declspec(dllexport) int sigismember(const sigset_t* set, int signalNumber) {
|
||||
uint64_t bit = PosixSignalBit(signalNumber);
|
||||
if (!set || bit == 0) { errno = EINVAL; return -1; }
|
||||
return (*set & bit) != 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
// Installs or queries one logical-process-wide POSIX signal action.
|
||||
__declspec(dllexport) int sigaction(int signalNumber,
|
||||
const struct sigaction* action,
|
||||
struct sigaction* oldAction) {
|
||||
if (!NtlPosixSignalValid(signalNumber)) { errno = EINVAL; return -1; }
|
||||
POSIX_LOGICAL_PROCESS_STATE* process = PosixRuntimeLogicalProcessState();
|
||||
if (!process) { errno = EIO; return -1; }
|
||||
POSIX_SIGNAL_ACTION_STATE* state = &process->SignalActions[signalNumber];
|
||||
|
||||
if (oldAction) {
|
||||
oldAction->sa_handler = (sighandler_t)state->Handler;
|
||||
oldAction->sa_mask = state->Mask;
|
||||
oldAction->sa_flags = (int)state->Flags;
|
||||
}
|
||||
if (!action) return 0;
|
||||
if (action->sa_flags != 0 || (action->sa_mask & ~NTL_POSIX_SIGNAL_VALID_MASK) != 0 ||
|
||||
action->sa_handler == SIG_ERR ||
|
||||
(signalNumber == SIGKILL && action->sa_handler != SIG_DFL)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
POSIX_SIGNAL_ACTION_STATE previous = *state;
|
||||
state->Handler = (uintptr_t)action->sa_handler;
|
||||
state->Mask = action->sa_mask & ~NTL_POSIX_SIGNAL_UNBLOCKABLE_MASK;
|
||||
state->Flags = (uint32_t)action->sa_flags;
|
||||
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Operation = NTL_POSIX_OP_SET_SIGNAL_DISPOSITION;
|
||||
request.SignalNumber = signalNumber;
|
||||
request.SignalDisposition = PosixSignalDisposition(state);
|
||||
NTL_POSIX_REPLY reply;
|
||||
KSTATUS status = PosixSignalCallServer(&request, &reply);
|
||||
if (!KSUCCESS(status)) {
|
||||
*state = previous;
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Changes the calling thread's persistent POSIX signal mask.
|
||||
__declspec(dllexport) int sigprocmask(int how, const sigset_t* set, sigset_t* oldSet) {
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread) { errno = EIO; return -1; }
|
||||
uint64_t previous = thread->SignalBlocked;
|
||||
if (oldSet) *oldSet = previous;
|
||||
if (!set) return 0;
|
||||
if ((*set & ~NTL_POSIX_SIGNAL_VALID_MASK) != 0 ||
|
||||
(how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t next = previous;
|
||||
if (how == SIG_BLOCK) next |= *set;
|
||||
else if (how == SIG_UNBLOCK) next &= ~*set;
|
||||
else next = *set;
|
||||
next &= NTL_POSIX_SIGNAL_VALID_MASK & ~NTL_POSIX_SIGNAL_UNBLOCKABLE_MASK;
|
||||
thread->SignalBlocked = next;
|
||||
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Operation = NTL_POSIX_OP_UPDATE_SIGNAL_MASK;
|
||||
request.SignalMask = next;
|
||||
NTL_POSIX_REPLY reply;
|
||||
KSTATUS status = PosixSignalCallServer(&request, &reply);
|
||||
if (!KSUCCESS(status)) {
|
||||
thread->SignalBlocked = previous;
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
PosixSignalDispatchLocalPending(thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns the union of calling-thread and process-pending signals.
|
||||
__declspec(dllexport) int sigpending(sigset_t* set) {
|
||||
if (!set) { errno = EINVAL; return -1; }
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread) { errno = EIO; return -1; }
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Operation = NTL_POSIX_OP_GET_PENDING_SIGNALS;
|
||||
NTL_POSIX_REPLY reply;
|
||||
KSTATUS status = PosixSignalCallServer(&request, &reply);
|
||||
if (!KSUCCESS(status)) { errno = PosixStatusToErrno(status); return -1; }
|
||||
*set = (thread->SignalPending | reply.PendingSignals) & NTL_POSIX_SIGNAL_VALID_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Atomically substitutes a temporary mask for the duration of one signal wait.
|
||||
__declspec(dllexport) int sigsuspend(const sigset_t* set) {
|
||||
if (!set || (*set & ~NTL_POSIX_SIGNAL_VALID_MASK) != 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread) { errno = EIO; return -1; }
|
||||
|
||||
SYS_HANDLE event = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = SysCreateEvent(0u, 0u, &event);
|
||||
if (!KSUCCESS(status)) { errno = PosixStatusToErrno(status); return -1; }
|
||||
|
||||
SYS_HANDLE previousEvent = thread->SignalWaitEvent;
|
||||
uint64_t deliveryCount = thread->SignalDeliveryCount;
|
||||
thread->SignalWaitEvent = event;
|
||||
sigset_t previousMask = 0;
|
||||
if (sigprocmask(SIG_SETMASK, set, &previousMask) != 0) {
|
||||
thread->SignalWaitEvent = previousEvent;
|
||||
(void)SysCloseHandle(event);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (thread->SignalDeliveryCount != deliveryCount) {
|
||||
status = NTLSTATUS_SUCCESS;
|
||||
break;
|
||||
}
|
||||
status = SysWait(event, SYS_WAIT_FLAG_ALERTABLE);
|
||||
if (status == NTLSTATUS_SUCCESS && thread->SignalDeliveryCount != deliveryCount)
|
||||
break;
|
||||
if (status == NTLSTATUS_USER_APC || status == NTLSTATUS_KERNEL_APC ||
|
||||
status == NTLSTATUS_ALERTED)
|
||||
continue;
|
||||
if (!KSUCCESS(status)) break;
|
||||
}
|
||||
|
||||
thread->SignalWaitEvent = previousEvent;
|
||||
int restore = sigprocmask(SIG_SETMASK, &previousMask, (sigset_t*)0);
|
||||
(void)SysCloseHandle(event);
|
||||
if (restore != 0) return -1;
|
||||
if (!KSUCCESS(status)) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Sends one signal through stable POSIX process or process-group identity.
|
||||
__declspec(dllexport) int kill(pid_t pid, int signalNumber) {
|
||||
if (signalNumber < 0 || signalNumber > NTL_POSIX_SIGNAL_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Operation = NTL_POSIX_OP_SEND_SIGNAL;
|
||||
request.SignalTargetPid = (int32_t)pid;
|
||||
request.SignalNumber = signalNumber;
|
||||
NTL_POSIX_REPLY reply;
|
||||
KSTATUS status = PosixSignalCallServer(&request, &reply);
|
||||
if (!KSUCCESS(status)) {
|
||||
if (status == NTLSTATUS_NOT_FOUND) errno = ESRCH;
|
||||
else if (status == NTLSTATUS_ACCESS_DENIED) errno = EPERM;
|
||||
else errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Replaces the process alarm and returns the rounded-up previous remaining interval.
|
||||
__declspec(dllexport) unsigned int alarm(unsigned int seconds) {
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Operation = NTL_POSIX_OP_SET_ALARM;
|
||||
request.AlarmSeconds = seconds;
|
||||
NTL_POSIX_REPLY reply;
|
||||
KSTATUS status = PosixSignalCallServer(&request, &reply);
|
||||
if (!KSUCCESS(status)) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return 0;
|
||||
}
|
||||
return reply.AlarmRemainingSeconds;
|
||||
}
|
||||
|
||||
// Waits until one caught signal runs.
|
||||
__declspec(dllexport) int pause(void) {
|
||||
sigset_t mask = 0;
|
||||
if (sigprocmask(SIG_SETMASK, (const sigset_t*)0, &mask) != 0) return -1;
|
||||
return sigsuspend(&mask);
|
||||
}
|
||||
|
||||
// Sleeps on a native waitable timer and reports whole seconds left after a caught signal.
|
||||
__declspec(dllexport) unsigned int sleep(unsigned int seconds) {
|
||||
if (seconds == 0) {
|
||||
(void)SysYield();
|
||||
return 0;
|
||||
}
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread) return seconds;
|
||||
|
||||
SYS_HANDLE timer = SYS_HANDLE_INVALID;
|
||||
SYS_HANDLE signalEvent = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = SysCreateTimer(&timer);
|
||||
if (!KSUCCESS(status)) return seconds;
|
||||
status = SysCreateEvent(0u, 0u, &signalEvent);
|
||||
if (!KSUCCESS(status)) { (void)SysCloseHandle(timer); return seconds; }
|
||||
|
||||
uint64_t frequency = 0;
|
||||
status = SysGetTickFrequency(&frequency);
|
||||
if (!KSUCCESS(status) || frequency == 0) {
|
||||
(void)SysCloseHandle(signalEvent);
|
||||
(void)SysCloseHandle(timer);
|
||||
return seconds;
|
||||
}
|
||||
uint64_t start = SysGetTick();
|
||||
|
||||
SYS_SET_TIMER_REQUEST setTimer;
|
||||
memset(&setTimer, 0, sizeof(setTimer));
|
||||
setTimer.Size = sizeof(setTimer);
|
||||
setTimer.TimerHandle = timer;
|
||||
setTimer.Flags = SYS_TIMER_FLAG_NONE;
|
||||
setTimer.DueTimeMilliseconds = (uint64_t)seconds * 1000u;
|
||||
status = SysSetTimer(&setTimer);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)SysCloseHandle(signalEvent);
|
||||
(void)SysCloseHandle(timer);
|
||||
return seconds;
|
||||
}
|
||||
|
||||
SYS_HANDLE previousEvent = thread->SignalWaitEvent;
|
||||
uint64_t deliveryCount = thread->SignalDeliveryCount;
|
||||
thread->SignalWaitEvent = signalEvent;
|
||||
SYS_HANDLE waits[2] = { timer, signalEvent };
|
||||
uint32_t selected = UINT32_MAX;
|
||||
SYS_WAIT_MANY_REQUEST wait;
|
||||
memset(&wait, 0, sizeof(wait));
|
||||
wait.Size = sizeof(wait);
|
||||
wait.Flags = SYS_WAIT_FLAG_ALERTABLE;
|
||||
wait.Handles = waits;
|
||||
wait.Count = 2u;
|
||||
wait.SignaledIndexOut = &selected;
|
||||
wait.TimeoutMilliseconds = SYS_WAIT_TIMEOUT_INFINITE;
|
||||
for (;;) {
|
||||
selected = UINT32_MAX;
|
||||
status = SysWaitMany(&wait);
|
||||
if (status == NTLSTATUS_SUCCESS && selected == 0u) break;
|
||||
if (thread->SignalDeliveryCount != deliveryCount) break;
|
||||
if (status == NTLSTATUS_SUCCESS || status == NTLSTATUS_USER_APC ||
|
||||
status == NTLSTATUS_KERNEL_APC || status == NTLSTATUS_ALERTED)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
thread->SignalWaitEvent = previousEvent;
|
||||
|
||||
uint64_t elapsedTicks = SysGetTick() - start;
|
||||
uint64_t elapsedMs = SysTicksToMilliseconds(elapsedTicks, frequency);
|
||||
uint64_t totalMs = (uint64_t)seconds * 1000u;
|
||||
uint64_t remainingMs = elapsedMs < totalMs ? totalMs - elapsedMs : 0;
|
||||
unsigned int remaining = (unsigned int)((remainingMs + 999u) / 1000u);
|
||||
|
||||
(void)SysCancelTimer(timer);
|
||||
(void)SysCloseHandle(signalEvent);
|
||||
(void)SysCloseHandle(timer);
|
||||
if (status == NTLSTATUS_SUCCESS && selected == 0u) return 0;
|
||||
if (thread->SignalDeliveryCount != deliveryCount) return remaining;
|
||||
return remaining ? remaining : seconds;
|
||||
}
|
||||
|
||||
// Installs the historical one-argument signal disposition API.
|
||||
__declspec(dllexport) sighandler_t signal(int signalNumber, sighandler_t handler) {
|
||||
struct sigaction action;
|
||||
struct sigaction previous;
|
||||
action.sa_handler = handler;
|
||||
action.sa_mask = 0;
|
||||
action.sa_flags = 0;
|
||||
if (sigaction(signalNumber, &action, &previous) != 0) return SIG_ERR;
|
||||
return previous.sa_handler;
|
||||
}
|
||||
|
||||
// Raises one signal on the calling POSIX thread.
|
||||
__declspec(dllexport) int raise(int signalNumber) {
|
||||
if (!NtlPosixSignalValid(signalNumber)) { errno = EINVAL; return -1; }
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread) { errno = EIO; return -1; }
|
||||
PosixSignalDeliver(thread, signalNumber);
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user