summaryrefslogtreecommitdiff
path: root/libgo/runtime/sigqueue.goc
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-03-02 16:38:43 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2012-03-02 16:38:43 +0000
commit2d2d80b8bd963f59534897b3d51ef8bd546cb4bc (patch)
treeefa0c55763b34cbc633bc494c2743d1b5d9aaff3 /libgo/runtime/sigqueue.goc
parent2ad2700dbf70b2e49575f3f2307839a45cf2f71c (diff)
downloadgcc-2d2d80b8bd963f59534897b3d51ef8bd546cb4bc.tar.gz
libgo: Update to weekly.2012-02-14 release.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@184798 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/runtime/sigqueue.goc')
-rw-r--r--libgo/runtime/sigqueue.goc120
1 files changed, 78 insertions, 42 deletions
diff --git a/libgo/runtime/sigqueue.goc b/libgo/runtime/sigqueue.goc
index e91571902c0..c550a4ebe9b 100644
--- a/libgo/runtime/sigqueue.goc
+++ b/libgo/runtime/sigqueue.goc
@@ -11,7 +11,7 @@
//
// 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).
+// The initial state is that sig.note is cleared (setup by signal_enable).
// At the beginning of each round, mask == 0.
// The round goes through three stages:
//
@@ -36,7 +36,7 @@
// ownership by returning from notesleep (caused by the notewakeup)
// and gives up ownership by clearing mask.
-package runtime
+package signal
#include "config.h"
#include "runtime.h"
#include "arch.h"
@@ -45,33 +45,29 @@ package runtime
static struct {
Note;
- uint32 mask;
+ uint32 mask[(NSIG+31)/32];
+ uint32 wanted[(NSIG+31)/32];
+ uint32 kick;
bool inuse;
} sig;
-void
-siginit(void)
-{
- runtime_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)
+ if(!sig.inuse || s < 0 || (size_t)s >= 32*nelem(sig.wanted) || !(sig.wanted[s/32]&(1U<<(s&31))))
return false;
- bit = 1 << s;
+ bit = 1 << (s&31);
for(;;) {
- mask = sig.mask;
+ mask = sig.mask[s/32];
if(mask & bit)
break; // signal already in queue
- if(runtime_cas(&sig.mask, mask, mask|bit)) {
+ if(runtime_cas(&sig.mask[s/32], mask, mask|bit)) {
// Added to queue.
- // Only send a wakeup for the first signal in each round.
- if(mask == 0)
+ // Only send a wakeup if the receiver needs a kick.
+ if(runtime_cas(&sig.kick, 1, 0))
runtime_notewakeup(&sig);
break;
}
@@ -79,37 +75,77 @@ __go_sigsend(int32 s)
return true;
}
-// Called to receive a bitmask of queued signals.
-func Sigrecv() (m uint32) {
- runtime_entersyscall();
- runtime_notesleep(&sig);
- runtime_exitsyscall();
- runtime_noteclear(&sig);
+// Called to receive the next queued signal.
+// Must only be called from a single goroutine at a time.
+func signal_recv() (m uint32) {
+ static uint32 recv[nelem(sig.mask)];
+ int32 i, more;
+
for(;;) {
- m = sig.mask;
- if(runtime_cas(&sig.mask, m, 0))
- break;
+ // Serve from local copy if there are bits left.
+ for(i=0; i<NSIG; i++) {
+ if(recv[i/32]&(1U<<(i&31))) {
+ recv[i/32] ^= 1U<<(i&31);
+ m = i;
+ goto done;
+ }
+ }
+
+ // Get a new local copy.
+ // Ask for a kick if more signals come in
+ // during or after our check (before the sleep).
+ if(sig.kick == 0) {
+ runtime_noteclear(&sig);
+ runtime_cas(&sig.kick, 0, 1);
+ }
+
+ more = 0;
+ for(i=0; (size_t)i<nelem(sig.mask); i++) {
+ for(;;) {
+ m = sig.mask[i];
+ if(runtime_cas(&sig.mask[i], m, 0))
+ break;
+ }
+ recv[i] = m;
+ if(m != 0)
+ more = 1;
+ }
+ if(more)
+ continue;
+
+ // Sleep waiting for more.
+ runtime_entersyscall();
+ runtime_notesleep(&sig);
+ runtime_exitsyscall();
}
+
+done:;
+ // goc requires that we fall off the end of functions
+ // that return values instead of using our own return
+ // statements.
}
-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;
+// Must only be called from a single goroutine at a time.
+func signal_enable(s uint32) {
+ int32 i;
+
+ if(!sig.inuse) {
+ // The first call to signal_enable is for us
+ // to use for initialization. It does not pass
+ // signal information in m.
+ sig.inuse = true; // enable reception of signals; cannot disable
+ runtime_noteclear(&sig);
+ return;
+ }
+
+ if(~s == 0) {
+ // Special case: want everything.
+ for(i=0; (size_t)i<nelem(sig.wanted); i++)
+ sig.wanted[i] = ~(uint32)0;
+ return;
}
- int32 len = __builtin_strlen(s);
- unsigned char *data = runtime_mallocgc(len, FlagNoPointers, 0, 0);
- __builtin_memcpy(data, s, len);
- name.__data = data;
- name.__length = len;
-}
-func Siginit() {
- runtime_initsig(SigQueue);
- sig.inuse = true; // enable reception of signals; cannot disable
+ if(s >= nelem(sig.wanted)*32)
+ return;
+ sig.wanted[s/32] |= 1U<<(s&31);
}