minimal plan9port to cross-build Jehanne
This commit is contained in:
272
lib/lib9/notify.c
Normal file
272
lib/lib9/notify.c
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <signal.h>
|
||||
#define NOPLAN9DEFINES
|
||||
#include <libc.h>
|
||||
|
||||
extern char *_p9sigstr(int, char*);
|
||||
extern int _p9strsig(char*);
|
||||
|
||||
typedef struct Sig Sig;
|
||||
struct Sig
|
||||
{
|
||||
int sig; /* signal number */
|
||||
int flags;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Restart = 1<<0,
|
||||
Ignore = 1<<1,
|
||||
NoNotify = 1<<2,
|
||||
};
|
||||
|
||||
static Sig sigs[] = {
|
||||
SIGHUP, 0,
|
||||
SIGINT, 0,
|
||||
SIGQUIT, 0,
|
||||
SIGILL, 0,
|
||||
SIGTRAP, 0,
|
||||
/* SIGABRT, 0, */
|
||||
#ifdef SIGEMT
|
||||
SIGEMT, 0,
|
||||
#endif
|
||||
SIGFPE, 0,
|
||||
SIGBUS, 0,
|
||||
/* SIGSEGV, 0, */
|
||||
SIGCHLD, Restart|Ignore,
|
||||
SIGSYS, 0,
|
||||
SIGPIPE, Ignore,
|
||||
SIGALRM, 0,
|
||||
SIGTERM, 0,
|
||||
SIGTSTP, Restart|Ignore|NoNotify,
|
||||
/* SIGTTIN, Restart|Ignore, */
|
||||
/* SIGTTOU, Restart|Ignore, */
|
||||
SIGXCPU, 0,
|
||||
SIGXFSZ, 0,
|
||||
SIGVTALRM, 0,
|
||||
SIGUSR1, 0,
|
||||
SIGUSR2, 0,
|
||||
#ifdef SIGWINCH
|
||||
SIGWINCH, Restart|Ignore|NoNotify,
|
||||
#endif
|
||||
#ifdef SIGINFO
|
||||
SIGINFO, Restart|Ignore|NoNotify,
|
||||
#endif
|
||||
};
|
||||
|
||||
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.
|
||||
*/
|
||||
typedef struct Jmp Jmp;
|
||||
struct Jmp
|
||||
{
|
||||
p9jmp_buf b;
|
||||
};
|
||||
|
||||
static Jmp onejmp;
|
||||
|
||||
static Jmp*
|
||||
getonejmp(void)
|
||||
{
|
||||
return &onejmp;
|
||||
}
|
||||
|
||||
Jmp *(*_notejmpbuf)(void) = getonejmp;
|
||||
static void noteinit(void);
|
||||
|
||||
/*
|
||||
* Actual signal handler.
|
||||
*/
|
||||
|
||||
static void (*notifyf)(void*, char*); /* Plan 9 handler */
|
||||
|
||||
static void
|
||||
signotify(int sig)
|
||||
{
|
||||
char tmp[64];
|
||||
Jmp *j;
|
||||
Sig *s;
|
||||
|
||||
j = (*_notejmpbuf)();
|
||||
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);
|
||||
s = findsig(sig);
|
||||
if(s && (s->flags&Ignore))
|
||||
return;
|
||||
signal(sig, SIG_DFL);
|
||||
raise(sig);
|
||||
_exit(1);
|
||||
case 2: /* noted(NCONT) */
|
||||
if(0)print("HANDLED %d\n", sig);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
signonotify(int sig)
|
||||
{
|
||||
USED(sig);
|
||||
}
|
||||
|
||||
int
|
||||
noted(int v)
|
||||
{
|
||||
p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
|
||||
abort();
|
||||
return 0;
|
||||
}
|
||||
|
||||
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*
|
||||
handler(int s)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
sigaction(s, nil, &sa);
|
||||
return sa.sa_handler;
|
||||
}
|
||||
|
||||
static int
|
||||
notesetenable(int sig, int enabled)
|
||||
{
|
||||
sigset_t mask, omask;
|
||||
|
||||
if(sig == 0)
|
||||
return -1;
|
||||
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, sig);
|
||||
sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask);
|
||||
return !sigismember(&omask, sig);
|
||||
}
|
||||
|
||||
int
|
||||
noteenable(char *msg)
|
||||
{
|
||||
return notesetenable(_p9strsig(msg), 1);
|
||||
}
|
||||
|
||||
int
|
||||
notedisable(char *msg)
|
||||
{
|
||||
return notesetenable(_p9strsig(msg), 0);
|
||||
}
|
||||
|
||||
static int
|
||||
notifyseton(int s, int on)
|
||||
{
|
||||
Sig *sig;
|
||||
struct sigaction sa, osa;
|
||||
|
||||
sig = findsig(s);
|
||||
if(sig == nil)
|
||||
return -1;
|
||||
memset(&sa, 0, sizeof sa);
|
||||
sa.sa_handler = on ? signotify : signonotify;
|
||||
if(sig->flags&Restart)
|
||||
sa.sa_flags |= SA_RESTART;
|
||||
|
||||
/*
|
||||
* We can't allow signals within signals because there's
|
||||
* only one jump buffer.
|
||||
*/
|
||||
sigfillset(&sa.sa_mask);
|
||||
|
||||
/*
|
||||
* Install handler.
|
||||
*/
|
||||
sigaction(sig->sig, &sa, &osa);
|
||||
return osa.sa_handler == signotify;
|
||||
}
|
||||
|
||||
int
|
||||
notifyon(char *msg)
|
||||
{
|
||||
return notifyseton(_p9strsig(msg), 1);
|
||||
}
|
||||
|
||||
int
|
||||
notifyoff(char *msg)
|
||||
{
|
||||
return notifyseton(_p9strsig(msg), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialization follows sigs table.
|
||||
*/
|
||||
static void
|
||||
noteinit(void)
|
||||
{
|
||||
int i;
|
||||
Sig *sig;
|
||||
|
||||
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.
|
||||
* Leave it alone.
|
||||
*/
|
||||
if(handler(sig->sig) != SIG_DFL)
|
||||
continue;
|
||||
notifyseton(sig->sig, !(sig->flags&NoNotify));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user