Files
2015-04-16 09:16:48 +02:00

1099 lines
26 KiB
C

/*
* This file is part of ixemul.library for the Amiga.
* Copyright (C) 1991, 1992 Markus M. Wild
* Portions Copyright (C) 1994 Rafael W. Luebbert
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: kern_sig.c,v 1.1.1.1 2005/03/15 15:57:08 laire Exp $
*
* Since the code originated from Berkeley, the following copyright
* header applies as well. The code has been changed, it's not the
* original Berkeley code!
*/
/*
* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* All rights reserved.
*
* Redistribution is only permitted until one year after the first shipment
* of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
* binary forms are permitted provided that: (1) source distributions retain
* this entire copyright notice and comment, and (2) distributions including
* binaries display the following acknowledgement: This product includes
* software developed by the University of California, Berkeley and its
* contributors'' in the documentation or other materials provided with the
* distribution and in all advertising materials mentioning features or use
* of this software. Neither the name of the University nor the names of
* its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* @(#)kern_sig.c 7.23 (Berkeley) 6/28/90
*/
#define _KERNEL
#include "ixemul.h"
#include "kprintf.h"
#define KPRINTF //kprintf
#include <stdio.h>
#include <string.h>
#include <wait.h>
#define ttystopsigmask (sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU))
#define stopsigmask (sigmask(SIGSTOP)|ttystopsigmask)
#define defaultignmask (sigmask(SIGCONT)|sigmask(SIGIO)|sigmask(SIGURG)| \
sigmask(SIGCHLD)|sigmask(SIGWINCH)|sigmask(SIGINFO)|sigmask(SIGMSG))
void setsigvec (int sig, struct sigaction *sa);
void sig_exit (unsigned int code);
void stop (struct user *p);
/*
* Can process p send the signal signo to process q?
*/
#define CANSIGNAL(p, q, signo) (1)
int
sigaction (int sig, const struct sigaction *nsa, struct sigaction *osa)
{
struct sigaction vec;
register struct sigaction *sa;
int bit;
usetup;
KPRINTF(("sigaction(%ld, %lx)\n", sig, nsa ? nsa->sa_handler : NULL));
if (sig <= 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP)
{
errno = EINVAL;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return -1;
}
sa = &vec;
if (osa)
{
sa->sa_handler = u.u_signal[sig];
sa->sa_mask = u.u_sigmask[sig];
bit = sigmask(sig);
sa->sa_flags = 0;
if ((u.u_sigonstack & bit) != 0)
sa->sa_flags |= SA_ONSTACK;
if ((u.u_sigintr & bit) == 0)
sa->sa_flags |= SA_RESTART;
if (u.p_flag & SNOCLDSTOP)
sa->sa_flags |= SA_NOCLDSTOP;
*osa = *sa;
}
if (nsa)
{
*sa = *nsa;
setsigvec(sig, sa);
}
return (0);
}
#ifdef NATIVE_MORPHOS
int
_trampoline_sigaction(void)
{
int *p = (int *)REG_A7;
int sig = p[1];
struct sigaction *nsa = (void *)p[2];
struct sigaction *osa = (void *)p[3];
struct sigaction my_nsa;
int r;
if (nsa && nsa->sa_handler != SIG_IGN &&
nsa->sa_handler != SIG_DFL && nsa->sa_handler != SIG_ERR)
{
my_nsa = *nsa;
*(int*)&my_nsa.sa_handler ^= 1;
nsa = &my_nsa;
}
r = sigaction(sig, nsa, osa);
if (osa && osa->sa_handler != SIG_IGN &&
osa->sa_handler != SIG_DFL && osa->sa_handler != SIG_ERR)
*(int *)osa->sa_handler ^= 1;
return r;
}
struct EmulLibEntry _gate_sigaction = {
TRAP_LIB, 0, (void(*)())_trampoline_sigaction
};
#endif
void
setsigvec (int sig, struct sigaction *sa)
{
register int bit;
usetup;
KPRINTF(("setsigvec(%ld, %lx)\n", sig, sa ? sa->sa_handler : NULL));
bit = sigmask(sig);
/*
* Change setting atomically.
*/
Forbid();
u.u_signal[sig] = sa->sa_handler;
u.u_sigmask[sig] = sa->sa_mask &~ sigcantmask;
if ((sa->sa_flags & SA_RESTART) == 0)
u.u_sigintr |= bit;
else
u.u_sigintr &= ~bit;
if (sa->sa_flags & SA_ONSTACK)
u.u_sigonstack |= bit;
else
u.u_sigonstack &= ~bit;
if (sig == SIGCHLD)
{
if (sa->sa_flags & SA_NOCLDSTOP)
u.p_flag |= SNOCLDSTOP;
else
u.p_flag &= ~SNOCLDSTOP;
}
/*
* Set bit in p_sigignore for signals that are set to SIG_IGN,
* and for signals set to SIG_DFL where the default is to ignore.
* However, don't put SIGCONT in p_sigignore,
* as we have to restart the process.
*/
if (sa->sa_handler == SIG_IGN ||
(bit & defaultignmask && sa->sa_handler == SIG_DFL))
{
u.p_sig &= ~bit; /* never to be seen again */
if (sig != SIGCONT)
u.p_sigignore |= bit; /* easier in _psignal */
u.p_sigcatch &= ~bit;
}
else
{
u.p_sigignore &= ~bit;
if (sa->sa_handler == SIG_DFL)
u.p_sigcatch &= ~bit;
else
u.p_sigcatch |= bit;
}
Permit();
}
/*
* Manipulate signal mask.
*/
int
sigprocmask (int how, const sigset_t *mask, sigset_t *omask)
{
usetup;
if (omask)
*omask = u.p_sigmask;
if (mask)
{
Forbid();
switch (how)
{
case SIG_BLOCK:
u.p_sigmask |= *mask &~ sigcantmask;
break;
case SIG_UNBLOCK:
u.p_sigmask &= ~*mask;
break;
case SIG_SETMASK:
u.p_sigmask = *mask &~ sigcantmask;
break;
default:
errno = EINVAL;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
goto err_ret;
}
Permit();
}
if (CURSIG (&u))
setrun (SysBase->ThisTask);
return 0;
err_ret:
Permit();
return -1;
}
int
sigpending (sigset_t *sigs)
{
usetup;
*sigs = u.p_sig;
return 0;
}
/*
* Generalized interface signal handler, 4.3-compatible.
* (included in amiga version, because I want to reduce the static part of the
* library to a minimum)
*/
/* ARGSUSED */
int
sigvec(int sig, struct sigvec *nsv, struct sigvec *osv)
{
usetup;
struct sigvec vec;
register struct sigvec *sv;
struct user *p = &u;
int bit;
KPRINTF(("sigvec(%ld, %lx)\n", sig, nsv ? nsv->sv_handler : NULL));
if (sig <= 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP)
{
*p->u_errno = EINVAL;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return -1;
}
sv = &vec;
if (osv)
{
*(sig_t *)&sv->sv_handler = p->u_signal[sig];
sv->sv_mask = p->u_sigmask[sig];
bit = sigmask(sig);
sv->sv_flags = 0;
if ((p->u_sigonstack & bit) != 0)
sv->sv_flags |= SV_ONSTACK;
if ((p->u_sigintr & bit) != 0)
sv->sv_flags |= SV_INTERRUPT;
if (p->p_flag & SNOCLDSTOP)
sv->sv_flags |= SA_NOCLDSTOP;
*osv = *sv;
}
if (nsv)
{
*sv = *nsv;
sv->sv_flags ^= SA_RESTART; /* opposite of SV_INTERRUPT */
setsigvec(sig, (struct sigaction *)sv);
}
return (0);
}
#ifdef NATIVE_MORPHOS
int
_trampoline_sigvec(void)
{
int *p = (int *)REG_A7;
int sig = p[1];
struct sigvec *nsv = (void *)p[2];
struct sigvec *osv = (void *)p[3];
struct sigvec my_nsv;
int r;
if (nsv && nsv->sv_handler != SIG_IGN &&
nsv->sv_handler != SIG_DFL && nsv->sv_handler != SIG_ERR)
{
my_nsv = *nsv;
*(int*)&my_nsv.sv_handler ^= 1;
nsv = &my_nsv;
}
r = sigvec(sig, nsv, osv);
if (osv && osv->sv_handler != SIG_IGN &&
osv->sv_handler != SIG_DFL && osv->sv_handler != SIG_ERR)
*(int *)osv->sv_handler ^= 1;
return r;
}
struct EmulLibEntry _gate_sigvec = {
TRAP_LIB, 0, (void(*)())_trampoline_sigvec
};
#endif
int
sigblock (int mask)
{
int result;
usetup;
Forbid();
result = u.p_sigmask;
u.p_sigmask |= mask &~ sigcantmask;
Permit();
return result;
}
int
sigsetmask(int mask)
{
int result;
usetup;
struct user *p = &u;
Forbid();
/* KPRINTF(("sigsetmask(%lx), old = %lx\n", mask, u.p_sigmask)); */
result = u.p_sigmask;
u.p_sigmask = mask &~ sigcantmask;
Permit();
if (CURSIG (p))
setrun (SysBase->ThisTask);
return result;
}
/*
* Suspend process until signal, providing mask to be set
* in the meantime.
*/
/* ARGSUSED */
int
sigsuspend (const sigset_t *mask)
{
usetup;
struct user *p = &u;
int i;
/*
* When returning from sigpause, we want
* the old mask to be restored after the
* signal handler has finished. Thus, we
* save it here and mark the proc structure
* to indicate this (should be in u.).
*/
KPRINTF("sigsuspend(%08lx)\n", mask);
KPRINTF("handling sigs 0. TDNestCnt = %ld, IDNestCnt = %ld\n", SysBase->TDNestCnt, SysBase->IDNestCnt);
Forbid();
p->u_oldmask = p->p_sigmask;
p->p_flag |= SOMASK;
p->p_sigmask = *mask &~ sigcantmask;
/* NOTE: we have to specify SIGBREAKF_CTRL_C here, as the OS doesn't seem
* to reschedule our task, if it receives a signal it isn't waiting
* for. If SIGINT is ignored, then this will jump back into the Wait,
* if not, we're leaving correctly, since we waited for a signal
* that now occured (lucky we, the OS tests the Recvd-field before
* tc_Launch has a chance to reset it ;-))
*/
while (ix_sleep ((caddr_t)p, "sigsuspend") == 0);
Permit();
//Delay(2);
KPRINTF("handling sigs 1. TDNestCnt = %ld, IDNestCnt = %ld\n", SysBase->TDNestCnt, SysBase->IDNestCnt);
setrun (SysBase->ThisTask);
//Delay(1);
//while(i=CURSIG(p))
// psig(p, i);
p->p_sigmask = p->u_oldmask;
KPRINTF("handling sigs 2. TDNestCnt = %ld, IDNestCnt = %ld\n", SysBase->TDNestCnt, SysBase->IDNestCnt);
if (CURSIG (p))
setrun (SysBase->ThisTask);
//Delay(1);
//while(i=CURSIG(p))
// psig(p, i);
KPRINTF("handled sigs. TDNestCnt = %ld, IDNestCnt = %ld\n", SysBase->TDNestCnt, SysBase->IDNestCnt);
/* always return EINTR rather than ERESTART... */
errno = EINTR;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return -1;
}
int
sigpause (int mask)
{ //Delay(1);
return sigsuspend (&mask);
}
/* ARGSUSED */
int
sigstack(const struct sigstack *nss, struct sigstack *oss)
{
usetup;
if (oss) *oss = u.u_sigstack;
if (nss) u.u_sigstack = *nss;
return 0;
}
/*
* Initialize signal state for process 0;
* set to ignore signals that are ignored by default.
*/
void
siginit(struct user *p)
{
p->p_sigignore = defaultignmask &~ sigmask(SIGCONT);
}
/*
* This looks for the process p, validates it, and checks, whether the process
* is currently using our signal mechanism (checks magic cookie in struct user)
*/
struct Task *
pfind (pid_t p)
{
struct Task *t;
usetup;
if (p && !(p & 1))
{
/* have to check if the task really exists */
struct List *exectasklist;
struct Node * execnode;
Disable();
exectasklist = &(SysBase->TaskWait);
for (execnode = exectasklist->lh_Head; execnode->ln_Succ;
execnode = execnode->ln_Succ)
{
if ((pid_t)execnode == p)
break;
}
if (execnode == NULL)
{
exectasklist = &(SysBase->TaskReady);
for (execnode = exectasklist->lh_Head; execnode->ln_Succ;
execnode = execnode->ln_Succ)
{
if ((pid_t)execnode == p)
break;
}
}
Enable();
if (execnode == NULL)
return 0;
t = (struct Task *) p;
if (t->tc_Node.ln_Type == NT_TASK ||
t->tc_Node.ln_Type == NT_PROCESS)
{
struct user *tu = getuser(t);
if (tu && !((int)getuser(t) & 1) && tu->u_ixbase == u.u_ixbase)
return t;
}
}
else if (! p)
return SysBase->ThisTask;
return 0;
}
/* ARGSUSED */
int
kill(pid_t pid, int signo)
{
register struct Task *t;
usetup;
KPRINTF(("kill(%lx, %ld)\n", pid, signo));
if ((unsigned) signo >= NSIG)
{
errno = EINVAL;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return -1;
}
if (pid >= 0)
{
/* kill single process */
t = pfind(pid);
if (t == 0)
{
/* there is a small chance, if pid == 0, that we may send the signal
* as well. If signo == SIGINT, and pid refers to a valid Task, we send
* it a SIGBREAKF_CTRL_C */
if ((signo == SIGINT) && pid && !(pid & 1))
{
t = (struct Task *) pid;
if (t->tc_Node.ln_Type == NT_TASK ||
t->tc_Node.ln_Type == NT_PROCESS)
{
Signal (t, SIGBREAKF_CTRL_C);
return 0;
}
}
errno = ESRCH;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return -1;
}
if (signo)
_psignal(t, signo);
KPRINTF(("kill: done.\n"));
return (0);
}
/* signalling process groups is not (yet) implemented */
errno = ESRCH;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
return -1;
}
/* ARGSUSED */
int
killpg(int pgid, int signo)
{
usetup;
if ((unsigned) signo >= NSIG)
errno = EINVAL;
else
errno = ESRCH;
KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));
/* signalling process groups is not (yet) implemented */
return -1;
}
/*
* Send a signal caused by a trap to the current process.
* If it will be caught immediately, deliver it with correct code.
* Otherwise, post it normally.
*/
void trapsignal(struct Task *t, int sig, unsigned code, void *addr)
{
int mask;
usetup;
mask = sigmask(sig);
if ((u.p_flag & STRC) == 0 && (u.p_sigcatch & mask) != 0 &&
(u.p_sigmask & mask) == 0)
{
u.u_ru.ru_nsignals++;
sendsig(getuser(t), u.u_signal[sig], sig, u.p_sigmask, code, addr);
u.p_sigmask |= u.u_sigmask[sig] | mask;
setrun (t);
}
else
{
u.u_code = code; /* XXX for core dump/debugger */
_psignal(t, sig);
}
}
/*
* Create a core image on the file "core".
* It writes UPAGES block of the
* user.h area followed by the entire
* data+stack segments.
*/
int core(void)
{
return -1;
}
/*
* Send the specified signal to the specified process.
* Most signals do not do anything directly to a process;
* they set a flag that asks the process to do something to itself.
* Exceptions:
* o When a stop signal is sent to a sleeping process that takes the default
* action, the process is stopped without awakening it.
* o SIGCONT restarts stopped processes (or puts them back to sleep)
* regardless of the signal action (eg, blocked or ignored).
* Other ignored signals are discarded immediately.
*/
void
_psignal(struct Task *t, int sig) /* MAY be called in Supervisor/Interrupt !*/
{
register sig_t action;
/* may be another process, so don't use u. here ! */
struct user *p = getuser(t);
int mask;
mask = sigmask(sig);
KPRINTF(("_psignal(%lx, %ld), mask = %lx, ignore = %lx\n", t, sig, p->p_sigmask, p->p_sigignore));
/*
* If proc is traced, always give parent a chance.
*/
if (p->p_flag & STRC)
action = SIG_DFL;
else
{
/* NOTE AMIGA !
* I can't allow for trap signals to be either ignored or masked out.
* This would cause the trap to reoccur immediately again, resulting
* in a deadly loop. So if such a signal gets here, it is converted
* in a SIGILL, masked in, not ignored, not caught, that's it.
*/
if (((mask & p->p_sigignore) || (mask & p->p_sigmask))
&& (sig == SIGILL || sig == SIGBUS || sig == SIGFPE ||
sig == SIGTRAP || sig == SIGEMT))
{
sig = SIGILL;
mask = sigmask (sig);
p->p_sigignore &= ~mask;
p->p_sigmask &= ~mask;
p->p_sigcatch &= ~mask;
/* that's it, SIGILL is now reset to SIG_DFL, which will exit() */
}
/*
* If the signal is being ignored,
* then we forget about it immediately.
* (Note: we don't set SIGCONT in p_sigignore,
* and if it is set to SIG_IGN,
* action will be SIG_DFL here.)
*/
if (p->p_sigignore & mask)
return;
if (p->p_sigmask & mask)
action = SIG_HOLD;
else if (p->p_sigcatch & mask)
action = SIG_CATCH;
else
action = SIG_DFL;
}
switch (sig)
{
case SIGTERM:
if ((p->p_flag&STRC) || action != SIG_DFL)
break;
/* FALLTHROUGH */
case SIGKILL:
break;
case SIGCONT:
p->p_sig &= ~stopsigmask;
break;
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
case SIGSTOP:
p->p_sig &= ~sigmask(SIGCONT);
break;
}
p->p_sig |= mask;
/*
* Defer further processing for signals which are held,
* except that stopped processes must be continued by SIGCONT.
*/
if (action == SIG_HOLD && (sig != SIGCONT || p->p_stat != SSTOP))
return;
/*
* If traced process is already stopped,
* then no further action is necessary.
*/
if (p->p_stat == SSTOP && (p->p_flag & STRC))
return;
setrun(t);
}
void stopped_process_handler (void)
{
/* We are running in user mode in the context of the exec Task that is
(in the view of other ixemul.library processes) a stopped process.
We got here from the stop_process_glue routine. */
struct Task *task = SysBase->ThisTask;
struct user *p = getuser(task);
Forbid();
_psignal((struct Task *)p->p_pptr, SIGCHLD);
stop (p);
while (p->p_stat != SRUN)
{
KPRINTF(("SSTOP: Wait (1<<p->p_zombie_sig);\n"));
Wait (1 << p->p_zombie_sig);
KPRINTF(("SSTOP: done, p->p_stat=%lx, p_xstat: %lx\n", p->p_stat, p->p_xstat));
}
Permit();
}
/*
* If the current process has a signal to process (should be caught
* or cause termination, should interrupt current syscall),
* return the signal number. Stop signals with default action
* are processed immediately, then cleared; they aren't returned.
* This is asked at least once each time a process enters the
* system (though this can usually be done without actually
* calling issig by checking the pending signal masks.)
*/
int
issig(struct user *p) /* called in SUPERVISOR */
{
register int sig, mask;
u_int sr;
usetup;
KPRINTF(("issig()\n"));
#ifdef NATIVE_MORPHOS
sr = 0;
#else
/*#ifdef MORPHOS
if (has_morphos)
sr = 0;
else
#endif*/
{
asm volatile (" \n\
movel a5,a0 \n\
lea Lget_sr,a5 \n\
movel 4:w,a6 \n\
jsr a6@(-0x1e) \n\
movel a1,%0 \n\
bra Lskip \n\
Lget_sr: \n\
movew sp@,a1 | get sr register from the calling function \n\
rte \n\
Lskip: \n\
movel a0,a5 \n\
" : "=g" (sr) : : "a0", "a1", "a6");
}
#endif
if (p->u_mask_state)
{
mask = p->u_mask_state;
p->u_mask_state = 0;
goto restart;
}
for (;;)
{
mask = p->p_sig & ~p->p_sigmask;
if (p->p_flag & SVFORK)
mask &= ~stopsigmask;
if (mask == 0) /* no signal to send */
return 0;
sig = ffs((long)mask);
mask = sigmask(sig);
/*
* We should see pending but ignored signals
* only if STRC was on when they were posted.
*/
if ((mask & p->p_sigignore) && (p->p_flag & STRC) == 0)
{
p->p_sig &= ~mask;
continue;
}
/* Don't do this while waiting in inet.library. */
if (p->p_stat != SWAIT && (p->p_flag & STRC)
&& (p->p_flag & SVFORK) == 0)
{
/*
* If traced, always stop, and stay
* stopped until released by the parent.
*/
KPRINTF(("issig(task=%lx): ...stopping... Setting p->p_xstat = %ld\n", FindTask(0), sig));
p->p_xstat = sig;
KPRINTF(("issig(task=%lx): ...stopping... Sending SIGCHLD to parent %lx\n", FindTask(0), p->p_pptr));
if (sr & 0x2000)
{
KPRINTF(("issig(task=%lx): ...stopping... while in supervisor\n", FindTask(0)));
p->u_mask_state = mask;
sendsig(p, (sig_t)stopped_process_handler, 0, 0, 0, 0);
return -1; /* Drop into the context of the task. */
}
else
{
p->u_regs = NULL;
p->u_fpregs = NULL;
KPRINTF(("issig(task=%lx): ...stopping... while NOT in supervisor\n", FindTask(0)));
stopped_process_handler ();
}
restart:
/*
* If the traced bit got turned off,
* go back up to the top to rescan signals.
* This ensures that p_sig* and u_signal are consistent.
*
* (That may be, but it fails to work with ptrace(PT_DETACH):
* the old SIGTRAP is caught again, but without tracing that
* results in a call to exit(). So we comment it out.)
*
*if ((p->p_flag & STRC) == 0)
* continue;
*/
/*
* If parent wants us to take the signal,
* then it will leave it in p->p_xstat;
* otherwise we just look for signals again.
*/
p->p_sig &= ~mask; /* clear the old signal */
sig = p->p_xstat;
if (sig == 0)
continue;
/*
* Put the new signal into p_sig.
* If signal is being masked,
* look for other signals.
*/
mask = sigmask(sig);
p->p_sig |= mask;
if (p->p_sigmask & mask)
continue;
}
/*
* Decide whether the signal should be returned.
* Return the signal's number, or fall through
* to clear it from the pending mask.
*/
int temp1 = p->u_signal[sig];
switch (((int)p->u_signal[sig]))
{
case (int)SIG_DFL:
#if notyet
/*
* Don't take default actions on system processes.
*/
if (p->p_ppid == 0)
break; /* == ignore */
#endif
/*
* If there is a pending stop signal to process
* with default action, stop here,
* then clear the signal. However,
* if process is member of an orphaned
* process group, ignore tty stop signals.
*/
if (mask & stopsigmask)
{
#if notyet
if (p->p_flag&STRC ||
(p->p_pgru.pg_jobc == 0 && mask & ttystopsigmask))
break; /* == ignore */
u.p_xstat = sig;
stop(p);
if ((u.p_pptr->p_flag & SNOCLDSTOP) == 0)
_psignal(u.p_pptr, SIGCHLD);
swtch();
#endif
break;
}
else if (mask & defaultignmask)
{
/*
* Except for SIGCONT, shouldn't get here.
* Default action is to ignore; drop it.
*/
break; /* == ignore */
}
else
return (sig);
/*NOTREACHED*/
case (int)SIG_IGN:
/*
* Masking above should prevent us ever trying
* to take action on an ignored signal other
* than SIGCONT, unless process is traced.
*/
#if 0
if (sig != SIGCONT && (u.p_flag&STRC) == 0)
printf("issig\n");
#endif
break; /* == ignore */
default:
/*
* This signal has an action, let
* psig process it.
*/
return (sig);
}
u.p_sig &= ~mask; /* take the signal! */
}
/* NOTREACHED */
}
/*
* Put the argument process into the stopped
* state and notify the parent via wakeup.
* Signals are handled elsewhere.
* The process must not be on the run queue.
*/
void stop(struct user *p)
{
p->p_stat = SSTOP;
p->p_flag &= ~SWTED;
ix_wakeup((u_int)getuser(p->p_pptr));
}
/*
* Perform the action specified by the current signal.
* The usual sequence is:
* if (sig = CURSIG(p))
* psig(p, sig);
*/
void
psig(struct user *p, int sig) /* called in SUPERVISOR */
{
int code, mask, returnmask;
register sig_t action;
do
{
if (sig == -1)
return;
KPRINTF(("psig(%ld)\n", sig));
mask = sigmask(sig);
p->p_sig &= ~mask;
action = p->u_signal[sig];
if (action != SIG_DFL)
{
/*
* Set the new mask value and also defer further
* occurences of this signal.
*
* Special case: user has done a sigpause. Here the
* current mask is not of interest, but rather the
* mask from before the sigpause is what we want
* restored after the signal processing is completed.
*/
if (p->p_flag & SOMASK)
{
returnmask = p->u_oldmask;
p->p_flag &= ~SOMASK;
}
else
returnmask = p->p_sigmask;
p->p_sigmask |= p->u_sigmask[sig] | mask;
p->u_ru.ru_nsignals++;
if (p->u_sig != sig)
{
KPRINTF(("psig(): code = 0;\n"));
code = 0;
}
else
{
KPRINTF(("psig(): code = u.u_code;\n"));
code = p->u_code;
p->u_code = 0;
}
KPRINTF(("psig(): calling sendsig()\n"));
sendsig(p, action, sig, returnmask, code, 0);
continue;
}
#if whatdoesthisdo
p->u_acflag |= AXSIG;
#endif
switch (sig)
{
case SIGILL:
case SIGIOT:
case SIGBUS:
case SIGQUIT:
case SIGTRAP:
case SIGEMT:
case SIGFPE:
case SIGSEGV:
case SIGSYS:
p->u_sig = sig;
if (core() == 0)
sig |= WCOREFLAG;
}
/* we can't call exit() when in supervisor mode, have to do this just like
* it was a signal passed on its own frame */
sendsig(p, (sig_t)sig_exit, sig, 0, 0, 0);
} while ((sig = CURSIG(p)));
}
static int sigprocessgrp(struct Process *proc, int pgrp, int signal, int test)
{
struct Process *p;
if (test)
{
if (getuser(proc) == NULL)
return 0;
for (p = getuser(proc)->p_cptr; p; p = getuser(p)->p_osptr)
{
if (getuser(p) == NULL)
return 0;
if (sigprocessgrp(p, pgrp, signal, test) == 0)
return 0;
}
return 1;
}
for (p = getuser(proc)->p_cptr; p; p = getuser(p)->p_osptr)
{
sigprocessgrp(p, pgrp, signal, test);
}
if (getuser(proc)->p_pgrp == pgrp)
_psignal((struct Task *)proc, signal);
return 1;
}
void _psignalgrp(struct Process *proc, int signal)
{
struct Process *p;
struct Process *ok = proc;
if (proc == NULL || getuser(proc) == NULL)
return;
p = getuser(proc)->p_pptr;
/* traverse to the top of the process-tree */
while (p && p != (struct Process *)1)
{
ok = p;
if (getuser(p) == NULL)
return;
p = getuser(p)->p_pptr;
}
if (sigprocessgrp(ok, getuser(proc)->p_pgrp, signal, 1))
sigprocessgrp(ok, getuser(proc)->p_pgrp, signal, 0);
}