]> Cypherpunks repositories - gostls13.git/commitdiff
os/signal: new package
authorDavid Symonds <dsymonds@golang.org>
Wed, 16 Dec 2009 02:21:29 +0000 (18:21 -0800)
committerRuss Cox <rsc@golang.org>
Wed, 16 Dec 2009 02:21:29 +0000 (18:21 -0800)
Fixes #71.

R=rsc, r
https://golang.org/cl/162056

19 files changed:
src/pkg/Makefile
src/pkg/os/signal/Makefile [new file with mode: 0644]
src/pkg/os/signal/signal.go [new file with mode: 0644]
src/pkg/os/signal/signal_test.go [new file with mode: 0644]
src/pkg/runtime/Makefile
src/pkg/runtime/darwin/386/signal.c
src/pkg/runtime/darwin/amd64/signal.c
src/pkg/runtime/darwin/signals.h
src/pkg/runtime/extern.go
src/pkg/runtime/freebsd/386/signal.c
src/pkg/runtime/freebsd/amd64/signal.c
src/pkg/runtime/freebsd/signals.h
src/pkg/runtime/linux/386/signal.c
src/pkg/runtime/linux/amd64/signal.c
src/pkg/runtime/linux/arm/signal.c
src/pkg/runtime/linux/signals.h
src/pkg/runtime/proc.c
src/pkg/runtime/runtime.h
src/pkg/runtime/sigqueue.cgo [new file with mode: 0644]

index ea50e0d7b55ed79eed0f78b533e02242d41da10c..db33ab2629986931a969fcacd1b8b710d701deae 100644 (file)
@@ -82,6 +82,7 @@ DIRS=\
        net\
        once\
        os\
+       os/signal\
        patch\
        path\
        rand\
diff --git a/src/pkg/os/signal/Makefile b/src/pkg/os/signal/Makefile
new file mode 100644 (file)
index 0000000..a1f04b6
--- /dev/null
@@ -0,0 +1,11 @@
+# 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.
+
+include ../../../Make.$(GOARCH)
+
+TARG=os/signal
+GOFILES=\
+       signal.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/os/signal/signal.go b/src/pkg/os/signal/signal.go
new file mode 100644 (file)
index 0000000..df81e51
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+// Package signal implements operating system-independent signal handling.
+package signal
+
+import (
+       "runtime"
+       "strconv"
+)
+
+// A Signal can represent any operating system signal.
+type Signal interface {
+       String() string
+}
+
+type UnixSignal int32
+
+func (sig UnixSignal) String() string {
+       s := runtime.Signame(int32(sig))
+       if len(s) > 0 {
+               return s
+       }
+       return "Signal " + strconv.Itoa(int(sig))
+}
+
+// Incoming is the global signal channel.
+// All signals received by the program will be delivered to this channel.
+var Incoming <-chan Signal
+
+func process(ch chan<- Signal) {
+       for {
+               var mask uint32 = runtime.Sigrecv()
+               for sig := uint(0); sig < 32; sig++ {
+                       if mask&(1<<sig) != 0 {
+                               ch <- UnixSignal(sig)
+                       }
+               }
+       }
+}
+
+func init() {
+       ch := make(chan Signal) // Done here so Incoming can have type <-chan Signal
+       Incoming = ch
+       go process(ch)
+}
diff --git a/src/pkg/os/signal/signal_test.go b/src/pkg/os/signal/signal_test.go
new file mode 100644 (file)
index 0000000..e5b21c7
--- /dev/null
@@ -0,0 +1,19 @@
+// 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.
+
+package signal
+
+import (
+       "syscall"
+       "testing"
+)
+
+func TestSignal(t *testing.T) {
+       // Send this process a SIGHUP.
+       syscall.Syscall(syscall.SYS_KILL, uintptr(syscall.Getpid()), syscall.SIGHUP, 0)
+
+       if sig := (<-Incoming).(UnixSignal); sig != 1 {
+               t.Error("signal was %v, want %v", sig, 1)
+       }
+}
index 6dc4f0ac15b38b536caa8374247b40efa12650c9..bd6cd908bd63245440965ed36d721e9b163adb02 100644 (file)
@@ -63,6 +63,7 @@ OFILES=\
        rt0.$O\
        sema.$O\
        signal.$O\
+       sigqueue.$O\
        slice.$O\
        string.$O\
        symtab.$O\
@@ -78,6 +79,7 @@ HFILES=\
        malloc.h\
        $(GOARCH)/asm.h\
        $(GOOS)/os.h\
+       $(GOOS)/signals.h\
        $(GOOS)/$(GOARCH)/defs.h\
 
 include ../../Make.pkg
index 8d9a68967cf9090fdae50613d02306f419731297..4023439b3938fe1711eece6e9d6b53d839e5a510 100644 (file)
@@ -25,6 +25,14 @@ dumpregs(Regs *r)
        printf("gs      %x\n", r->gs);
 }
 
+String
+signame(int32 sig)
+{
+       if(sig < 0 || sig >= NSIG)
+               return emptystring;
+       return gostring((byte*)sigtab[sig].name);
+}
+
 void
 sighandler(int32 sig, Siginfo *info, void *context)
 {
@@ -32,6 +40,11 @@ sighandler(int32 sig, Siginfo *info, void *context)
        Mcontext *mc;
        Regs *r;
 
+       if(sigtab[sig].flags & SigQueue) {
+               sigsend(sig);
+               return;
+       }
+
        if(panicking)   // traceback already printed
                exit(2);
        panicking = 1;
@@ -82,12 +95,14 @@ initsig(void)
        int32 i;
        static Sigaction sa;
 
+       siginit();
+
        sa.sa_flags |= SA_SIGINFO|SA_ONSTACK;
        sa.sa_mask = 0xFFFFFFFFU;
        sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler
        for(i = 0; i<NSIG; i++) {
                if(sigtab[i].flags) {
-                       if(sigtab[i].flags & SigCatch) {
+                       if(sigtab[i].flags & (SigCatch | SigQueue)) {
                                sa.__sigaction_u.__sa_sigaction = sighandler;
                        } else {
                                sa.__sigaction_u.__sa_sigaction = sigignore;
@@ -100,4 +115,3 @@ initsig(void)
                }
        }
 }
-
index 8ceb17ed38911b5bf3438f5d7f349ee498e26cd5..5e26a713eea00ddbcf8cb45d88c0a308d631302c 100644 (file)
@@ -33,6 +33,14 @@ dumpregs(Regs *r)
        printf("gs      %X\n", r->gs);
 }
 
+String
+signame(int32 sig)
+{
+       if(sig < 0 || sig >= NSIG)
+               return emptystring;
+       return gostring((byte*)sigtab[sig].name);
+}
+
 void
 sighandler(int32 sig, Siginfo *info, void *context)
 {
@@ -40,6 +48,11 @@ sighandler(int32 sig, Siginfo *info, void *context)
        Mcontext *mc;
        Regs *r;
 
+       if(sigtab[sig].flags & SigQueue) {
+               sigsend(sig);
+               return;
+       }
+
        if(panicking)   // traceback already printed
                exit(2);
        panicking = 1;
@@ -90,12 +103,14 @@ initsig(void)
        int32 i;
        static Sigaction sa;
 
+       siginit();
+
        sa.sa_flags |= SA_SIGINFO|SA_ONSTACK;
        sa.sa_mask = 0xFFFFFFFFU;
        sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler
        for(i = 0; i<NSIG; i++) {
                if(sigtab[i].flags) {
-                       if(sigtab[i].flags & SigCatch) {
+                       if(sigtab[i].flags & (SigCatch | SigQueue)) {
                                sa.__sigaction_u.__sa_sigaction = sighandler;
                        } else {
                                sa.__sigaction_u.__sa_sigaction = sigignore;
@@ -108,4 +123,3 @@ initsig(void)
                }
        }
 }
-
index 8cca361f759fdb7126fbaa4dbcec078d2e890405..48a5db12d8ce5282a36234258fced8a9165ef04e 100644 (file)
@@ -5,11 +5,12 @@
 #define C SigCatch
 #define I SigIgnore
 #define R SigRestart
+#define Q SigQueue
 
 static SigTab sigtab[] = {
        /* 0 */ 0, "SIGNONE: no trap",
-       /* 1 */ 0, "SIGHUP: terminal line hangup",
-       /* 2 */ 0, "SIGINT: interrupt",
+       /* 1 */ Q+R, "SIGHUP: terminal line hangup",
+       /* 2 */ Q+R, "SIGINT: interrupt",
        /* 3 */ C, "SIGQUIT: quit",
        /* 4 */ C, "SIGILL: illegal instruction",
        /* 5 */ C, "SIGTRAP: trace trap",       /* used by panic and array out of bounds, etc. */
@@ -21,27 +22,28 @@ static SigTab sigtab[] = {
        /* 11 */        C, "SIGSEGV: segmentation violation",
        /* 12 */        C, "SIGSYS: bad system call",
        /* 13 */        I, "SIGPIPE: write to broken pipe",
-       /* 14 */        0, "SIGALRM: alarm clock",
-       /* 15 */        0, "SIGTERM: termination",
-       /* 16 */        0, "SIGURG: urgent condition on socket",
+       /* 14 */        Q+R, "SIGALRM: alarm clock",
+       /* 15 */        Q+R, "SIGTERM: termination",
+       /* 16 */        Q+R, "SIGURG: urgent condition on socket",
        /* 17 */        0, "SIGSTOP: stop",
-       /* 18 */        0, "SIGTSTP: keyboard stop",
+       /* 18 */        Q+R, "SIGTSTP: keyboard stop",
        /* 19 */        0, "SIGCONT: continue after stop",
        /* 20 */        I+R, "SIGCHLD: child status has changed",
-       /* 21 */        0, "SIGTTIN: background read from tty",
-       /* 22 */        0, "SIGTTOU: background write to tty",
-       /* 23 */        0, "SIGIO: i/o now possible",
-       /* 24 */        0, "SIGXCPU: cpu limit exceeded",
-       /* 25 */        0, "SIGXFSZ: file size limit exceeded",
-       /* 26 */        0, "SIGVTALRM: virtual alarm clock",
-       /* 27 */        0, "SIGPROF: profiling alarm clock",
-       /* 28 */        I+R, "SIGWINCH: window size change",
-       /* 29 */        0, "SIGINFO: status request from keyboard",
-       /* 30 */        0, "SIGUSR1: user-defined signal 1",
-       /* 31 */        0, "SIGUSR2: user-defined signal 2",
+       /* 21 */        Q+R, "SIGTTIN: background read from tty",
+       /* 22 */        Q+R, "SIGTTOU: background write to tty",
+       /* 23 */        Q+R, "SIGIO: i/o now possible",
+       /* 24 */        Q+R, "SIGXCPU: cpu limit exceeded",
+       /* 25 */        Q+R, "SIGXFSZ: file size limit exceeded",
+       /* 26 */        Q+R, "SIGVTALRM: virtual alarm clock",
+       /* 27 */        Q+R, "SIGPROF: profiling alarm clock",
+       /* 28 */        Q+R, "SIGWINCH: window size change",
+       /* 29 */        Q+R, "SIGINFO: status request from keyboard",
+       /* 30 */        Q+R, "SIGUSR1: user-defined signal 1",
+       /* 31 */        Q+R, "SIGUSR2: user-defined signal 2",
 };
 #undef C
 #undef I
 #undef R
+#undef Q
 
 #define        NSIG 32
index 575caf1f2143c36147bf91b25bf46f3f53b63a6d..27cb73c5582c6f1d375113f806e68434611e9c93 100644 (file)
@@ -59,3 +59,10 @@ func Semacquire(s *uint32)
 // It is intended as a simple wakeup primitive for use by the synchronization
 // library and should not be used directly.
 func Semrelease(s *uint32)
+
+// Sigrecv returns a bitmask of signals that have arrived since the last call to Sigrecv.
+// It blocks until at least one signal arrives.
+func Sigrecv() uint32
+
+// Signame returns a string describing the signal, or "" if the signal is unknown.
+func Signame(sig int32) string
index 1654d2bc3b552f44999aea35797bb771f57d69df..7bad780844a894312d0d55bf6d00f0bbee41b8f5 100644 (file)
@@ -1,3 +1,7 @@
+// 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.
+
 #include "runtime.h"
 #include "defs.h"
 #include "signals.h"
@@ -32,12 +36,25 @@ dumpregs(Mcontext *r)
        printf("gs      %x\n", r->mc_gs);
 }
 
+String
+signame(int32 sig)
+{
+       if(sig < 0 || sig >= NSIG)
+               return emptystring;
+       return gostring((byte*)sigtab[sig].name);
+}
+
 void
 sighandler(int32 sig, Siginfo* info, void* context)
 {
        Ucontext *uc;
        Mcontext *mc;
 
+       if(sigtab[sig].flags & SigQueue) {
+               sigsend(sig);
+               return;
+       }
+
        if(panicking)   // traceback already printed
                exit(2);
        panicking = 1;
@@ -85,13 +102,15 @@ initsig(void)
 {
        static Sigaction sa;
 
+       siginit();
+
        int32 i;
        sa.sa_flags |= SA_ONSTACK | SA_SIGINFO;
        sa.sa_mask = ~0x0ull;
        
        for(i = 0; i < NSIG; i++) {
                if(sigtab[i].flags) {
-                       if(sigtab[i].flags & SigCatch)
+                       if(sigtab[i].flags & (SigCatch | SigQueue))
                                sa.__sigaction_u.__sa_sigaction = (void*) sigtramp;
                        else
                                sa.__sigaction_u.__sa_sigaction = (void*) sigignore;
index a7ed8260e9eae3b2b980426de38a96e3010b061f..ed03db1bcc6339bec76a96a992c362f4f78a170e 100644 (file)
@@ -1,3 +1,7 @@
+// 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.
+
 #include "runtime.h"
 #include "defs.h"
 #include "signals.h"
@@ -40,12 +44,25 @@ dumpregs(Mcontext *r)
        printf("gs      %X\n", r->mc_gs);
 }
 
+String
+signame(int32 sig)
+{
+       if(sig < 0 || sig >= NSIG)
+               return emptystring;
+       return gostring((byte*)sigtab[sig].name);
+}
+
 void
 sighandler(int32 sig, Siginfo* info, void* context)
 {
        Ucontext *uc;
        Mcontext *mc;
 
+       if(sigtab[sig].flags & SigQueue) {
+               sigsend(sig);
+               return;
+       }
+
        if(panicking)   // traceback already printed
                exit(2);
        panicking = 1;
@@ -93,13 +110,15 @@ initsig(void)
 {
        static Sigaction sa;
 
+       siginit();
+
        int32 i;
        sa.sa_flags |= SA_ONSTACK | SA_SIGINFO;
        sa.sa_mask = ~0x0ull;
        
        for(i = 0; i < NSIG; i++) {
                if(sigtab[i].flags) {
-                       if(sigtab[i].flags & SigCatch)
+                       if(sigtab[i].flags & (SigCatch | SigQueue))
                                sa.__sigaction_u.__sa_sigaction = (void*) sigtramp;
                        else
                                sa.__sigaction_u.__sa_sigaction = (void*) sigignore;
index c566481e0581e8451e5f69b7b6ca60306133ae1e..91ddef8889600616c1a6a3a257191d486c3a8502 100644 (file)
@@ -5,11 +5,12 @@
 #define C SigCatch
 #define I SigIgnore
 #define R SigRestart
+#define Q SigQueue
 
 static SigTab sigtab[] = {
        /* 0 */         0, "SIGNONE: no trap",
-       /* 1 */         0, "SIGHUP: terminal line hangup",
-       /* 2 */         0, "SIGINT: interrupt",
+       /* 1 */         Q+R, "SIGHUP: terminal line hangup",
+       /* 2 */         Q+R, "SIGINT: interrupt",
        /* 3 */         C, "SIGQUIT: quit",
        /* 4 */         C, "SIGILL: illegal instruction",
        /* 5 */         C, "SIGTRAP: trace trap",
@@ -21,28 +22,29 @@ static SigTab sigtab[] = {
        /* 11 */        C, "SIGSEGV: segmentation violation",
        /* 12 */        C, "SIGSYS: bad system call",
        /* 13 */        I, "SIGPIPE: write to broken pipe",
-       /* 14 */        0, "SIGALRM: alarm clock",
-       /* 15 */        0, "SIGTERM: termination",
-       /* 16 */        0, "SIGURG: urgent condition on socket",
+       /* 14 */        Q+R, "SIGALRM: alarm clock",
+       /* 15 */        Q+R, "SIGTERM: termination",
+       /* 16 */        Q+R, "SIGURG: urgent condition on socket",
        /* 17 */        0, "SIGSTOP: stop, unblockable",
-       /* 18 */        0, "SIGTSTP: stop from tty",
+       /* 18 */        Q+R, "SIGTSTP: stop from tty",
        /* 19 */        0, "SIGCONT: continue",
        /* 20 */        I+R, "SIGCHLD: child status has changed",
-       /* 21 */        0, "SIGTTIN: background read from tty",
-       /* 22 */        0, "SIGTTOU: background write to tty",
-       /* 23 */        0, "SIGIO: i/o now possible",
-       /* 24 */        0, "SIGXCPU: cpu limit exceeded",
-       /* 25 */        0, "SIGXFSZ: file size limit exceeded",
-       /* 26 */        0, "SIGVTALRM: virtual alarm clock",
-       /* 27 */        0, "SIGPROF: profiling alarm clock",
+       /* 21 */        Q+R, "SIGTTIN: background read from tty",
+       /* 22 */        Q+R, "SIGTTOU: background write to tty",
+       /* 23 */        Q+R, "SIGIO: i/o now possible",
+       /* 24 */        Q+R, "SIGXCPU: cpu limit exceeded",
+       /* 25 */        Q+R, "SIGXFSZ: file size limit exceeded",
+       /* 26 */        Q+R, "SIGVTALRM: virtual alarm clock",
+       /* 27 */        Q+R, "SIGPROF: profiling alarm clock",
        /* 28 */        I+R, "SIGWINCH: window size change",
-       /* 29 */        0, "SIGINFO: information request",
-       /* 30 */        0, "SIGUSR1: user-defined signal 1",
-       /* 31 */        0, "SIGUSR2: user-defined signal 2",
-       /* 32 */        0, "SIGTHR: reserved",
+       /* 29 */        Q+R, "SIGINFO: information request",
+       /* 30 */        Q+R, "SIGUSR1: user-defined signal 1",
+       /* 31 */        Q+R, "SIGUSR2: user-defined signal 2",
+       /* 32 */        Q+R, "SIGTHR: reserved",
 };
 #undef C
 #undef I
 #undef R
+#undef Q
 
 #define        NSIG 33
index 90685d8799f9444ef8d750d25719dd311c899fe3..2e6c7a5ff05548c0acc669df898016b1c1257211 100644 (file)
@@ -33,12 +33,25 @@ extern void sigtramp(void);
 extern void sigignore(void);   // just returns
 extern void sigreturn(void);   // calls sigreturn
 
+String
+signame(int32 sig)
+{
+       if(sig < 0 || sig >= NSIG)
+               return emptystring;
+       return gostring((byte*)sigtab[sig].name);
+}
+
 void
 sighandler(int32 sig, Siginfo* info, void* context)
 {
        Ucontext *uc;
        Sigcontext *sc;
 
+       if(sigtab[sig].flags & SigQueue) {
+               sigsend(sig);
+               return;
+       }
+
        if(panicking)   // traceback already printed
                exit(2);
        panicking = 1;
@@ -81,13 +94,15 @@ initsig(void)
 {
        static Sigaction sa;
 
+       siginit();
+
        int32 i;
        sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
        sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL;
        sa.sa_restorer = (void*)sigreturn;
        for(i = 0; i<NSIG; i++) {
                if(sigtab[i].flags) {
-                       if(sigtab[i].flags & SigCatch)
+                       if(sigtab[i].flags & (SigCatch | SigQueue))
                                sa.k_sa_handler = (void*)sigtramp;
                        else
                                sa.k_sa_handler = (void*)sigignore;
@@ -99,4 +114,3 @@ initsig(void)
                }
        }
 }
-
index 55215176dec4fdd6d65b22e681073148dc4b11c8..693b8c7042c0fe57b2cc316372dd3d9eb3831c7c 100644 (file)
@@ -41,6 +41,14 @@ extern void sigtramp(void);
 extern void sigignore(void);   // just returns
 extern void sigreturn(void);   // calls sigreturn
 
+String
+signame(int32 sig)
+{
+       if(sig < 0 || sig >= NSIG)
+               return emptystring;
+       return gostring((byte*)sigtab[sig].name);
+}
+
 void
 sighandler(int32 sig, Siginfo* info, void* context)
 {
@@ -48,6 +56,11 @@ sighandler(int32 sig, Siginfo* info, void* context)
        Mcontext *mc;
        Sigcontext *sc;
 
+       if(sigtab[sig].flags & SigQueue) {
+               sigsend(sig);
+               return;
+       }
+
        if(panicking)   // traceback already printed
                exit(2);
        panicking = 1;
@@ -91,13 +104,15 @@ initsig(void)
 {
        static Sigaction sa;
 
+       siginit();
+
        int32 i;
        sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
        sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL;
        sa.sa_restorer = (void*)sigreturn;
        for(i = 0; i<NSIG; i++) {
                if(sigtab[i].flags) {
-                       if(sigtab[i].flags & SigCatch)
+                       if(sigtab[i].flags & (SigCatch | SigQueue))
                                sa.sa_handler = (void*)sigtramp;
                        else
                                sa.sa_handler = (void*)sigignore;
@@ -109,4 +124,3 @@ initsig(void)
                }
        }
 }
-
index f14dcbf912c740d7aeac2c5bec4d7e67b7d181fa..2400575481ec3b6d89448855e5882c9f060615da 100644 (file)
@@ -35,6 +35,14 @@ extern void sigtramp(void);
 extern void sigignore(void);   // just returns
 extern void sigreturn(void);   // calls sigreturn
 
+String
+signame(int32 sig)
+{
+       if(sig < 0 || sig >= NSIG)
+               return emptystring;
+       return gostring((byte*)sigtab[sig].name);
+}
+
 void sighandler(void) {}
 // void
 // sighandler(int32 sig, Siginfo* info, void* context)
index 8f1112b99192071c8d8129ac5d403ca06e4337e5..883ac4e04ae395f000b4d4a17c2dc7a0bae01870 100644 (file)
@@ -5,11 +5,12 @@
 #define C SigCatch
 #define I SigIgnore
 #define R SigRestart
+#define Q SigQueue
 
 static SigTab sigtab[] = {
        /* 0 */ 0, "SIGNONE: no trap",
-       /* 1 */ 0, "SIGHUP: terminal line hangup",
-       /* 2 */ 0, "SIGINT: interrupt",
+       /* 1 */ Q+R, "SIGHUP: terminal line hangup",
+       /* 2 */ Q+R, "SIGINT: interrupt",
        /* 3 */ C, "SIGQUIT: quit",
        /* 4 */ C, "SIGILL: illegal instruction",
        /* 5 */ C, "SIGTRAP: trace trap",
@@ -17,31 +18,32 @@ static SigTab sigtab[] = {
        /* 7 */ C, "SIGBUS: bus error",
        /* 8 */ C, "SIGFPE: floating-point exception",
        /* 9 */ 0, "SIGKILL: kill",
-       /* 10 */        0, "SIGUSR1: user-defined signal 1",
+       /* 10 */        Q+R, "SIGUSR1: user-defined signal 1",
        /* 11 */        C, "SIGSEGV: segmentation violation",
-       /* 12 */        0, "SIGUSR2: user-defined signal 2",
+       /* 12 */        Q+R, "SIGUSR2: user-defined signal 2",
        /* 13 */        I, "SIGPIPE: write to broken pipe",
-       /* 14 */        0, "SIGALRM: alarm clock",
-       /* 15 */        0, "SIGTERM: termination",
-       /* 16 */        0, "SIGSTKFLT: stack fault",
-       /* 17 */        I+R, "SIGCHLD: child status has changed",
+       /* 14 */        Q+R, "SIGALRM: alarm clock",
+       /* 15 */        Q+R, "SIGTERM: termination",
+       /* 16 */        Q+R, "SIGSTKFLT: stack fault",
+       /* 17 */        Q+R, "SIGCHLD: child status has changed",
        /* 18 */        0, "SIGCONT: continue",
        /* 19 */        0, "SIGSTOP: stop, unblockable",
-       /* 20 */        0, "SIGTSTP: keyboard stop",
-       /* 21 */        0, "SIGTTIN: background read from tty",
-       /* 22 */        0, "SIGTTOU: background write to tty",
-       /* 23 */        0, "SIGURG: urgent condition on socket",
-       /* 24 */        0, "SIGXCPU: cpu limit exceeded",
-       /* 25 */        0, "SIGXFSZ: file size limit exceeded",
-       /* 26 */        0, "SIGVTALRM: virtual alarm clock",
-       /* 27 */        0, "SIGPROF: profiling alarm clock",
-       /* 28 */        I+R, "SIGWINCH: window size change",
-       /* 29 */        0, "SIGIO: i/o now possible",
-       /* 30 */        0, "SIGPWR: power failure restart",
+       /* 20 */        Q+R, "SIGTSTP: keyboard stop",
+       /* 21 */        Q+R, "SIGTTIN: background read from tty",
+       /* 22 */        Q+R, "SIGTTOU: background write to tty",
+       /* 23 */        Q+R, "SIGURG: urgent condition on socket",
+       /* 24 */        Q+R, "SIGXCPU: cpu limit exceeded",
+       /* 25 */        Q+R, "SIGXFSZ: file size limit exceeded",
+       /* 26 */        Q+R, "SIGVTALRM: virtual alarm clock",
+       /* 27 */        Q+R, "SIGPROF: profiling alarm clock",
+       /* 28 */        Q+R, "SIGWINCH: window size change",
+       /* 29 */        Q+R, "SIGIO: i/o now possible",
+       /* 30 */        Q+R, "SIGPWR: power failure restart",
        /* 31 */        C, "SIGSYS: bad system call",
 };
 #undef C
 #undef I
 #undef R
+#undef Q
 
 #define        NSIG 32
index e81089bfae03c3892f15955c622c0a091dec575f..60d76bc0f7425e70a67601ebb9ab34cf2a671622 100644 (file)
@@ -527,12 +527,9 @@ gosched(void)
 // Record that it's not using the cpu anymore.
 // This is called only from the go syscall library, not
 // from the low-level system calls used by the runtime.
-// The "arguments" are syscall.Syscall's stack frame
 void
-runtime·entersyscall(uint64 callerpc, int64 trap)
+runtime·entersyscall(void)
 {
-       USED(callerpc, trap);
-
        lock(&sched);
        if(sched.predawn) {
                unlock(&sched);
index 54bc9d8f2d80486ef3886aefe336080df3cd214a..46df412b399c19c71922dfd875047bdffe576bf7 100644 (file)
@@ -235,6 +235,7 @@ enum
        SigCatch = 1<<0,
        SigIgnore = 1<<1,
        SigRestart = 1<<2,
+       SigQueue = 1<<3,
 };
 
 // (will be) shared with go; edit ../cmd/6g/sys.go too.
@@ -373,6 +374,10 @@ void       breakpoint(void);
 void   gosched(void);
 void   goexit(void);
 void   runcgo(void (*fn)(void*), void*);
+void   entersyscall(void);
+void   exitsyscall(void);
+void   siginit(void);
+void   sigsend(int32 sig);
 
 #pragma        varargck        argpos  printf  1
 
@@ -485,6 +490,8 @@ float64     ldexp(float64 d, int32 e);
 float64        modf(float64 d, float64 *ip);
 void   semacquire(uint32*);
 void   semrelease(uint32*);
+String signame(int32 sig);
+
 
 void   mapassign(Hmap*, byte*, byte*);
 void   mapaccess(Hmap*, byte*, byte*, bool*);
diff --git a/src/pkg/runtime/sigqueue.cgo b/src/pkg/runtime/sigqueue.cgo
new file mode 100644 (file)
index 0000000..059d3ed
--- /dev/null
@@ -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);
+}