478 lines
18 KiB
C
478 lines
18 KiB
C
// POSIX signal policy and user-mode dispatch over generic thread APC delivery.
|
|
|
|
#include <stdbool.h>
|
|
#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 bool PosixSignalDeliver(POSIX_THREAD_STATE* thread, int signalNumber) {
|
|
if (!thread || !thread->NativeProcess || !NtlPosixSignalValid(signalNumber)) return false;
|
|
uint64_t bit = PosixSignalBit(signalNumber);
|
|
uint64_t effectiveMask = thread->SignalBlocked | thread->SignalHandlerBlocked;
|
|
if (signalNumber != SIGKILL && (effectiveMask & bit) != 0) {
|
|
thread->SignalPending |= bit;
|
|
return false;
|
|
}
|
|
|
|
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 false;
|
|
if (handlerValue == (uintptr_t)SIG_DFL) {
|
|
_exit(128 + signalNumber);
|
|
return true;
|
|
}
|
|
|
|
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 true;
|
|
}
|
|
|
|
// 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 uint32_t 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;
|
|
}
|