summaryrefslogtreecommitdiff
path: root/libgo/runtime/sigqueue.goc
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/runtime/sigqueue.goc')
-rw-r--r--libgo/runtime/sigqueue.goc113
1 files changed, 113 insertions, 0 deletions
diff --git a/libgo/runtime/sigqueue.goc b/libgo/runtime/sigqueue.goc
new file mode 100644
index 0000000000..b5f2954bc8
--- /dev/null
+++ b/libgo/runtime/sigqueue.goc
@@ -0,0 +1,113 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements runtime support for signal handling.
+//
+// Most synchronization primitives are not available from
+// the signal handler (it cannot block and cannot use locks)
+// so the handler communicates with a processing goroutine
+// via struct sig, below.
+//
+// Ownership for sig.Note passes back and forth between
+// the signal handler and the signal goroutine in rounds.
+// The initial state is that sig.note is cleared (setup by siginit).
+// At the beginning of each round, mask == 0.
+// The round goes through three stages:
+//
+// (In parallel)
+// 1a) One or more signals arrive and are handled
+// by sigsend using cas to set bits in sig.mask.
+// The handler that changes sig.mask from zero to non-zero
+// calls notewakeup(&sig).
+// 1b) Sigrecv calls notesleep(&sig) to wait for the wakeup.
+//
+// 2) Having received the wakeup, sigrecv knows that sigsend
+// will not send another wakeup, so it can noteclear(&sig)
+// to prepare for the next round. (Sigsend may still be adding
+// signals to sig.mask at this point, which is fine.)
+//
+// 3) Sigrecv uses cas to grab the current sig.mask and zero it,
+// triggering the next round.
+//
+// The signal handler takes ownership of the note by atomically
+// changing mask from a zero to non-zero value. It gives up
+// ownership by calling notewakeup. The signal goroutine takes
+// ownership by returning from notesleep (caused by the notewakeup)
+// and gives up ownership by clearing mask.
+
+package runtime
+#include "config.h"
+#include "runtime.h"
+#include "malloc.h"
+#include "defs.h"
+
+static struct {
+ Note;
+ uint32 mask;
+ bool inuse;
+} sig;
+
+void
+siginit(void)
+{
+ noteclear(&sig);
+}
+
+// Called from sighandler to send a signal back out of the signal handling thread.
+bool
+__go_sigsend(int32 s)
+{
+ uint32 bit, mask;
+
+ if(!sig.inuse)
+ return false;
+ bit = 1 << s;
+ for(;;) {
+ mask = sig.mask;
+ if(mask & bit)
+ break; // signal already in queue
+ if(runtime_cas(&sig.mask, mask, mask|bit)) {
+ // Added to queue.
+ // Only send a wakeup for the first signal in each round.
+ if(mask == 0)
+ notewakeup(&sig);
+ break;
+ }
+ }
+ return true;
+}
+
+// Called to receive a bitmask of queued signals.
+func Sigrecv() (m uint32) {
+ // runtime·entersyscall();
+ notesleep(&sig);
+ // runtime·exitsyscall();
+ noteclear(&sig);
+ for(;;) {
+ m = sig.mask;
+ if(runtime_cas(&sig.mask, m, 0))
+ break;
+ }
+}
+
+func Signame(sig int32) (name String) {
+ const char* s = NULL;
+ char buf[100];
+#if defined(HAVE_STRSIGNAL)
+ s = strsignal(sig);
+#endif
+ if (s == NULL) {
+ snprintf(buf, sizeof buf, "signal %d", sig);
+ s = buf;
+ }
+ int32 len = __builtin_strlen(s);
+ unsigned char *data = runtime_mallocgc(len, RefNoPointers, 0, 0);
+ __builtin_memcpy(data, s, len);
+ name.__data = data;
+ name.__length = len;
+}
+
+func Siginit() {
+ sig.inuse = true; // enable reception of signals; cannot disable
+}