494 lines
12 KiB
C
494 lines
12 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
sigsup.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This provides support routines to implement signal delivery and dispatch.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Mark Lucovsky (markl) 30-Mar-1989
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "psxsrv.h"
|
|||
|
#define PENDING_SIGKILL (1<<SIGKILL)
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PendingSignalHandledInside(
|
|||
|
IN PPSX_PROCESS p,
|
|||
|
IN PPSX_API_MSG m,
|
|||
|
IN sigset_t *RestoreBlockSigset OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This procedure is called on system exit prior to reply generation. Its
|
|||
|
purpose is to test for the presence of pending signals, and if found, to
|
|||
|
process the signal.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
p - Supplies the address of the process to be checked.
|
|||
|
|
|||
|
m - Supplies the address of the process' current message.
|
|||
|
|
|||
|
RestoreBlockSigset - Supplies an optional blocked signal mask that
|
|||
|
should be restored after the signal completes
|
|||
|
|
|||
|
Locks - Process lock is released upon return.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - A pending signal was discovered that required extra time in the
|
|||
|
system, or the signal action caused the process to terminate. The
|
|||
|
process will be unlocked by this call, and no reply should be
|
|||
|
generated.
|
|||
|
|
|||
|
FALSE - Either no pending signals were found, or a pending signal was
|
|||
|
processed. The contents of *m should be used to generate a reply.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
sigset_t Pending;
|
|||
|
ULONG Signal;
|
|||
|
ULONG SigAsMask;
|
|||
|
|
|||
|
AcquireProcessLock(p);
|
|||
|
|
|||
|
Pending = p->SignalDataBase.PendingSignalMask &
|
|||
|
~p->SignalDataBase.BlockedSignalMask;
|
|||
|
|
|||
|
if (!Pending) {
|
|||
|
//
|
|||
|
// Fast Path. Not pending, unblocked signals
|
|||
|
//
|
|||
|
|
|||
|
ReleaseProcessLock(p);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Pending, Non-Blocked signals discovered
|
|||
|
//
|
|||
|
|
|||
|
for (Signal = 1, SigAsMask = 1;
|
|||
|
Signal <= _SIGMAXSIGNO;
|
|||
|
Signal++, SigAsMask <<= 1L) {
|
|||
|
|
|||
|
if (Pending & SigAsMask) {
|
|||
|
|
|||
|
//
|
|||
|
// Make sure that if a SIGKILL is pending, the process is killed !
|
|||
|
//
|
|||
|
|
|||
|
if (Pending & PENDING_SIGKILL) {
|
|||
|
SigAsMask = PENDING_SIGKILL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Clear the signal
|
|||
|
//
|
|||
|
|
|||
|
p->SignalDataBase.PendingSignalMask &= ~SigAsMask;
|
|||
|
|
|||
|
switch ((ULONG_PTR)p->SignalDataBase.SignalDisposition[Signal-1].sa_handler) {
|
|||
|
|
|||
|
case (ULONG_PTR)SIG_IGN:
|
|||
|
|
|||
|
//
|
|||
|
// If signal is being ignored, then simply clearing its
|
|||
|
// pending bit "handles" the signal
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case (ULONG_PTR)SIG_DFL:
|
|||
|
|
|||
|
//
|
|||
|
// Do the default action associated with the signal
|
|||
|
//
|
|||
|
|
|||
|
switch (Signal) {
|
|||
|
|
|||
|
case SIGABRT:
|
|||
|
case SIGALRM:
|
|||
|
case SIGFPE:
|
|||
|
case SIGHUP:
|
|||
|
case SIGILL:
|
|||
|
case SIGINT:
|
|||
|
case SIGKILL:
|
|||
|
case SIGPIPE:
|
|||
|
case SIGQUIT:
|
|||
|
case SIGSEGV:
|
|||
|
case SIGTERM:
|
|||
|
case SIGUSR1:
|
|||
|
case SIGUSR2:
|
|||
|
|
|||
|
//
|
|||
|
// Terminate Process. No reply will be generated. API Port
|
|||
|
// can be closed in terminate process.
|
|||
|
//
|
|||
|
|
|||
|
ReleaseProcessLock(p);
|
|||
|
PsxTerminateProcessBySignal(p, m, Signal);
|
|||
|
return TRUE;
|
|||
|
|
|||
|
case SIGCHLD:
|
|||
|
|
|||
|
//
|
|||
|
// Default is to ignore this signal. Simply clear from
|
|||
|
// pending mask.
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case SIGSTOP:
|
|||
|
PsxStopProcess(p, m, SIGSTOP, RestoreBlockSigset);
|
|||
|
return TRUE;
|
|||
|
|
|||
|
case SIGTSTP:
|
|||
|
case SIGTTIN:
|
|||
|
case SIGTTOU:
|
|||
|
|
|||
|
if (PsxStopProcess(p, m, Signal, RestoreBlockSigset)) {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
AcquireProcessLock(p);
|
|||
|
break;
|
|||
|
|
|||
|
case SIGCONT:
|
|||
|
//
|
|||
|
// Since process can not be active, and stopped at the same
|
|||
|
// time, a pending SIGCONT means that process is not
|
|||
|
// stopped so simply ignore the signal.
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
Panic("Unknown Pending Signal");
|
|||
|
break;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
//
|
|||
|
// Signal is being caught
|
|||
|
//
|
|||
|
|
|||
|
if ((Signal == SIGKILL) || (Signal == SIGSTOP)) {
|
|||
|
Panic("Catching SIGKILL or SIGSTOP");
|
|||
|
}
|
|||
|
|
|||
|
if (m->Signal == SIGCONT) {
|
|||
|
// When a signal is being caught, we should
|
|||
|
// EINTR out.
|
|||
|
|
|||
|
m->Signal = SIGALRM;
|
|||
|
}
|
|||
|
|
|||
|
PsxDeliverSignal(p,Signal,RestoreBlockSigset);
|
|||
|
ReleaseProcessLock(p);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ReleaseProcessLock(p);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
PsxCheckPendingSignals(
|
|||
|
IN PPSX_PROCESS p
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This procedure is called from BlockProcess to see if the block should
|
|||
|
proceed, or if the block should be aborted due to a signal.
|
|||
|
|
|||
|
This function is called with the process locked.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
p - Supplies the address of the process to be checked.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns the number of the last pending signal, or 0 if there were no
|
|||
|
pending signals.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
sigset_t Pending;
|
|||
|
ULONG Signal;
|
|||
|
ULONG SigAsMask;
|
|||
|
int ReturnSignal = 0;
|
|||
|
|
|||
|
Pending = p->SignalDataBase.PendingSignalMask &
|
|||
|
~p->SignalDataBase.BlockedSignalMask;
|
|||
|
|
|||
|
if (!Pending) {
|
|||
|
return 0; // no pending, unblocked signals
|
|||
|
}
|
|||
|
|
|||
|
for(Signal = 1, SigAsMask = 1; Signal <= _SIGMAXSIGNO;
|
|||
|
Signal++, SigAsMask <<= 1L) {
|
|||
|
if (!(Pending & SigAsMask)) {
|
|||
|
continue; // this signal is not pending
|
|||
|
}
|
|||
|
|
|||
|
switch ((ULONG_PTR)p->SignalDataBase.SignalDisposition[Signal - 1].sa_handler) {
|
|||
|
case (ULONG_PTR)SIG_IGN:
|
|||
|
|
|||
|
//
|
|||
|
// If signal is being ignored, then simply
|
|||
|
// clearing its pending bit "handles" the
|
|||
|
// signal.
|
|||
|
//
|
|||
|
|
|||
|
p->SignalDataBase.PendingSignalMask &=
|
|||
|
~SigAsMask;
|
|||
|
break;
|
|||
|
|
|||
|
case (ULONG_PTR)SIG_DFL:
|
|||
|
|
|||
|
switch (Signal) {
|
|||
|
case SIGABRT:
|
|||
|
case SIGALRM:
|
|||
|
case SIGFPE:
|
|||
|
case SIGHUP:
|
|||
|
case SIGILL:
|
|||
|
case SIGINT:
|
|||
|
case SIGKILL:
|
|||
|
case SIGPIPE:
|
|||
|
case SIGQUIT:
|
|||
|
case SIGSEGV:
|
|||
|
case SIGTERM:
|
|||
|
case SIGUSR1:
|
|||
|
case SIGUSR2:
|
|||
|
|
|||
|
//
|
|||
|
// The default action is to terminate. Don't
|
|||
|
// let the block proceed.
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case SIGCHLD:
|
|||
|
|
|||
|
//
|
|||
|
// Default is to ignore this signal. Clear
|
|||
|
// from pending mask.
|
|||
|
//
|
|||
|
|
|||
|
p->SignalDataBase.PendingSignalMask &=
|
|||
|
~SigAsMask;
|
|||
|
continue;
|
|||
|
|
|||
|
case SIGSTOP:
|
|||
|
case SIGTSTP:
|
|||
|
case SIGTTIN:
|
|||
|
case SIGTTOU:
|
|||
|
//
|
|||
|
// Default action is to stop process. Don't
|
|||
|
// allow the process to be blocked.
|
|||
|
//
|
|||
|
break;
|
|||
|
|
|||
|
case SIGCONT:
|
|||
|
//
|
|||
|
// SIGCONT is defaulted; the action is to
|
|||
|
// continue if stopped, ignore otherwise.
|
|||
|
// Here we suspect that the process is being
|
|||
|
// blocked, so we prevent that from happening.
|
|||
|
//
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
Panic("Unknown Pending Signal");
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
ReturnSignal = Signal;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
//
|
|||
|
// This signal is handled.
|
|||
|
//
|
|||
|
|
|||
|
ReturnSignal = Signal;
|
|||
|
}
|
|||
|
}
|
|||
|
return ReturnSignal;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PsxDeliverSignal(
|
|||
|
IN PPSX_PROCESS p,
|
|||
|
IN ULONG Signal,
|
|||
|
IN sigset_t *RestoreBlockSigset OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is used to deliver a signal to a process.
|
|||
|
This function is only called from PendingSignalHandledInside. It
|
|||
|
can safely assume that the target process is inside Psx.
|
|||
|
|
|||
|
This function is called with the process locked.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
p - Supplies the address of the process to be signaled
|
|||
|
|
|||
|
Signal - Supplies the index of the signal to be delivered to the
|
|||
|
process
|
|||
|
|
|||
|
RestoreBlockSigset - Supplies an optional blocked signal mask that
|
|||
|
should be restored after the signal completes
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS st;
|
|||
|
sigset_t PreviousBlockMask;
|
|||
|
ULONG_PTR Args[3];
|
|||
|
|
|||
|
|
|||
|
PreviousBlockMask = ARGUMENT_PRESENT(RestoreBlockSigset) ?
|
|||
|
*RestoreBlockSigset :
|
|||
|
p->SignalDataBase.BlockedSignalMask;
|
|||
|
|
|||
|
//
|
|||
|
// 1003.1-90 (3.3.4.2) -- When a signal is caught ... [the]
|
|||
|
// mask is formed by taking the union of the current signal
|
|||
|
// mask and the value of the sa_mask for the signal being
|
|||
|
// delivered, and then including the signal being delivered.
|
|||
|
//
|
|||
|
|
|||
|
p->SignalDataBase.BlockedSignalMask |=
|
|||
|
p->SignalDataBase.SignalDisposition[Signal-1].sa_mask;
|
|||
|
|
|||
|
SIGADDSET(&p->SignalDataBase.BlockedSignalMask, Signal);
|
|||
|
|
|||
|
//
|
|||
|
// Arrange for call to signal deliverer
|
|||
|
//
|
|||
|
// r5 = PreviousBlockMask
|
|||
|
// r6 = Signal
|
|||
|
// r7 = Handler
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// XXX.mjb: this code seems to fix problems in the MIPS
|
|||
|
// PP/signal_con test... I can't imagine why.
|
|||
|
//
|
|||
|
LARGE_INTEGER DelayInterval;
|
|||
|
|
|||
|
DelayInterval.HighPart = 0;
|
|||
|
DelayInterval.LowPart = 0;
|
|||
|
|
|||
|
NtDelayExecution(TRUE, &DelayInterval);
|
|||
|
}
|
|||
|
|
|||
|
Args[0] = (ULONG)PreviousBlockMask;
|
|||
|
Args[1] = (ULONG)Signal;
|
|||
|
Args[2] = (ULONG_PTR)(p->SignalDataBase.SignalDisposition[Signal-1].sa_handler);
|
|||
|
|
|||
|
st = RtlRemoteCall(
|
|||
|
p->Process,
|
|||
|
p->Thread,
|
|||
|
(PVOID)p->SignalDeliverer,
|
|||
|
3,
|
|||
|
Args,
|
|||
|
TRUE,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(st)) {
|
|||
|
KdPrint(("PSXSS: PsxDeliverSignal: RtlRemoteCall: 0x%x\n", st));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PsxSigSuspendHandler(
|
|||
|
IN PPSX_PROCESS p,
|
|||
|
IN PINTCB IntControlBlock,
|
|||
|
IN PSX_INTERRUPTREASON InterruptReason,
|
|||
|
IN int Signal // Signal interrupting, if any
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This procedure is called when a signal is generated that should pop a
|
|||
|
process out of a sigsuspend system call. The procedure is called with the
|
|||
|
process locked. The main purpose of this function is to restore the
|
|||
|
blocked signal mask to its original value, deallocate the interrupt control
|
|||
|
block, and reply to the original call to sigsuspend. During the reply, the
|
|||
|
generated signal will be deliverd, or will cause the process to terminate.
|
|||
|
|
|||
|
This function is responsible for unlocking the process.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
p - Supplies the address of the process being interrupted.
|
|||
|
|
|||
|
IntControlBlock - Supplies the address of the interrupt control block.
|
|||
|
|
|||
|
InterruptReason - Supplies the reason that this process is being
|
|||
|
interrupted. Not used in this handler.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PPSX_API_MSG m;
|
|||
|
sigset_t RestoreBlockSigset;
|
|||
|
|
|||
|
RtlLeaveCriticalSection(&BlockLock);
|
|||
|
|
|||
|
RestoreBlockSigset = (sigset_t)((ULONG_PTR)IntControlBlock->IntContext);
|
|||
|
|
|||
|
m = IntControlBlock->IntMessage;
|
|||
|
RtlFreeHeap(PsxHeap, 0,IntControlBlock);
|
|||
|
|
|||
|
m->Error = EINTR;
|
|||
|
m->Signal = Signal;
|
|||
|
ApiReply(p, m, &RestoreBlockSigset);
|
|||
|
RtlFreeHeap(PsxHeap, 0, m);
|
|||
|
}
|