Patchwork libgo patch committed: Catch signals on alternate stack

login
register
mail settings
Submitter Ian Taylor
Date Dec. 21, 2011, 10:29 p.m.
Message ID <mcry5u51ru2.fsf@dhcp-172-18-216-180.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/132745/
State New
Headers show

Comments

Ian Taylor - Dec. 21, 2011, 10:29 p.m.
This patch to libgo catches most signals on the alternate signal stack.
The only ones caught on the normal stack are the ones which can occur
synchronously: SIGSEGV, SIGBUS, SIGFPE.  While updating the signal code
I also used SA_SIGINFO to distinguish expected signals (null
dereferences, division by zero) from unexpected ones, and to either
panic or throw as appropriate.

That change permits me to tell the split stack code to not bother
disabling signals while splitting the stack, which is also in this
patch.  This is now OK because if some signal arrives while splitting
the stack, it will be handled entirely on the alternate stack.
Admittedly this won't work well if SIGSEGV, SIGBUS, or SIGFPE arrive
while splitting the stack.  Oh well.  At some point I will have to
implement unwinding the stack of a different goroutine, and this issue
can be fixed at that time.

This reduces the number of sigprocmask calls in the net/http test from
26,597 to 2,276 (before my last patch to libgcc it was 3,604,100).

Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian
Richard Henderson - Dec. 21, 2011, 10:55 p.m.
On 12/21/2011 02:29 PM, Ian Lance Taylor wrote:
> +/* Ignore a signal.  This is called on the alternate signal stack so
> +   it may not split the stack.  */
> +
> +static void sig_ignore (int) __attribute__ ((no_split_stack));
>  
>  static void
>  sig_ignore (int sig __attribute__ ((unused)))
>  {
>  }

Does SIG_IGN not work for some reason?


r~
Ian Taylor - Dec. 21, 2011, 11:52 p.m.
Richard Henderson <rth@redhat.com> writes:

> On 12/21/2011 02:29 PM, Ian Lance Taylor wrote:
>> +/* Ignore a signal.  This is called on the alternate signal stack so
>> +   it may not split the stack.  */
>> +
>> +static void sig_ignore (int) __attribute__ ((no_split_stack));
>>  
>>  static void
>>  sig_ignore (int sig __attribute__ ((unused)))
>>  {
>>  }
>
> Does SIG_IGN not work for some reason?

It probably does work.  I was just copying the way the master library
works.  I don't know why it doesn't use SIG_IGN.  Fixing the master
library is something to look into at some later date, I think.

Ian

Patch

diff -r 950f4ee58444 libgo/runtime/go-panic.c
--- a/libgo/runtime/go-panic.c	Tue Dec 20 10:48:30 2011 -0800
+++ b/libgo/runtime/go-panic.c	Wed Dec 21 14:21:31 2011 -0800
@@ -24,13 +24,13 @@ 
   if (p->__next != NULL)
     {
       __printpanics (p->__next);
-      printf ("\t");
+      fprintf (stderr, "\t");
     }
-  printf ("panic: ");
+  fprintf (stderr, "panic: ");
   printany (p->__arg);
   if (p->__was_recovered)
-    printf (" [recovered]");
-  putchar ('\n');
+    fprintf (stderr, " [recovered]");
+  fputc ('\n', stderr);
 }
 
 /* This implements __go_panic which is used for the panic
diff -r 950f4ee58444 libgo/runtime/go-signal.c
--- a/libgo/runtime/go-signal.c	Tue Dec 20 10:48:30 2011 -0800
+++ b/libgo/runtime/go-signal.c	Wed Dec 21 14:21:31 2011 -0800
@@ -17,109 +17,133 @@ 
   #define SA_RESTART 0
 #endif
 
-/* What to do for a signal.  */
+#ifdef USING_SPLIT_STACK
 
-struct sigtab
-{
-  /* Signal number.  */
-  int sig;
-  /* Nonzero if the signal should be caught.  */
-  _Bool catch;
-  /* Nonzero if the signal should be queued.  */
-  _Bool queue;
-  /* Nonzero if the signal should be ignored.  */
-  _Bool ignore;
-  /* Nonzero if we should restart system calls.  */
-  _Bool restart;
-};
+extern void __splitstack_getcontext(void *context[10]);
 
-/* What to do for signals.  */
+extern void __splitstack_setcontext(void *context[10]);
 
-static struct sigtab signals[] =
-{
-  { SIGHUP, 0, 1, 0, 1 },
-  { SIGINT, 0, 1, 0, 1 },
-  { SIGQUIT, 0, 1, 0, 1 },
-  { SIGALRM, 0, 1, 1, 1 },
-  { SIGTERM, 0, 1, 0, 1 },
+#endif
+
+#define C SigCatch
+#define I SigIgnore
+#define R SigRestart
+#define Q SigQueue
+#define P SigPanic
+
+/* Signal actions.  This collects the sigtab tables for several
+   different targets from the master library.  SIGKILL, SIGCONT, and
+   SIGSTOP are not listed, as we don't want to set signal handlers for
+   them.  */
+
+SigTab runtime_sigtab[] = {
+#ifdef SIGHUP
+  { SIGHUP,	Q + R },
+#endif
+#ifdef SIGINT
+  { SIGINT, 	Q + R },
+#endif
+#ifdef SIGQUIT
+  { SIGQUIT, 	C },
+#endif
 #ifdef SIGILL
-  { SIGILL, 1, 0, 0, 0 },
+  { SIGILL, 	C },
 #endif
 #ifdef SIGTRAP
-  { SIGTRAP, 1, 0, 0, 0 },
+  { SIGTRAP, 	C },
 #endif
 #ifdef SIGABRT
-  { SIGABRT, 1, 0, 0, 0 },
+  { SIGABRT, 	C },
 #endif
 #ifdef SIGBUS
-  { SIGBUS, 1, 0, 0, 0 },
+  { SIGBUS, 	C + P },
 #endif
 #ifdef SIGFPE
-  { SIGFPE, 1, 0, 0, 0 },
+  { SIGFPE, 	C + P },
 #endif
 #ifdef SIGUSR1
-  { SIGUSR1, 0, 1, 1, 1 },
+  { SIGUSR1, 	Q + I + R },
 #endif
 #ifdef SIGSEGV
-  { SIGSEGV, 1, 0, 0, 0 },
+  { SIGSEGV, 	C + P },
 #endif
 #ifdef SIGUSR2
-  { SIGUSR2, 0, 1, 1, 1 },
+  { SIGUSR2, 	Q + I + R },
 #endif
 #ifdef SIGPIPE
-  { SIGPIPE, 0, 0, 1, 0 },
+  { SIGPIPE, 	I },
+#endif
+#ifdef SIGALRM
+  { SIGALRM, 	Q + I + R },
+#endif
+#ifdef SIGTERM
+  { SIGTERM, 	Q + R },
 #endif
 #ifdef SIGSTKFLT
-  { SIGSTKFLT, 1, 0, 0, 0 },
+  { SIGSTKFLT, 	C },
 #endif
 #ifdef SIGCHLD
-  { SIGCHLD, 0, 1, 1, 1 },
+  { SIGCHLD, 	Q + I + R },
 #endif
 #ifdef SIGTSTP
-  { SIGTSTP, 0, 1, 1, 1 },
+  { SIGTSTP, 	Q + I + R },
 #endif
 #ifdef SIGTTIN
-  { SIGTTIN, 0, 1, 1, 1 },
+  { SIGTTIN, 	Q + I + R },
 #endif
 #ifdef SIGTTOU
-  { SIGTTOU, 0, 1, 1, 1 },
+  { SIGTTOU, 	Q + I + R },
 #endif
 #ifdef SIGURG
-  { SIGURG, 0, 1, 1, 1 },
+  { SIGURG, 	Q + I + R },
 #endif
 #ifdef SIGXCPU
-  { SIGXCPU, 0, 1, 1, 1 },
+  { SIGXCPU, 	Q + I + R },
 #endif
 #ifdef SIGXFSZ
-  { SIGXFSZ, 0, 1, 1, 1 },
+  { SIGXFSZ, 	Q + I + R },
 #endif
-#ifdef SIGVTARLM
-  { SIGVTALRM, 0, 1, 1, 1 },
+#ifdef SIGVTALRM
+  { SIGVTALRM, 	Q + I + R },
 #endif
 #ifdef SIGPROF
-  { SIGPROF, 0, 1, 1, 1 },
+  { SIGPROF, 	Q + I + R },
 #endif
 #ifdef SIGWINCH
-  { SIGWINCH, 0, 1, 1, 1 },
+  { SIGWINCH, 	Q + I + R },
 #endif
 #ifdef SIGIO
-  { SIGIO, 0, 1, 1, 1 },
+  { SIGIO, 	Q + I + R },
 #endif
 #ifdef SIGPWR
-  { SIGPWR, 0, 1, 1, 1 },
+  { SIGPWR, 	Q + I + R },
 #endif
 #ifdef SIGSYS
-  { SIGSYS, 1, 0, 0, 0 },
+  { SIGSYS, 	C },
 #endif
-  { -1, 0, 0, 0, 0 }
+#ifdef SIGEMT
+  { SIGEMT,	C },
+#endif
+#ifdef SIGINFO
+  { SIGINFO,	Q + I + R },
+#endif
+#ifdef SIGTHR
+  { SIGTHR,	Q + I + R },
+#endif
+  { -1,		0 }
 };
+#undef C
+#undef I
+#undef R
+#undef Q
+#undef P
 
-/* The Go signal handler.  */
+/* Handle a signal, for cases where we don't panic.  We can split the
+   stack here.  */
 
 static void
-sighandler (int sig)
+sig_handler (int sig)
 {
-  const char *msg;
   int i;
 
 #ifdef SIGPROF
@@ -131,99 +155,223 @@ 
     }
 #endif
 
-  /* FIXME: Should check siginfo for more information when
-     available.  */
-  msg = NULL;
+  for (i = 0; runtime_sigtab[i].sig != -1; ++i)
+    {
+      struct sigaction sa;
+
+      if (runtime_sigtab[i].sig != sig)
+	continue;
+
+      if ((runtime_sigtab[i].flags & SigQueue) != 0)
+	{
+	  if (__go_sigsend (sig)
+	      || (runtime_sigtab[sig].flags & SigIgnore) != 0)
+	    return;
+	  runtime_exit (2);		// SIGINT, SIGTERM, etc
+	}
+
+      if (runtime_panicking)
+	runtime_exit (2);
+      runtime_panicking = 1;
+
+      /* We should do a stack backtrace here.  Until we can do that,
+	 we reraise the signal in order to get a slightly better
+	 report from the shell.  */
+
+      memset (&sa, 0, sizeof sa);
+
+      sa.sa_handler = SIG_DFL;
+
+      i = sigemptyset (&sa.sa_mask);
+      __go_assert (i == 0);
+
+      if (sigaction (sig, &sa, NULL) != 0)
+	abort ();
+
+      raise (sig);
+
+      runtime_exit (2);
+    }
+
+  __builtin_unreachable ();
+}
+
+/* The start of handling a signal which panics.  */
+
+static void
+sig_panic_leadin (int sig)
+{
+  int i;
+  sigset_t clear;
+
+  if (runtime_m ()->mallocing)
+    {
+      runtime_printf ("caught signal while mallocing: %d\n", sig);
+      runtime_throw ("caught signal while mallocing");
+    }
+
+  /* The signal handler blocked signals; unblock them.  */
+  i = sigfillset (&clear);
+  __go_assert (i == 0);
+  i = sigprocmask (SIG_UNBLOCK, &clear, NULL);
+  __go_assert (i == 0);
+}
+
+#ifdef SA_SIGINFO
+
+/* Signal dispatch for signals which panic, on systems which support
+   SA_SIGINFO.  This is called on the thread stack, and as such it is
+   permitted to split the stack.  */
+
+static void
+sig_panic_info_handler (int sig, siginfo_t *info,
+			void *context __attribute__ ((unused)))
+{
+  if (runtime_g () == NULL)
+    {
+      sig_handler (sig);
+      return;
+    }
+
+  sig_panic_leadin (sig);
+
   switch (sig)
     {
-#ifdef SIGILL
-    case SIGILL:
-      msg = "illegal instruction";
-      break;
+#ifdef SIGBUS
+    case SIGBUS:
+      if (info->si_code == BUS_ADRERR && (uintptr_t) info->si_addr < 0x1000)
+	runtime_panicstring ("invalid memory address or "
+			     "nil pointer dereference");
+      runtime_printf ("unexpected fault address %p\n", info->si_addr);
+      runtime_throw ("fault");
 #endif
 
-#ifdef SIGBUS
-    case SIGBUS:
-      msg = "invalid memory address or nil pointer dereference";
-      break;
+#ifdef SIGSEGV
+    case SIGSEGV:
+      if ((info->si_code == 0
+	   || info->si_code == SEGV_MAPERR
+	   || info->si_code == SEGV_ACCERR)
+	  && (uintptr_t) info->si_addr < 0x1000)
+	runtime_panicstring ("invalid memory address or "
+			     "nil pointer dereference");
+      runtime_printf ("unexpected fault address %p\n", info->si_addr);
+      runtime_throw ("fault");
 #endif
 
 #ifdef SIGFPE
     case SIGFPE:
-      msg = "integer divide by zero or floating point error";
-      break;
+      switch (info->si_code)
+	{
+	case FPE_INTDIV:
+	  runtime_panicstring ("integer divide by zero");
+	case FPE_INTOVF:
+	  runtime_panicstring ("integer overflow");
+	}
+      runtime_panicstring ("floating point error");
+#endif
+    }
+
+  /* All signals with SigPanic should be in cases above, and this
+     handler should only be invoked for those signals.  */
+  __builtin_unreachable ();
+}
+
+#else /* !defined (SA_SIGINFO) */
+
+static void
+sig_panic_handler (int sig)
+{
+  if (runtime_g () == NULL)
+    {
+      sig_handler (sig);
+      return;
+    }
+
+  sig_panic_leadin (sig);
+
+  switch (sig)
+    {
+#ifdef SIGBUS
+    case SIGBUS:
+      runtime_panicstring ("invalid memory address or "
+			   "nil pointer dereference");
 #endif
 
 #ifdef SIGSEGV
     case SIGSEGV:
-      msg = "invalid memory address or nil pointer dereference";
-      break;
+      runtime_panicstring ("invalid memory address or "
+			   "nil pointer dereference");
 #endif
 
-    default:
-      break;
+#ifdef SIGFPE
+    case SIGFPE:
+      runtime_panicstring ("integer divide by zero or floating point error");
+#endif
     }
 
-  if (msg != NULL)
-    {
-      sigset_t clear;
-
-      if (runtime_m()->mallocing)
-	{
-	  fprintf (stderr, "caught signal while mallocing: %s\n", msg);
-	  __go_assert (0);
-	}
-
-      /* The signal handler blocked signals; unblock them.  */
-      i = sigfillset (&clear);
-      __go_assert (i == 0);
-      i = sigprocmask (SIG_UNBLOCK, &clear, NULL);
-      __go_assert (i == 0);
-
-      runtime_panicstring (msg);
-    }
-
-  for (i = 0; signals[i].sig != -1; ++i)
-    {
-      if (signals[i].sig == sig)
-	{
-	  struct sigaction sa;
-
-	  if (signals[i].queue)
-	    {
-	      if (__go_sigsend (sig) || signals[i].ignore)
-		return;
-	      runtime_exit (2);		// SIGINT, SIGTERM, etc
-	    }
-
-	  if (runtime_panicking)
-	    runtime_exit (2);
-	  runtime_panicking = 1;
-
-	  memset (&sa, 0, sizeof sa);
-
-	  sa.sa_handler = SIG_DFL;
-
-	  i = sigemptyset (&sa.sa_mask);
-	  __go_assert (i == 0);
-
-	  if (sigaction (sig, &sa, NULL) != 0)
-	    abort ();
-
-	  raise (sig);
-	  exit (2);
-	}
-    }
-  abort ();
+  /* All signals with SigPanic should be in cases above, and this
+     handler should only be invoked for those signals.  */
+  __builtin_unreachable ();
 }
 
-/* Ignore a signal.  */
+#endif /* !defined (SA_SIGINFO) */
+
+/* Ignore a signal.  This is called on the alternate signal stack so
+   it may not split the stack.  */
+
+static void sig_ignore (int) __attribute__ ((no_split_stack));
 
 static void
 sig_ignore (int sig __attribute__ ((unused)))
 {
 }
 
+/* A signal handler used for signals which are not going to panic.
+   This is called on the alternate signal stack so it may not split
+   the stack.  */
+
+static void
+sig_tramp (int) __attribute__ ((no_split_stack));
+
+static void
+sig_tramp (int sig)
+{
+  G *gp;
+  M *mp;
+
+  /* We are now running on the stack registered via sigaltstack.
+     (Actually there is a small span of time between runtime_siginit
+     and sigaltstack when the program starts.)  */
+  gp = runtime_g ();
+  mp = runtime_m ();
+
+  if (gp != NULL)
+    __splitstack_getcontext (&gp->stack_context[0]);
+
+  if (gp != NULL && mp->gsignal != NULL)
+    {
+      /* We are running on the signal stack.  Set the split stack
+	 context so that the stack guards are checked correctly.  */
+#ifdef USING_SPLIT_STACK
+      __splitstack_setcontext (&mp->gsignal->stack_context[0]);
+#endif
+    }
+
+  sig_handler (sig);
+
+  /* We are going to return back to the signal trampoline and then to
+     whatever we were doing before we got the signal.  Restore the
+     split stack context so that stack guards are checked
+     correctly.  */
+
+  if (gp != NULL)
+    {
+#ifdef USING_SPLIT_STACK
+      __splitstack_setcontext (&gp->stack_context[0]);
+#endif
+    }
+}
+
 /* Initialize signal handling for Go.  This is called when the program
    starts.  */
 
@@ -237,21 +385,44 @@ 
 
   memset (&sa, 0, sizeof sa);
 
-  sa.sa_handler = sighandler;
-
   i = sigfillset (&sa.sa_mask);
   __go_assert (i == 0);
 
-  for (i = 0; signals[i].sig != -1; ++i)
+  for (i = 0; runtime_sigtab[i].sig != -1; ++i)
     {
-      if (signals[i].queue != (queue ? 1 : 0))
+      if (runtime_sigtab[i].flags == 0)
 	continue;
-      if (signals[i].catch || signals[i].queue)
-	sa.sa_handler = sighandler;
+      if ((runtime_sigtab[i].flags & SigQueue) != queue)
+	continue;
+
+      if ((runtime_sigtab[i].flags & (SigCatch | SigQueue)) != 0)
+	{
+	  if ((runtime_sigtab[i].flags & SigPanic) == 0)
+	    {
+	      sa.sa_flags = SA_ONSTACK;
+	      sa.sa_handler = sig_tramp;
+	    }
+	  else
+	    {
+#ifdef SA_SIGINFO
+	      sa.sa_flags = SA_SIGINFO;
+	      sa.sa_sigaction = sig_panic_info_handler;
+#else
+	      sa.sa_flags = 0;
+	      sa.sa_handler = sig_panic_handler;
+#endif
+	    }
+	}
       else
-	sa.sa_handler = sig_ignore;
-      sa.sa_flags = signals[i].restart ? SA_RESTART : 0;
-      if (sigaction (signals[i].sig, &sa, NULL) != 0)
+	{
+	  sa.sa_flags = SA_ONSTACK;
+	  sa.sa_handler = sig_ignore;
+	}
+
+      if ((runtime_sigtab[i].flags & SigRestart) != 0)
+	sa.sa_flags |= SA_RESTART;
+
+      if (sigaction (runtime_sigtab[i].sig, &sa, NULL) != 0)
 	__go_assert (0);
     }
 }
@@ -281,7 +452,7 @@ 
     }
   else
     {
-      sa.sa_handler = sighandler;
+      sa.sa_handler = sig_handler;
       sa.sa_flags = SA_RESTART;
       i = sigaction (SIGPROF, &sa, NULL);
       __go_assert (i == 0);
diff -r 950f4ee58444 libgo/runtime/mem.c
--- a/libgo/runtime/mem.c	Tue Dec 20 10:48:30 2011 -0800
+++ b/libgo/runtime/mem.c	Wed Dec 21 14:21:31 2011 -0800
@@ -47,7 +47,7 @@ 
 	if (dev_zero == -1) {
 		dev_zero = open("/dev/zero", O_RDONLY);
 		if (dev_zero < 0) {
-			printf("open /dev/zero: errno=%d\n", errno);
+			runtime_printf("open /dev/zero: errno=%d\n", errno);
 			exit(2);
 		}
 	}
@@ -57,8 +57,8 @@ 
 	p = runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, fd, 0);
 	if (p == MAP_FAILED) {
 		if(errno == EACCES) {
-			printf("runtime: mmap: access denied\n");
-			printf("if you're running SELinux, enable execmem for this process.\n");
+			runtime_printf("runtime: mmap: access denied\n");
+			runtime_printf("if you're running SELinux, enable execmem for this process.\n");
 			exit(2);
 		}
 		return nil;
@@ -97,7 +97,7 @@ 
 	if (dev_zero == -1) {
 		dev_zero = open("/dev/zero", O_RDONLY);
 		if (dev_zero < 0) {
-			printf("open /dev/zero: errno=%d\n", errno);
+			runtime_printf("open /dev/zero: errno=%d\n", errno);
 			exit(2);
 		}
 	}
@@ -123,7 +123,7 @@ 
 	if (dev_zero == -1) {
 		dev_zero = open("/dev/zero", O_RDONLY);
 		if (dev_zero < 0) {
-			printf("open /dev/zero: errno=%d\n", errno);
+			runtime_printf("open /dev/zero: errno=%d\n", errno);
 			exit(2);
 		}
 	}
diff -r 950f4ee58444 libgo/runtime/proc.c
--- a/libgo/runtime/proc.c	Tue Dec 20 10:48:30 2011 -0800
+++ b/libgo/runtime/proc.c	Wed Dec 21 14:21:31 2011 -0800
@@ -29,6 +29,11 @@ 
 extern void *__splitstack_find(void *, void *, size_t *, void **, void **,
 			       void **);
 
+extern void __splitstack_block_signals (int *, int *);
+
+extern void __splitstack_block_signals_context (void *context[10], int *,
+						int *);
+
 #endif
 
 #if defined(USING_SPLIT_STACK) && defined(LINKER_SUPPORTS_SPLIT_STACK)
@@ -862,6 +867,14 @@ 
 		*(int*)0x21 = 0x21;
 	}
 	runtime_minit();
+
+#ifdef USING_SPLIT_STACK
+	{
+	  int dont_block_signals = 0;
+	  __splitstack_block_signals(&dont_block_signals, nil);
+	}
+#endif
+
 	schedule(nil);
 	return nil;
 }
@@ -1142,9 +1155,13 @@ 
 	newg = runtime_malloc(sizeof(G));
 	if(stacksize >= 0) {
 #if USING_SPLIT_STACK
+		int dont_block_signals = 0;
+
 		*ret_stack = __splitstack_makecontext(stacksize,
 						      &newg->stack_context[0],
 						      ret_stacksize);
+		__splitstack_block_signals_context(&newg->stack_context[0],
+						   &dont_block_signals, nil);
 #else
 		*ret_stack = runtime_mallocgc(stacksize, FlagNoProfiling|FlagNoGC, 0, 0);
 		*ret_stacksize = stacksize;
@@ -1186,8 +1203,12 @@ 
 
 	if((newg = gfget()) != nil){
 #ifdef USING_SPLIT_STACK
+		int dont_block_signals = 0;
+
 		sp = __splitstack_resetcontext(&newg->stack_context[0],
 					       &spsize);
+		__splitstack_block_signals_context(&newg->stack_context[0],
+						   &dont_block_signals, nil);
 #else
 		sp = newg->gcinitial_sp;
 		spsize = newg->gcstack_size;
diff -r 950f4ee58444 libgo/runtime/runtime.h
--- a/libgo/runtime/runtime.h	Tue Dec 20 10:48:30 2011 -0800
+++ b/libgo/runtime/runtime.h	Wed Dec 21 14:21:31 2011 -0800
@@ -52,6 +52,7 @@ 
 typedef	union	Lock		Lock;
 typedef	struct	M		M;
 typedef	union	Note		Note;
+typedef	struct	SigTab		SigTab;
 typedef	struct	MCache		MCache;
 typedef struct	FixAlloc	FixAlloc;
 typedef	struct	Hchan		Hchan;
@@ -179,6 +180,20 @@ 
 	uint32	waitsemalock;
 };
 
+struct	SigTab
+{
+	int32	sig;
+	int32	flags;
+};
+enum
+{
+	SigCatch = 1<<0,
+	SigIgnore = 1<<1,
+	SigRestart = 1<<2,
+	SigQueue = 1<<3,
+	SigPanic = 1<<4,
+};
+
 /* Macros.  */
 
 #ifdef __WINDOWS__
@@ -251,7 +266,7 @@ 
 void	runtime_osinit();
 void	runtime_goargs(void);
 void	runtime_goenvs(void);
-void	runtime_throw(const char*);
+void	runtime_throw(const char*) __attribute__ ((noreturn));
 void	runtime_panicstring(const char*) __attribute__ ((noreturn));
 void*	runtime_mal(uintptr);
 void	runtime_schedinit(void);
diff -r 950f4ee58444 libgo/runtime/sigqueue.goc
--- a/libgo/runtime/sigqueue.goc	Tue Dec 20 10:48:30 2011 -0800
+++ b/libgo/runtime/sigqueue.goc	Wed Dec 21 14:21:31 2011 -0800
@@ -110,6 +110,6 @@ 
 }
 
 func Siginit() {
-	runtime_initsig(1);
+	runtime_initsig(SigQueue);
 	sig.inuse = true;	// enable reception of signals; cannot disable
 }