430 lines
8.8 KiB
C
430 lines
8.8 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
sigapi.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements all signal oriented APIs.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Mark Lucovsky (markl) 30-Mar-1989
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "psxsrv.h"
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PsxSigAction (
|
|||
|
IN PPSX_PROCESS p,
|
|||
|
IN OUT PPSX_API_MSG m
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This procedure implements POSIX sigaction
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
p - Supplies the address of the process making the call.
|
|||
|
|
|||
|
m - Supplies the address of the message associated with the open request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - The contens of *m should be used to generate a reply.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PPSX_SIGACTION_MSG args;
|
|||
|
|
|||
|
args = &m->u.SigAction;
|
|||
|
|
|||
|
//
|
|||
|
// Validate Signal
|
|||
|
//
|
|||
|
|
|||
|
if ( !ISSIGNOINRANGE(args->Sig) || args->Sig <= 0 ) {
|
|||
|
m->Error = EINVAL;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(args->ActSpecified) ) {
|
|||
|
|
|||
|
//
|
|||
|
// Since call is attempting to set a signal action, fail if:
|
|||
|
// attemping to catch a signal that cant be caught
|
|||
|
// SIGKILL, SIGSTOP
|
|||
|
// attemping to ignore a signal that cant be ignored
|
|||
|
// SIGKILL, SIGSTOP
|
|||
|
//
|
|||
|
// SIGKILL and SIGSTOP can only be set to SIG_DFL !
|
|||
|
//
|
|||
|
|
|||
|
if ( ((args->Sig == SIGKILL) || (args->Sig == SIGSTOP)) &&
|
|||
|
(args->Act.sa_handler != (_handler) SIG_DFL) ) {
|
|||
|
|
|||
|
m->Error = EINVAL;
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Clear SIGKILL and SIGSTOP from the new block
|
|||
|
// mask without causing an error
|
|||
|
//
|
|||
|
|
|||
|
SIGDELSET(&args->Act.sa_mask, SIGKILL);
|
|||
|
SIGDELSET(&args->Act.sa_mask, SIGSTOP);
|
|||
|
args->Act.sa_mask &= _SIGFULLSET;
|
|||
|
|
|||
|
AcquireProcessLock(p);
|
|||
|
|
|||
|
args->Oact = p->SignalDataBase.SignalDisposition[args->Sig-1];
|
|||
|
p->SignalDataBase.SignalDisposition[args->Sig-1] = args->Act;
|
|||
|
|
|||
|
if (SIGISMEMBER(&p->SignalDataBase.PendingSignalMask, args->Sig) ) {
|
|||
|
|
|||
|
//
|
|||
|
// Signal whose action is being changed is pending.
|
|||
|
//
|
|||
|
// If signal iction is being set to ignored, or if being set to
|
|||
|
// default action, and default action is to ignore the signal,
|
|||
|
// then clear the signal from the set of pending signals.
|
|||
|
//
|
|||
|
|
|||
|
if ( (args->Act.sa_handler == SIG_IGN) ||
|
|||
|
((args->Act.sa_handler == SIG_DFL) && (args->Sig == SIGCHLD)) ) {
|
|||
|
|
|||
|
SIGDELSET(&p->SignalDataBase.PendingSignalMask, args->Sig);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ReleaseProcessLock(p);
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
AcquireProcessLock(p);
|
|||
|
|
|||
|
args->Oact = p->SignalDataBase.SignalDisposition[args->Sig-1];
|
|||
|
|
|||
|
ReleaseProcessLock(p);
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PsxSigProcMask(
|
|||
|
IN PPSX_PROCESS p,
|
|||
|
IN PPSX_API_MSG m
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This procedure implements POSIX sigaction
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
p - Supplies the address of the process making the call.
|
|||
|
|
|||
|
m - Supplies the address of the message associated with the open request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - The contens of *m should be used to generate a reply.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PPSX_SIGPROCMASK_MSG args;
|
|||
|
|
|||
|
args = &m->u.SigProcMask;
|
|||
|
|
|||
|
AcquireProcessLock(p);
|
|||
|
|
|||
|
args->Oset = p->SignalDataBase.BlockedSignalMask;
|
|||
|
|
|||
|
if ( ARGUMENT_PRESENT(args->SetSpecified) ) {
|
|||
|
|
|||
|
switch (args->How) {
|
|||
|
|
|||
|
case SIG_BLOCK:
|
|||
|
|
|||
|
p->SignalDataBase.BlockedSignalMask |= args->Set;
|
|||
|
break;
|
|||
|
|
|||
|
case SIG_UNBLOCK:
|
|||
|
|
|||
|
p->SignalDataBase.BlockedSignalMask &= ~args->Set;
|
|||
|
break;
|
|||
|
|
|||
|
case SIG_SETMASK:
|
|||
|
|
|||
|
p->SignalDataBase.BlockedSignalMask = args->Set;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
m->Error = EINVAL;
|
|||
|
ReleaseProcessLock(p);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
SIGDELSET(&p->SignalDataBase.BlockedSignalMask,SIGKILL);
|
|||
|
SIGDELSET(&p->SignalDataBase.BlockedSignalMask,SIGSTOP);
|
|||
|
}
|
|||
|
|
|||
|
ReleaseProcessLock(p);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PsxSigPending(
|
|||
|
IN PPSX_PROCESS p,
|
|||
|
IN PPSX_API_MSG m
|
|||
|
)
|
|||
|
{
|
|||
|
PPSX_SIGPENDING_MSG args;
|
|||
|
|
|||
|
args = &m->u.SigPending;
|
|||
|
|
|||
|
args->Set = p->SignalDataBase.PendingSignalMask;
|
|||
|
m->Error = 0;
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PsxSigSuspend(
|
|||
|
IN PPSX_PROCESS p,
|
|||
|
IN PPSX_API_MSG m
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This procedure implements POSIX sigsuspend
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
p - Supplies the address of the process making the call.
|
|||
|
|
|||
|
m - Supplies the address of the message associated with the request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE - A reply will not be generated until a signal is generated that
|
|||
|
either terminates the process or is delivered to the process.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PPSX_SIGSUSPEND_MSG args;
|
|||
|
sigset_t NewBlockMask;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
args = &m->u.SigSuspend;
|
|||
|
|
|||
|
AcquireProcessLock(p);
|
|||
|
|
|||
|
NewBlockMask = p->SignalDataBase.BlockedSignalMask;
|
|||
|
|
|||
|
//
|
|||
|
// For sigsuspend, sigmask is specified; otherwise, the current
|
|||
|
// blocked signal mask is used
|
|||
|
//
|
|||
|
|
|||
|
if ( args->SigMaskSpecified ) {
|
|||
|
p->SignalDataBase.BlockedSignalMask = args->SigMask;
|
|||
|
}
|
|||
|
|
|||
|
SIGDELSET(&p->SignalDataBase.BlockedSignalMask,SIGKILL);
|
|||
|
SIGDELSET(&p->SignalDataBase.BlockedSignalMask,SIGSTOP);
|
|||
|
|
|||
|
ReleaseProcessLock(p);
|
|||
|
|
|||
|
Status = BlockProcess(p, (PVOID)NewBlockMask, PsxSigSuspendHandler,
|
|||
|
m, FALSE, NULL);
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
m->Error = PsxStatusToErrno(Status);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The process was blocked -- don't reply to the api request yet.
|
|||
|
//
|
|||
|
return FALSE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PsxNull (
|
|||
|
IN PPSX_PROCESS p,
|
|||
|
IN OUT PPSX_API_MSG m
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The null system service. This service is used to get a process to
|
|||
|
look at its pending signals.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
p - Supplies the address of the process making the call.
|
|||
|
|
|||
|
m - Supplies the address of the message associated with the request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - The contens of *m should be used to generate a reply.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// The process may fork again.
|
|||
|
//
|
|||
|
|
|||
|
p->Flags &= ~P_NO_FORK;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PsxKill(
|
|||
|
IN PPSX_PROCESS p,
|
|||
|
IN PPSX_API_MSG m
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function implements posix kill().
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
p - Supplies the address of the calling process
|
|||
|
|
|||
|
m - Supplies the address of the related message
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - Always succeeds and generates a reply
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PPSX_KILL_MSG args;
|
|||
|
PPSX_PROCESS cp;
|
|||
|
BOOLEAN SignalSent;
|
|||
|
pid_t TargetGroup;
|
|||
|
|
|||
|
args = &m->u.Kill;
|
|||
|
|
|||
|
if ( ! ISSIGNOINRANGE(args->Sig) ) {
|
|||
|
m->Error = EINVAL;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if ( args->Pid < 0 && args->Pid != -1 ) {
|
|||
|
|
|||
|
TargetGroup = args->Pid * -1;
|
|||
|
} else {
|
|||
|
TargetGroup = 0;
|
|||
|
}
|
|||
|
|
|||
|
SignalSent = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Lock the process table so that we can scan process table.
|
|||
|
//
|
|||
|
|
|||
|
AcquireProcessStructureLock();
|
|||
|
|
|||
|
//
|
|||
|
// Scan process table looking for pid
|
|||
|
//
|
|||
|
|
|||
|
for (cp = FirstProcess; cp < LastProcess; cp++) {
|
|||
|
|
|||
|
//
|
|||
|
// Only look at non-free slots
|
|||
|
//
|
|||
|
|
|||
|
if (cp->Flags & P_FREE) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (args->Pid > 0) {
|
|||
|
|
|||
|
//
|
|||
|
// Send signal to process whose Pid is args->Pid
|
|||
|
//
|
|||
|
|
|||
|
if (cp->Pid == args->Pid) {
|
|||
|
PsxSignalProcess(cp, args->Sig);
|
|||
|
SignalSent = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
if (args->Pid == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// Send signal to all processes whose process group id
|
|||
|
// matches the caller
|
|||
|
//
|
|||
|
|
|||
|
if (cp->ProcessGroupId == p->ProcessGroupId) {
|
|||
|
PsxSignalProcess(cp, args->Sig);
|
|||
|
SignalSent = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
if (args->Pid == -1) {
|
|||
|
|
|||
|
//
|
|||
|
// Posix does not define this.
|
|||
|
//
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (TargetGroup) {
|
|||
|
|
|||
|
//
|
|||
|
// Send signal to all processes whose process group id
|
|||
|
// matches the absolute value of args->Pid
|
|||
|
//
|
|||
|
|
|||
|
if ( cp->ProcessGroupId == TargetGroup ) {
|
|||
|
PsxSignalProcess(cp, args->Sig);
|
|||
|
SignalSent = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!SignalSent) {
|
|||
|
m->Error = ESRCH;
|
|||
|
}
|
|||
|
|
|||
|
ReleaseProcessStructureLock();
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|