/*
 * 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,
};

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,
/*	SIGTTIN,		Restart|Ignore, */
/*	SIGTTOU,		Restart|Ignore, */
	SIGXCPU,		0,
	SIGXFSZ,		0,
	SIGVTALRM,	0,
	SIGUSR1,		0,
	SIGUSR2,		0,
	SIGWINCH,	Restart|Ignore,
#ifdef SIGINFO
	SIGINFO,		Restart|Ignore,
#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, 1);
	}
}

