plan9port/src/lib9/notify.c

270 lines
4.8 KiB
C
Raw Normal View History

2004-10-23 02:59:33 +00:00
/*
* Signal handling for Plan 9 programs.
* We stubbornly use the strings from Plan 9 instead
* of the enumerated Unix constants.
* There are some weird translations. In particular,
* a "kill" note is the same as SIGTERM in Unix.
* There is no equivalent note to Unix's SIGKILL, since
* it's not a deliverable signal anyway.
*
* We do not handle SIGABRT or SIGSEGV, mainly because
* the thread library queues its notes for later, and we want
* to dump core with the state at time of delivery.
2004-10-23 02:59:33 +00:00
*
* We have to add some extra entry points to provide the
* ability to tweak which signals are deliverable and which
* are acted upon. Notifydisable and notifyenable play with
* the process signal mask. Notifyignore enables the signal
* but will not call notifyf when it comes in. This is occasionally
* useful.
*/
2003-11-23 18:12:54 +00:00
#include <u.h>
2004-03-25 23:03:57 +00:00
#include <signal.h>
2003-11-23 18:12:54 +00:00
#define NOPLAN9DEFINES
#include <libc.h>
extern char *_p9sigstr(int, char*);
2004-10-23 02:59:33 +00:00
extern int _p9strsig(char*);
2003-11-23 18:12:54 +00:00
2004-10-23 02:59:33 +00:00
typedef struct Sig Sig;
struct Sig
{
int sig; /* signal number */
int restart; /* do we restart the system call after this signal is handled? */
int enabled; /* is this signal enabled (not masked)? */
int notified; /* do we call the notify function for this signal? */
};
/* initial settings; for current status, ask the kernel */
static Sig sigs[] = {
SIGHUP, 0, 1, 1,
SIGINT, 0, 1, 1,
SIGQUIT, 0, 1, 1,
SIGILL, 0, 1, 1,
SIGTRAP, 0, 1, 1,
/* SIGABRT, 0, 1, 1, */
2003-11-24 00:43:41 +00:00
#ifdef SIGEMT
2004-10-23 02:59:33 +00:00
SIGEMT, 0, 1, 1,
2003-11-24 00:43:41 +00:00
#endif
2004-10-23 02:59:33 +00:00
SIGFPE, 0, 1, 1,
SIGBUS, 0, 1, 1,
/* SIGSEGV, 0, 1, 1, */
SIGCHLD, 1, 0, 1,
SIGSYS, 0, 1, 1,
SIGPIPE, 0, 0, 1,
SIGALRM, 0, 1, 1,
SIGTERM, 0, 1, 1,
SIGTSTP, 1, 0, 1,
SIGTTIN, 1, 0, 1,
SIGTTOU, 1, 0, 1,
SIGXCPU, 0, 1, 1,
SIGXFSZ, 0, 1, 1,
SIGVTALRM, 0, 1, 1,
SIGUSR1, 0, 1, 1,
SIGUSR2, 0, 1, 1,
SIGWINCH, 1, 0, 1,
2003-11-24 00:43:41 +00:00
#ifdef SIGINFO
2004-10-23 02:59:33 +00:00
SIGINFO, 1, 1, 1,
2003-11-24 00:43:41 +00:00
#endif
2003-11-23 18:12:54 +00:00
};
2004-10-23 02:59:33 +00:00
static Sig*
findsig(int s)
{
int i;
for(i=0; i<nelem(sigs); i++)
if(sigs[i].sig == s)
return &sigs[i];
return nil;
}
/*
* The thread library initializes _notejmpbuf to its own
* routine which provides a per-pthread jump buffer.
* If we're not using the thread library, we assume we are
* single-threaded.
*/
2004-09-23 03:06:04 +00:00
typedef struct Jmp Jmp;
struct Jmp
{
p9jmp_buf b;
};
static Jmp onejmp;
static Jmp*
getonejmp(void)
{
return &onejmp;
}
Jmp *(*_notejmpbuf)(void) = getonejmp;
2004-10-23 02:59:33 +00:00
static void noteinit(void);
2004-10-23 02:59:33 +00:00
/*
* Actual signal handler.
*/
static void (*notifyf)(void*, char*); /* Plan 9 handler */
2003-11-23 18:12:54 +00:00
static void
2004-10-23 02:59:33 +00:00
signotify(int sig)
2003-11-23 18:12:54 +00:00
{
char tmp[64];
2004-09-23 03:06:04 +00:00
Jmp *j;
2003-11-23 18:12:54 +00:00
2004-09-23 03:06:04 +00:00
j = (*_notejmpbuf)();
2004-10-23 02:59:33 +00:00
switch(p9setjmp(j->b)){
case 0:
if(notifyf)
(*notifyf)(nil, _p9sigstr(sig, tmp));
/* fall through */
case 1: /* noted(NDFLT) */
if(0)print("DEFAULT %d\n", sig);
signal(sig, SIG_DFL);
raise(sig);
_exit(1);
case 2: /* noted(NCONT) */
2004-09-23 03:06:04 +00:00
if(0)print("HANDLED %d\n", sig);
2003-11-23 18:12:54 +00:00
return;
}
2004-10-23 02:59:33 +00:00
}
static void
signonotify(int sig)
{
USED(sig);
2003-11-23 18:12:54 +00:00
}
2004-09-23 03:06:04 +00:00
int
noted(int v)
{
p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
abort();
return 0;
}
2004-10-23 02:59:33 +00:00
int
notify(void (*f)(void*, char*))
{
static int init;
notifyf = f;
if(!init){
init = 1;
noteinit();
}
return 0;
}
/*
* Nonsense about enabling and disabling signals.
*/
typedef void Sighandler(int);
static Sighandler*
2004-10-23 02:59:33 +00:00
handler(int s)
{
struct sigaction sa;
sigaction(s, nil, &sa);
return sa.sa_handler;
}
static void
notesetenable(int sig, int enabled)
2003-11-23 18:12:54 +00:00
{
2004-10-23 02:59:33 +00:00
sigset_t mask;
2003-11-23 18:12:54 +00:00
2004-10-23 02:59:33 +00:00
if(sig == 0)
return;
2004-10-23 02:59:33 +00:00
sigemptyset(&mask);
sigaddset(&mask, sig);
sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, nil);
}
void
noteenable(char *msg)
2004-10-23 02:59:33 +00:00
{
notesetenable(_p9strsig(msg), 1);
2004-10-23 02:59:33 +00:00
}
void
notedisable(char *msg)
2004-10-23 02:59:33 +00:00
{
notesetenable(_p9strsig(msg), 0);
2004-10-23 02:59:33 +00:00
}
static void
notifyseton(int s, int on)
{
Sig *sig;
struct sigaction sa;
sig = findsig(s);
if(sig == nil)
return;
if(on)
notesetenable(s, 1);
memset(&sa, 0, sizeof sa);
2004-10-23 02:59:33 +00:00
sa.sa_handler = on ? signotify : signonotify;
if(sig->restart)
sa.sa_flags |= SA_RESTART;
/*
2004-10-23 02:59:33 +00:00
* We can't allow signals within signals because there's
* only one jump buffer.
*/
sigfillset(&sa.sa_mask);
2004-10-23 02:59:33 +00:00
/*
* Install handler.
*/
sigaction(sig->sig, &sa, nil);
}
2004-10-23 02:59:33 +00:00
void
notifyon(char *msg)
{
2004-10-23 02:59:33 +00:00
notifyseton(_p9strsig(msg), 1);
2003-11-23 18:12:54 +00:00
}
void
2004-10-23 02:59:33 +00:00
notifyoff(char *msg)
{
notifyseton(_p9strsig(msg), 0);
}
2004-10-23 02:59:33 +00:00
/*
* Initialization follows sigs table.
*/
static void
noteinit(void)
{
int i;
2004-10-23 02:59:33 +00:00
Sig *sig;
2004-10-23 02:59:33 +00:00
for(i=0; i<nelem(sigs); i++){
sig = &sigs[i];
/*
* If someone has already installed a handler,
* It's probably some ld preload nonsense,
* like pct (a SIGVTALRM-based profiler).
* Or maybe someone has already called notifyon/notifyoff.
2004-10-23 02:59:33 +00:00
* Leave it alone.
*/
if(handler(sig->sig) != SIG_DFL)
continue;
/*
* Should we only disable and not enable signals?
* (I.e. if parent has disabled for us, should we still enable?)
* Right now we always initialize to the state we want.
*/
notesetenable(sig->sig, sig->enabled);
2004-10-23 02:59:33 +00:00
notifyseton(sig->sig, sig->notified);
}
}