summaryrefslogtreecommitdiff
path: root/src/lib9/notify.c
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2008-06-12 13:26:16 -0700
committerRob Pike <r@golang.org>2008-06-12 13:26:16 -0700
commitc348f82e29356fc95dcb6331b4860b2d76fa07aa (patch)
treef571b5448e5f72870de933c01d9a6dcf04879e85 /src/lib9/notify.c
parent4732d2a3518bda35334461950464d2dffcd008b2 (diff)
downloadgo-c348f82e29356fc95dcb6331b4860b2d76fa07aa.tar.gz
import the plan 9 libraries libc (lib9) and libbio into the tree.
remove the dependency on /home/r. SVN=122482
Diffstat (limited to 'src/lib9/notify.c')
-rw-r--r--src/lib9/notify.c297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/lib9/notify.c b/src/lib9/notify.c
new file mode 100644
index 000000000..84999b887
--- /dev/null
+++ b/src/lib9/notify.c
@@ -0,0 +1,297 @@
+/*
+Plan 9 from User Space src/lib9/notify.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/notify.c
+
+Copyright 2001-2007 Russ Cox. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/*
+ * 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,
+#ifdef SIGWINCH
+ SIGWINCH, Restart|Ignore,
+#endif
+#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);
+ }
+}
+