aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime/sigqueue.cgo
diff options
context:
space:
mode:
authorDavid Symonds <dsymonds@golang.org>2009-12-15 18:21:29 -0800
committerRuss Cox <rsc@golang.org>2009-12-15 18:21:29 -0800
commitb5866494eaabd03a8eaeaabd05bd2e043e2795b5 (patch)
tree84efb708e358a0c126fa11d918d75f2cc0e78a05 /src/pkg/runtime/sigqueue.cgo
parenta47a45ec7741d677ea6582cdeee3419325ac9488 (diff)
downloadgo-b5866494eaabd03a8eaeaabd05bd2e043e2795b5.tar.xz
os/signal: new package
Fixes #71. R=rsc, r https://golang.org/cl/162056
Diffstat (limited to 'src/pkg/runtime/sigqueue.cgo')
-rw-r--r--src/pkg/runtime/sigqueue.cgo90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/pkg/runtime/sigqueue.cgo b/src/pkg/runtime/sigqueue.cgo
new file mode 100644
index 0000000000..059d3edd1c
--- /dev/null
+++ b/src/pkg/runtime/sigqueue.cgo
@@ -0,0 +1,90 @@
+// 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 "runtime.h"
+#include "defs.h"
+
+static struct {
+ Note;
+ uint32 mask;
+} sig;
+
+void
+siginit(void)
+{
+ noteclear(&sig);
+}
+
+// Called from sighandler to send a signal back out of the signal handling thread.
+void
+sigsend(int32 s)
+{
+ uint32 bit, mask;
+
+ bit = 1 << s;
+ for(;;) {
+ mask = sig.mask;
+ if(mask & bit)
+ return; // signal already in queue
+ if(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);
+ return;
+ }
+ }
+}
+
+// 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(cas(&sig.mask, m, 0))
+ break;
+ }
+}
+
+func Signame(sig int32) (name String) {
+ name = signame(sig);
+}