Source to mint/dossig.c
/*
Copyright 1990,1991,1992,1994 Eric R. Smith.
All rights reserved.
*/
/* dossig.c:: dos signal handling routines */
#include "mint.h"
void ARGS_ON_STACK sig_user P_((int vec));
/*
* send a signal to another process. If pid > 0, send the signal just to
* that process. If pid < 0, send the signal to all processes whose process
* group is -pid. If pid == 0, send the signal to all processes with the
* same process group id.
*
* note: post_sig just posts the signal to the process.
*/
long ARGS_ON_STACK
p_kill(pid, sig)
int pid, sig;
{
PROC *p;
long r;
TRACE(("Pkill(%d, %d)", pid, sig));
if (sig < 0 || sig >= NSIG) {
DEBUG(("Pkill: signal out of range"));
return ERANGE;
}
if (pid < 0)
r = killgroup(-pid, sig, 0);
else if (pid == 0)
r = killgroup(curproc->pgrp, sig, 0);
else {
p = pid2proc(pid);
if (p == 0 || p->wait_q == ZOMBIE_Q || p->wait_q == TSR_Q) {
DEBUG(("Pkill: pid %d not found", pid));
return EFILNF;
}
if (curproc->euid && curproc->ruid != p->ruid) {
DEBUG(("Pkill: wrong user"));
return EACCDN;
}
/* if the user sends signal 0, don't deliver it -- for users, signal
* 0 is a null signal used to test the existence of a process
*/
if (sig != 0)
post_sig(p, sig);
r = 0;
}
if (r == 0) {
check_sigs();
TRACE(("Pkill: returning OK"));
}
return r;
}
/*
* set a user-specified signal handler, POSIX.1 style
* "oact", if non-null, gets the old signal handling
* behaviour; "act", if non-null, specifies new
* behaviour
*/
long ARGS_ON_STACK
p_sigaction(sig, act, oact)
int sig;
const struct sigaction *act;
struct sigaction *oact;
{
TRACE(("Psigaction(%d)", sig));
if (sig < 1 || sig >= NSIG)
return ERANGE;
if (act && (sig == SIGKILL || sig == SIGSTOP))
return EACCDN;
if (oact) {
oact->sa_handler = curproc->sighandle[sig];
oact->sa_mask = curproc->sigextra[sig];
oact->sa_flags = curproc->sigflags[sig] & SAUSER;
}
if (act) {
ushort flags;
curproc->sighandle[sig] = act->sa_handler;
curproc->sigextra[sig] = act->sa_mask & ~UNMASKABLE;
/* only the flags in SAUSER can be changed by the user */
flags = curproc->sigflags[sig] & ~SAUSER;
flags |= act->sa_flags & SAUSER;
curproc->sigflags[sig] = flags;
/* various special things that should happen */
if (act->sa_handler == SIG_IGN) {
/* discard pending signals */
curproc->sigpending &= ~(1L<<sig);
}
/* I dunno if this is right, but bash seems to expect it */
curproc->sigmask &= ~(1L<<sig);
}
return 0;
}
/*
* set a user-specified signal handler
*/
long ARGS_ON_STACK
p_signal(sig, handler)
int sig;
long handler;
{
long oldhandle;
TRACE(("Psignal(%d, %lx)", sig, handler));
if (sig < 1 || sig >= NSIG)
return ERANGE;
if (sig == SIGKILL || sig == SIGSTOP)
return EACCDN;
oldhandle = curproc->sighandle[sig];
curproc->sighandle[sig] = handler;
curproc->sigextra[sig] = 0;
curproc->sigflags[sig] = 0;
/* various special things that should happen */
if (handler == SIG_IGN) {
/* discard pending signals */
curproc->sigpending &= ~(1L<<sig);
}
/* I dunno if this is right, but bash seems to expect it */
curproc->sigmask &= ~(1L<<sig);
return oldhandle;
}
/*
* block some signals. Returns the old signal mask.
*/
long ARGS_ON_STACK
p_sigblock(mask)
ulong mask;
{
ulong oldmask;
TRACE(("Psigblock(%lx)",mask));
/* some signals (e.g. SIGKILL) can't be masked */
mask &= ~(UNMASKABLE);
oldmask = curproc->sigmask;
curproc->sigmask |= mask;
return oldmask;
}
/*
* set the signals that we're blocking. Some signals (e.g. SIGKILL)
* can't be masked.
* Returns the old mask.
*/
long ARGS_ON_STACK
p_sigsetmask(mask)
ulong mask;
{
ulong oldmask;
TRACE(("Psigsetmask(%lx)",mask));
oldmask = curproc->sigmask;
curproc->sigmask = mask & ~(UNMASKABLE);
check_sigs(); /* maybe we unmasked something */
return oldmask;
}
/*
* p_sigpending: return which signals are pending delivery
*/
long ARGS_ON_STACK
p_sigpending()
{
TRACE(("Psigpending()"));
check_sigs(); /* clear out any that are going to be delivered soon */
/* note that signal #0 is used internally, so we don't tell the process
* about it
*/
return curproc->sigpending & ~1L;
}
/*
* p_sigpause: atomically set the signals that we're blocking, then pause.
* Some signals (e.g. SIGKILL) can't be masked.
*/
long ARGS_ON_STACK
p_sigpause(mask)
ulong mask;
{
ulong oldmask;
TRACE(("Psigpause(%lx)", mask));
oldmask = curproc->sigmask;
curproc->sigmask = mask & ~(UNMASKABLE);
if (curproc->sigpending & ~(curproc->sigmask))
check_sigs(); /* a signal is immediately pending */
else
sleep(IO_Q, -1L);
curproc->sigmask = oldmask;
check_sigs(); /* maybe we unmasked something */
TRACE(("Psigpause: returning OK"));
return 0;
}
/*
* p_sigintr: Set an exception vector to send us the specified signal.
*/
typedef struct usig {
int vec; /* exception vector number */
int sig; /* signal to send */
PROC *proc; /* process to get signal */
long oldv; /* old exception vector value */
struct usig *next; /* next entry ... */
} usig;
static usig *usiglst;
extern long mcpu;
long ARGS_ON_STACK
p_sigintr(vec, sig)
int vec;
int sig;
{
extern void new_intr(); /* in intr.spp */
long vec2;
usig *new;
if (!sig) /* ignore signal 0 */
return 0;
vec2 = (long) new_intr;
#ifndef ONLY030
if (mcpu == 0)
/* put vector number in high byte of vector address */
vec2 |= ((long) vec) << 24;
#endif
new = kmalloc(sizeof(usig));
if (!new) /* hope this never happens...! */
return ENSMEM;
new->vec = vec;
new->sig = sig;
new->proc = curproc;
new->next = usiglst; /* simple unsorted list... */
usiglst = new;
new->oldv = setexc(vec, vec2);
return new->oldv;
}
/*
* Find the process that requested this interrupt, and send it a signal.
* Called at interrupt time by new_intr() from intr.spp, with interrupt
* vector number on the stack.
*/
void ARGS_ON_STACK
sig_user(vec)
int vec;
{
usig *ptr;
for (ptr = usiglst; ptr; ptr=ptr->next)
if (vec == ptr->vec) {
if (ptr->proc->wait_q != ZOMBIE_Q &&
ptr->proc->wait_q != TSR_Q) {
post_sig(ptr->proc, ptr->sig);
}
#if 0 /* Search entire list, to allow multiple processes to respond to
the same interrupt. (Why/when would you want that?) */
break;
#endif
}
/*
* Clear in-service bit for ST MFP interrupts
*/
if (vec >= 64 && vec < 80) {
char *mfp, c;
if (vec < 72) /* Register B */
mfp = (char *)0xfffffa11L;
else /* Register A */
mfp = (char *)0xfffffa0fL;
c = 1 << (vec & 7);
*mfp = ~c;
}
}
/*
* cancelsigintrs: remove any interrupts requested by this process, called
* at process termination.
*/
void
cancelsigintrs()
{
usig *ptr, **old, *nxt;
short s = spl7();
for (old=&usiglst, ptr=usiglst; ptr; ) {
nxt = ptr->next;
if (ptr->proc == curproc) {
setexc(ptr->vec, ptr->oldv);
*old = nxt;
kfree(ptr);
} else {
old = &(ptr->next);
}
ptr = nxt;
}
spl(s);
}