/*++ 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<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); }