Re: [PATCH 2/2] patches/hurd-i386/submitted-hurdsig-*: Improve signals on Hurd
On Sat, Jul 23, 2011 at 08:54:28AM +0200, Jeremie Koenig wrote:
> --- a/debian/patches/series
> +++ b/debian/patches/series
(...)
> hurd-i386/local-madvise_warn.diff
> -hurd-i386/submitted-PTRACE_CONTINUE.diff
> hurd-i386/submitted-ldsodefs.h.diff
> +hurd-i386/submitted-hurdsig-fixes.diff
> +hurd-i386/submitted-hurdsig-global-dispositions.diff
> +hurd-i386/submitted-hurdsig-SA_SIGINFO.diff
Oh, submitted-hurdsig-fixes-2.diff is missing here.
I attach a fixed patch and will confirm it tests well when I finish
building the modified packages.
--
Jeremie Koenig <jk@jk.fr.eu.org>
http://jk.fr.eu.org
commit 47e01ef36e3941a0e23045a13b5022dd32f5fe71
Author: Jeremie Koenig <jk@jk.fr.eu.org>
Date: Thu Jun 16 18:07:39 2011 +0000
patches/hurd-i386/submitted-hurdsig-*: Improve signals on Hurd
New symbols are introduced by
patches/hurd-i386/submitted-hurdsig-global-dispositions.diff, for which the
version GLIBC_2.13_DEBIAN_11 is used temporarily. The plan is to create
aliases when these patches are merged upstream with the official one.
diff --git a/debian/changelog b/debian/changelog
index 6aa6149..de3baad 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -24,6 +24,13 @@ eglibc (2.13-11) UNRELEASED; urgency=low
[ Jeremie Koenig ]
* Add debian/libc0.3.symbols.hurd-i386.
+ * New patches to improve the signal code on Hurd:
+ patches/hurd-i386/submitted-hurdsig-fixes.diff,
+ patches/hurd-i386/submitted-hurdsig-global-dispositions.diff,
+ patches/hurd-i386/submitted-hurdsig-SA_SIGINFO.diff,
+ patches/hurd-i386/submitted-hurdsig-fixes-2.diff.
+ * Remove patches/hurd-i386/submitted-PTRACE_CONTINUE.diff, now covered by
+ submitted-hurdsig-fixes.diff.
[ Steve Langasek ]
* Try again to make libc6-dev multiarch-same.
diff --git a/debian/libc0.3.symbols.hurd-i386 b/debian/libc0.3.symbols.hurd-i386
index 7c9977f..cde325a 100644
--- a/debian/libc0.3.symbols.hurd-i386
+++ b/debian/libc0.3.symbols.hurd-i386
@@ -3,6 +3,7 @@ ld.so.1 #PACKAGE# #MINVER#
libc.so.0.3 #PACKAGE# #MINVER#
#include "symbols.wildcards"
*@HURD_CTHREADS_0.3 2.11
+ *@GLIBC_2.13_DEBIAN_11 2.13-11~
libBrokenLocale.so.1 #PACKAGE# #MINVER#
#include "symbols.wildcards"
libSegFault.so #PACKAGE# #MINVER#
diff --git a/debian/patches/hurd-i386/submitted-PTRACE_CONTINUE.diff b/debian/patches/hurd-i386/submitted-PTRACE_CONTINUE.diff
deleted file mode 100644
index bcfd266..0000000
--- a/debian/patches/hurd-i386/submitted-PTRACE_CONTINUE.diff
+++ /dev/null
@@ -1,29 +0,0 @@
-http://sourceware.org/ml/libc-alpha/2011-06/msg00124.html
-
-* hurd/hurdsig.c (post_signal): Don't call resume() with ACT uninitialized,
-as it might result in the target thread being left suspended.
----
- hurd/hurdsig.c | 7 +++++--
- 1 files changed, 5 insertions(+), 2 deletions(-)
-
-diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
-index 0ec0f27..74a01a6 100644
---- a/hurd/hurdsig.c
-+++ b/hurd/hurdsig.c
-@@ -558,8 +558,11 @@ post_signal (struct hurd_sigstate *ss,
- if (signo == 0)
- {
- if (untraced)
-- /* This is PTRACE_CONTINUE. */
-- resume ();
-+ {
-+ /* This is PTRACE_CONTINUE. */
-+ act = ignore;
-+ resume ();
-+ }
-
- /* This call is just to check for pending signals. */
- __spin_lock (&ss->lock);
---
-1.7.5.3
-
diff --git a/debian/patches/hurd-i386/submitted-hurdsig-SA_SIGINFO.diff b/debian/patches/hurd-i386/submitted-hurdsig-SA_SIGINFO.diff
new file mode 100644
index 0000000..405c351
--- /dev/null
+++ b/debian/patches/hurd-i386/submitted-hurdsig-SA_SIGINFO.diff
@@ -0,0 +1,527 @@
+diff --git a/hurd/hurd/signal.h b/hurd/hurd/signal.h
+index 1c4733a..cc96f21 100644
+--- a/hurd/hurd/signal.h
++++ b/hurd/hurd/signal.h
+@@ -264,6 +264,11 @@ extern void _hurd_raise_signal (struct hurd_sigstate *ss, int signo,
+ extern void _hurd_exception2signal (struct hurd_signal_detail *detail,
+ int *signo);
+
++/* Translate a Mach exception into a signal with a legacy sigcode. */
++
++extern void _hurd_exception2signal_legacy (struct hurd_signal_detail *detail,
++ int *signo);
++
+
+ /* Make the thread described by SS take the signal described by SIGNO and
+ DETAIL. If the process is traced, this will in fact stop with a SIGNO
+diff --git a/hurd/hurdinit.c b/hurd/hurdinit.c
+index 259f8a3..97d3460 100644
+--- a/hurd/hurdinit.c
++++ b/hurd/hurdinit.c
+@@ -176,7 +176,7 @@ _hurd_new_proc_init (char **argv,
+ /* This process is "traced", meaning it should stop on signals or exec.
+ We are all set up now to handle signals. Stop ourselves, to inform
+ our parent (presumably a debugger) that the exec has completed. */
+- __msg_sig_post (_hurd_msgport, SIGTRAP, 0, __mach_task_self ());
++ __msg_sig_post (_hurd_msgport, SIGTRAP, TRAP_TRACE, __mach_task_self ());
+ }
+
+ #include <shlib-compat.h>
+diff --git a/sysdeps/mach/hurd/bits/sigaction.h b/sysdeps/mach/hurd/bits/sigaction.h
+new file mode 100644
+index 0000000..4528b38
+--- /dev/null
++++ b/sysdeps/mach/hurd/bits/sigaction.h
+@@ -0,0 +1,79 @@
++/* Copyright (C) 1991,92,96,97,98,2001 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef _SIGNAL_H
++# error "Never include <bits/sigaction.h> directly; use <signal.h> instead."
++#endif
++
++/* These definitions match those used by the 4.4 BSD kernel.
++ If the operating system has a `sigaction' system call that correctly
++ implements the POSIX.1 behavior, there should be a system-dependent
++ version of this file that defines `struct sigaction' and the `SA_*'
++ constants appropriately. */
++
++/* Structure describing the action to be taken when a signal arrives. */
++struct sigaction
++ {
++ /* Signal handler. */
++#ifdef __USE_POSIX199309
++ union
++ {
++ /* Used if SA_SIGINFO is not set. */
++ __sighandler_t sa_handler;
++ /* Used if SA_SIGINFO is set. */
++ void (*sa_sigaction) (int, siginfo_t *, void *);
++ }
++ __sigaction_handler;
++# define sa_handler __sigaction_handler.sa_handler
++# define sa_sigaction __sigaction_handler.sa_sigaction
++#else
++ __sighandler_t sa_handler;
++#endif
++
++ /* Additional set of signals to be blocked. */
++ __sigset_t sa_mask;
++
++ /* Special flags. */
++ int sa_flags;
++ };
++
++/* Bits in `sa_flags'. */
++#if defined __USE_UNIX98 || defined __USE_MISC
++# define SA_ONSTACK 0x0001 /* Take signal on signal stack. */
++# define SA_RESTART 0x0002 /* Restart syscall on signal return. */
++# define SA_NODEFER 0x0010 /* Don't automatically block the signal when
++ its handler is being executed. */
++# define SA_RESETHAND 0x0004 /* Reset to SIG_DFL on entry to handler. */
++# define SA_SIGINFO 0x0040 /* Signal handler with SA_SIGINFO args */
++#endif
++#define SA_NOCLDSTOP 0x0008 /* Don't send SIGCHLD when children stop. */
++
++#ifdef __USE_MISC
++# define SA_INTERRUPT 0 /* Historical no-op ("not SA_RESTART"). */
++
++/* Some aliases for the SA_ constants. */
++# define SA_NOMASK SA_NODEFER
++# define SA_ONESHOT SA_RESETHAND
++# define SA_STACK SA_ONSTACK
++#endif
++
++
++/* Values for the HOW argument to `sigprocmask'. */
++#define SIG_BLOCK 1 /* Block signals. */
++#define SIG_UNBLOCK 2 /* Unblock signals. */
++#define SIG_SETMASK 3 /* Set the set of blocked signals. */
+diff --git a/sysdeps/mach/hurd/i386/bits/sigcontext.h b/sysdeps/mach/hurd/i386/bits/sigcontext.h
+index a78dd2f..1956d41 100644
+--- a/sysdeps/mach/hurd/i386/bits/sigcontext.h
++++ b/sysdeps/mach/hurd/i386/bits/sigcontext.h
+@@ -96,6 +96,10 @@ struct sigcontext
+ #define sc_ps sc_efl
+
+
++/* The deprecated sigcode values below are passed as an extra, non-portable
++ argument to regular signal handlers. You should use SA_SIGINFO handlers
++ instead, which use the standard POSIX signal codes. */
++
+ /* Codes for SIGFPE. */
+ #define FPE_INTOVF_TRAP 0x1 /* integer overflow */
+ #define FPE_INTDIV_FAULT 0x2 /* integer divide by zero */
+diff --git a/sysdeps/mach/hurd/i386/exc2signal.c b/sysdeps/mach/hurd/i386/exc2signal.c
+index a6bf750..7ffeb5f 100644
+--- a/sysdeps/mach/hurd/i386/exc2signal.c
++++ b/sysdeps/mach/hurd/i386/exc2signal.c
+@@ -24,8 +24,8 @@
+ /* Translate the Mach exception codes, as received in an `exception_raise' RPC,
+ into a signal number and signal subcode. */
+
+-void
+-_hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
++static void
++exception2signal (struct hurd_signal_detail *detail, int *signo, int posix)
+ {
+ detail->error = 0;
+
+@@ -37,44 +37,62 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
+ break;
+
+ case EXC_BAD_ACCESS:
+- if (detail->exc_code == KERN_INVALID_ADDRESS
+- || detail->exc_code == KERN_PROTECTION_FAILURE
+- || detail->exc_code == KERN_WRITE_PROTECTION_FAILURE)
+- *signo = SIGSEGV;
+- else
+- *signo = SIGBUS;
+- detail->code = detail->exc_subcode;
++ switch (detail->exc_code)
++ {
++ case KERN_INVALID_ADDRESS:
++ case KERN_MEMORY_FAILURE:
++ *signo = SIGSEGV;
++ detail->code = posix ? SEGV_MAPERR : detail->exc_subcode;
++ break;
++
++ case KERN_PROTECTION_FAILURE:
++ case KERN_WRITE_PROTECTION_FAILURE:
++ *signo = SIGSEGV;
++ detail->code = posix ? SEGV_ACCERR : detail->exc_subcode;
++ break;
++
++ default:
++ *signo = SIGBUS;
++ detail->code = 0;
++ break;
++ }
+ detail->error = detail->exc_code;
+ break;
+
+ case EXC_BAD_INSTRUCTION:
+ *signo = SIGILL;
+- if (detail->exc_code == EXC_I386_INVOP)
+- detail->code = ILL_INVOPR_FAULT;
+- else if (detail->exc_code == EXC_I386_STKFLT)
+- detail->code = ILL_STACK_FAULT;
+- else
+- detail->code = 0;
++ switch (detail->exc_code)
++ {
++ case EXC_I386_INVOP:
++ detail->code = posix ? ILL_ILLOPC : ILL_INVOPR_FAULT;
++ break;
++
++ case EXC_I386_STKFLT:
++ detail->code = posix ? ILL_BADSTK : ILL_STACK_FAULT;
++ break;
++
++ default:
++ detail->code = 0;
++ break;
++ }
+ break;
+
+ case EXC_ARITHMETIC:
++ *signo = SIGFPE;
+ switch (detail->exc_code)
+ {
+ case EXC_I386_DIV: /* integer divide by zero */
+- *signo = SIGFPE;
+- detail->code = FPE_INTDIV_FAULT;
++ detail->code = posix ? FPE_INTDIV : FPE_INTDIV_FAULT;
+ break;
+
+ case EXC_I386_INTO: /* integer overflow */
+- *signo = SIGFPE;
+- detail->code = FPE_INTOVF_TRAP;
++ detail->code = posix ? FPE_INTOVF : FPE_INTOVF_TRAP;
+ break;
+
+ /* These aren't anywhere documented or used in Mach 3.0. */
+ case EXC_I386_NOEXT:
+ case EXC_I386_EXTOVR:
+ default:
+- *signo = SIGFPE;
+ detail->code = 0;
+ break;
+
+@@ -83,51 +101,43 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
+ Give an error code corresponding to the first bit set. */
+ if (detail->exc_subcode & FPS_IE)
+ {
+- *signo = SIGILL;
+- detail->code = ILL_FPEOPR_FAULT;
++ /* NB: We used to send SIGILL here but we can't distinguish
++ POSIX vs. legacy with respect to what signal we send. */
++ detail->code = posix ? FPE_FLTINV : 0 /*ILL_FPEOPR_FAULT*/;
+ }
+ else if (detail->exc_subcode & FPS_DE)
+ {
+- *signo = SIGFPE;
+- detail->code = FPE_FLTDNR_FAULT;
++ detail->code = posix ? FPE_FLTUND : FPE_FLTDNR_FAULT;
+ }
+ else if (detail->exc_subcode & FPS_ZE)
+ {
+- *signo = SIGFPE;
+- detail->code = FPE_FLTDIV_FAULT;
++ detail->code = posix ? FPE_FLTDIV : FPE_FLTDIV_FAULT;
+ }
+ else if (detail->exc_subcode & FPS_OE)
+ {
+- *signo = SIGFPE;
+- detail->code = FPE_FLTOVF_FAULT;
++ detail->code = posix ? FPE_FLTOVF : FPE_FLTOVF_FAULT;
+ }
+ else if (detail->exc_subcode & FPS_UE)
+ {
+- *signo = SIGFPE;
+- detail->code = FPE_FLTUND_FAULT;
++ detail->code = posix ? FPE_FLTUND : FPE_FLTUND_FAULT;
+ }
+ else if (detail->exc_subcode & FPS_PE)
+ {
+- *signo = SIGFPE;
+- detail->code = FPE_FLTINX_FAULT;
++ detail->code = posix ? FPE_FLTRES : FPE_FLTINX_FAULT;
+ }
+ else
+ {
+- *signo = SIGFPE;
+ detail->code = 0;
+ }
+ break;
+
+ /* These two can only be arithmetic exceptions if we
+- are in V86 mode, which sounds like emulation to me.
+- (See Mach 3.0 i386/trap.c.) */
++ are in V86 mode. (See Mach 3.0 i386/trap.c.) */
+ case EXC_I386_EMERR:
+- *signo = SIGFPE;
+- detail->code = FPE_EMERR_FAULT;
++ detail->code = posix ? 0 : FPE_EMERR_FAULT;
+ break;
+ case EXC_I386_BOUND:
+- *signo = SIGFPE;
+- detail->code = FPE_EMBND_FAULT;
++ detail->code = posix ? FPE_FLTSUB : FPE_EMBND_FAULT;
+ break;
+ }
+ break;
+@@ -144,7 +154,7 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
+ if (detail->exc_code == EXC_I386_BOUND)
+ {
+ *signo = SIGFPE;
+- detail->code = FPE_SUBRNG_FAULT;
++ detail->code = posix ? FPE_FLTSUB : FPE_SUBRNG_FAULT;
+ }
+ else
+ {
+@@ -155,12 +165,33 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
+
+ case EXC_BREAKPOINT:
+ *signo = SIGTRAP;
+- if (detail->exc_code == EXC_I386_SGL)
+- detail->code = DBG_SINGLE_TRAP;
+- else if (detail->exc_code == EXC_I386_BPT)
+- detail->code = DBG_BRKPNT_FAULT;
+- else
+- detail->code = 0;
++ switch (detail->exc_code)
++ {
++ case EXC_I386_SGL:
++ detail->code = posix ? TRAP_BRKPT : DBG_SINGLE_TRAP;
++ break;
++
++ case EXC_I386_BPT:
++ detail->code = posix ? TRAP_BRKPT : DBG_BRKPNT_FAULT;
++ break;
++
++ default:
++ detail->code = 0;
++ break;
++ }
+ break;
+ }
+ }
++
++void
++_hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
++{
++ exception2signal (detail, signo, 1);
++}
++
++void
++_hurd_exception2signal_legacy (struct hurd_signal_detail *detail, int *signo)
++{
++ exception2signal (detail, signo, 0);
++}
++
+diff --git a/sysdeps/mach/hurd/i386/trampoline.c b/sysdeps/mach/hurd/i386/trampoline.c
+index ec52847..5abd33d 100644
+--- a/sysdeps/mach/hurd/i386/trampoline.c
++++ b/sysdeps/mach/hurd/i386/trampoline.c
+@@ -21,13 +21,66 @@
+ #include <hurd/signal.h>
+ #include <hurd/userlink.h>
+ #include <thread_state.h>
++#include <mach/exception.h>
+ #include <mach/machine/eflags.h>
+ #include <assert.h>
+ #include <errno.h>
+ #include "hurdfault.h"
+ #include <intr-msg.h>
++#include <sys/ucontext.h>
+
+
++/* Fill in a siginfo_t structure for SA_SIGINFO-enabled handlers. */
++static void fill_siginfo (siginfo_t *si, int signo,
++ const struct hurd_signal_detail *detail,
++ const struct machine_thread_all_state *state)
++{
++ si->si_signo = signo;
++ si->si_errno = detail->error;
++ si->si_code = detail->code;
++
++ /* XXX We would need a protocol change for sig_post to include
++ * this information. */
++ si->si_pid = -1;
++ si->si_uid = -1;
++
++ /* Address of the faulting instruction or memory access. */
++ if (detail->exc == EXC_BAD_ACCESS)
++ si->si_addr = (void *) detail->exc_subcode;
++ else
++ si->si_addr = (void *) state->basic.eip;
++
++ /* XXX On SIGCHLD, this should be the exit status of the child
++ * process. We would need a protocol change for the proc server
++ * to send this information along with the signal. */
++ si->si_status = 0;
++
++ si->si_band = 0; /* SIGPOLL is not supported yet. */
++ si->si_value.sival_int = 0; /* sigqueue() is not supported yet. */
++}
++
++/* Fill in a ucontext_t structure SA_SIGINFO-enabled handlers. */
++static void fill_ucontext (ucontext_t *uc, const struct sigcontext *sc)
++{
++ uc->uc_flags = 0;
++ uc->uc_link = NULL;
++ uc->uc_sigmask = sc->sc_mask;
++ uc->uc_stack.ss_sp = (__ptr_t) sc->sc_esp;
++ uc->uc_stack.ss_size = 0;
++ uc->uc_stack.ss_flags = 0;
++
++ /* Registers. */
++ memcpy (&uc->uc_mcontext.gregs[REG_GS], &sc->sc_gs,
++ (REG_TRAPNO - REG_GS) * sizeof (int));
++ uc->uc_mcontext.gregs[REG_TRAPNO] = 0;
++ uc->uc_mcontext.gregs[REG_ERR] = 0;
++ memcpy (&uc->uc_mcontext.gregs[REG_EIP], &sc->sc_eip,
++ (NGREG - REG_EIP) * sizeof (int));
++
++ /* XXX FPU state. */
++ memset (&uc->uc_mcontext.fpregs, 0, sizeof (fpregset_t));
++}
++
+ struct sigcontext *
+ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
+ int signo, struct hurd_signal_detail *detail,
+@@ -40,18 +93,37 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
+ extern const void _hurd_intr_rpc_msg_in_trap;
+ extern const void _hurd_intr_rpc_msg_cx_sp;
+ extern const void _hurd_intr_rpc_msg_sp_restored;
++ struct sigaction *action;
+ void *volatile sigsp;
+ struct sigcontext *scp;
+ struct
+ {
+ int signo;
+- long int sigcode;
+- struct sigcontext *scp; /* Points to ctx, below. */
++ union
++ {
++ /* Extra arguments for traditional signal handlers */
++ struct
++ {
++ long int sigcode;
++ struct sigcontext *scp; /* Points to ctx, below. */
++ } legacy;
++
++ /* Extra arguments for SA_SIGINFO handlers */
++ struct
++ {
++ siginfo_t *siginfop; /* Points to siginfo, below. */
++ ucontext_t *uctxp; /* Points to uctx, below. */
++ } posix;
++ };
+ void *sigreturn_addr;
+ void *sigreturn_returns_here;
+ struct sigcontext *return_scp; /* Same; arg to sigreturn. */
++
++ /* NB: sigreturn assumes link is next to ctx. */
+ struct sigcontext ctx;
+ struct hurd_userlink link;
++ ucontext_t ucontext;
++ siginfo_t siginfo;
+ } *stackframe;
+
+ if (ss->context)
+@@ -143,15 +215,9 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
+ = &stackframe->link.thread.next;
+ ss->active_resources = &stackframe->link;
+
+- /* Set up the arguments for the signal handler. */
+- stackframe->signo = signo;
+- stackframe->sigcode = detail->code;
+- stackframe->scp = stackframe->return_scp = scp = &stackframe->ctx;
+- stackframe->sigreturn_addr = &__sigreturn;
+- stackframe->sigreturn_returns_here = firewall; /* Crash on return. */
+-
+ /* Set up the sigcontext from the current state of the thread. */
+
++ scp = &stackframe->ctx;
+ scp->sc_onstack = ss->sigaltstack.ss_flags & SS_ONSTACK ? 1 : 0;
+
+ /* struct sigcontext is laid out so that starting at sc_gs mimics a
+@@ -165,6 +231,35 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
+ &state->fpu, &scp->sc_i386_float_state,
+ sizeof (state->fpu));
+
++ /* Set up the arguments for the signal handler. */
++ stackframe->signo = signo;
++ if (action->sa_flags & SA_SIGINFO)
++ {
++ stackframe->posix.siginfop = &stackframe->siginfo;
++ stackframe->posix.uctxp = &stackframe->ucontext;
++ fill_siginfo (&stackframe->siginfo, signo, detail, state);
++ fill_ucontext (&stackframe->ucontext, scp);
++ }
++ else
++ {
++ if (detail->exc)
++ {
++ int nsigno;
++ _hurd_exception2signal_legacy (detail, &nsigno);
++ assert (nsigno == signo);
++ }
++ else
++ detail->code = 0;
++
++ stackframe->legacy.sigcode = detail->code;
++ stackframe->legacy.scp = &stackframe->ctx;
++ }
++
++ /* Set up the bottom of the stack. */
++ stackframe->sigreturn_addr = &__sigreturn;
++ stackframe->sigreturn_returns_here = firewall; /* Crash on return. */
++ stackframe->return_scp = &stackframe->ctx;
++
+ _hurdsig_end_catch_fault ();
+
+ if (! ok)
+diff --git a/sysdeps/mach/hurd/kill.c b/sysdeps/mach/hurd/kill.c
+index a9946e0..ac7ffc7 100644
+--- a/sysdeps/mach/hurd/kill.c
++++ b/sysdeps/mach/hurd/kill.c
+@@ -65,7 +65,7 @@ __kill (pid_t pid, int sig)
+ {
+ if (msgport != MACH_PORT_NULL)
+ /* Send a signal message to his message port. */
+- return __msg_sig_post (msgport, sig, 0, refport);
++ return __msg_sig_post (msgport, sig, SI_USER, refport);
+
+ /* The process has no message port. Perhaps try direct
+ frobnication of the task. */
+diff --git a/sysdeps/mach/hurd/setitimer.c b/sysdeps/mach/hurd/setitimer.c
+index fec64a8..c82bfcd 100644
+--- a/sysdeps/mach/hurd/setitimer.c
++++ b/sysdeps/mach/hurd/setitimer.c
+@@ -105,7 +105,7 @@ timer_thread (void)
+ __msg_sig_post_request (_hurd_msgport,
+ _hurd_itimer_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+- SIGALRM, 0, __mach_task_self ());
++ SIGALRM, SI_TIMER, __mach_task_self ());
+ break;
+
+ case MACH_RCV_INTERRUPTED:
diff --git a/debian/patches/hurd-i386/submitted-hurdsig-fixes-2.diff b/debian/patches/hurd-i386/submitted-hurdsig-fixes-2.diff
new file mode 100644
index 0000000..f9fea2f
--- /dev/null
+++ b/debian/patches/hurd-i386/submitted-hurdsig-fixes-2.diff
@@ -0,0 +1,44 @@
+diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
+index 67037e8..44e067c 100644
+--- a/hurd/hurdsig.c
++++ b/hurd/hurdsig.c
+@@ -859,9 +859,7 @@ post_signal (struct hurd_sigstate *ss,
+ }
+
+ /* Handle receipt of a blocked signal, or any signal while stopped. */
+- if (act != ignore && /* Signals ignored now are forgotten now. */
+- __sigismember (&blocked, signo) ||
+- (signo != SIGKILL && _hurd_stopped))
++ if (__sigismember (&blocked, signo) || (signo != SIGKILL && _hurd_stopped))
+ {
+ mark_pending ();
+ act = ignore;
+diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
+index a4f3055..c74998d 100644
+--- a/sysdeps/mach/hurd/fork.c
++++ b/sysdeps/mach/hurd/fork.c
+@@ -648,8 +648,10 @@ __fork (void)
+ err = __USEPORT (PROC, __proc_getpids (port, &_hurd_pid, &_hurd_ppid,
+ &_hurd_orphaned));
+
+- /* Forking clears the trace flag. */
++ /* Forking clears the trace flag and pending masks. */
+ __sigemptyset (&_hurdsig_traced);
++ __sigemptyset (&_hurd_global_sigstate->pending);
++ __sigemptyset (&ss->pending);
+
+ /* Run things that want to run in the child task to set up. */
+ RUN_HOOK (_hurd_fork_child_hook, ());
+diff --git a/sysdeps/mach/hurd/spawni.c b/sysdeps/mach/hurd/spawni.c
+index 373da8d..2442e6f 100644
+--- a/sysdeps/mach/hurd/spawni.c
++++ b/sysdeps/mach/hurd/spawni.c
+@@ -241,7 +241,7 @@ __spawni (pid_t *pid, const char *file,
+
+ _hurd_sigstate_lock (ss);
+ ints[INIT_SIGMASK] = ss->blocked;
+- ints[INIT_SIGPENDING] = _hurd_sigstate_pending (ss); /* XXX really? */
++ ints[INIT_SIGPENDING] = 0;
+ ints[INIT_SIGIGN] = 0;
+ /* Unless we were asked to reset all handlers to SIG_DFL,
+ pass down the set of signals that were set to SIG_IGN. */
diff --git a/debian/patches/hurd-i386/submitted-hurdsig-fixes.diff b/debian/patches/hurd-i386/submitted-hurdsig-fixes.diff
new file mode 100644
index 0000000..994bd6f
--- /dev/null
+++ b/debian/patches/hurd-i386/submitted-hurdsig-fixes.diff
@@ -0,0 +1,352 @@
+diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
+index 7a6b1d5..74a01a6 100644
+--- a/hurd/hurdsig.c
++++ b/hurd/hurdsig.c
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1991,92,93,94,95,96,97,98,99,2000,2001,2002,2005,2008
++/* Copyright (C) 1991,92,93,94,95,96,97,98,99,2000,2001,2002,2005,2008,2011
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+@@ -443,6 +443,30 @@ abort_all_rpcs (int signo, struct machine_thread_all_state *state, int live)
+ }
+ }
+
++/* Wake up any sigsuspend call that is blocking SS->thread. SS must be
++ locked. */
++static void
++wake_sigsuspend (struct hurd_sigstate *ss)
++{
++ error_t err;
++ mach_msg_header_t msg;
++
++ if (ss->suspended == MACH_PORT_NULL)
++ return;
++
++ /* There is a sigsuspend waiting. Tell it to wake up. */
++ msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND, 0);
++ msg.msgh_remote_port = ss->suspended;
++ msg.msgh_local_port = MACH_PORT_NULL;
++ /* These values do not matter. */
++ msg.msgh_id = 8675309; /* Jenny, Jenny. */
++ ss->suspended = MACH_PORT_NULL;
++ err = __mach_msg (&msg, MACH_SEND_MSG, sizeof msg, 0,
++ MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
++ MACH_PORT_NULL);
++ assert_perror (err);
++}
++
+ struct hurd_signal_preemptor *_hurdsig_preemptors = 0;
+ sigset_t _hurdsig_preempted_set;
+
+@@ -453,35 +477,18 @@ weak_alias (_hurdsig_preemptors, _hurdsig_preempters)
+ #define STOPSIGS (sigmask (SIGTTIN) | sigmask (SIGTTOU) | \
+ sigmask (SIGSTOP) | sigmask (SIGTSTP))
+
+-/* Deliver a signal. SS is not locked. */
+-void
+-_hurd_internal_post_signal (struct hurd_sigstate *ss,
+- int signo, struct hurd_signal_detail *detail,
+- mach_port_t reply_port,
+- mach_msg_type_name_t reply_port_type,
+- int untraced)
++/* Actual delivery of a single signal. Called with SS unlocked. When
++ the signal is delivered, return 1 with SS locked. If the signal is
++ being traced, return 0 with SS unlocked. */
++static int
++post_signal (struct hurd_sigstate *ss,
++ int signo, struct hurd_signal_detail *detail,
++ int untraced, void (*reply) (void))
+ {
+- error_t err;
+ struct machine_thread_all_state thread_state;
+ enum { stop, ignore, core, term, handle } act;
+- sighandler_t handler;
+- sigset_t pending;
+ int ss_suspended;
+
+- /* Reply to this sig_post message. */
+- __typeof (__msg_sig_post_reply) *reply_rpc
+- = (untraced ? __msg_sig_post_untraced_reply : __msg_sig_post_reply);
+- void reply (void)
+- {
+- error_t err;
+- if (reply_port == MACH_PORT_NULL)
+- return;
+- err = (*reply_rpc) (reply_port, reply_port_type, 0);
+- reply_port = MACH_PORT_NULL;
+- if (err != MACH_SEND_INVALID_DEST) /* Ignore dead reply port. */
+- assert_perror (err);
+- }
+-
+ /* Mark the signal as pending. */
+ void mark_pending (void)
+ {
+@@ -545,19 +552,23 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
+ ss_suspended = 1;
+ }
+
++ error_t err;
++ sighandler_t handler;
++
+ if (signo == 0)
+ {
+ if (untraced)
+- /* This is PTRACE_CONTINUE. */
+- resume ();
++ {
++ /* This is PTRACE_CONTINUE. */
++ act = ignore;
++ resume ();
++ }
+
+ /* This call is just to check for pending signals. */
+ __spin_lock (&ss->lock);
+- goto check_pending_signals;
++ return 1;
+ }
+
+- post_signal:
+-
+ thread_state.set = 0; /* We know nothing. */
+
+ __spin_lock (&ss->lock);
+@@ -620,7 +631,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
+ suspend ();
+ __spin_unlock (&ss->lock);
+ reply ();
+- return;
++ return 0;
+ }
+
+ handler = ss->actions[signo].sa_handler;
+@@ -863,7 +874,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
+ as a unit. */
+ crit ? 0 : signo, 1,
+ &thread_state, &state_changed,
+- &reply)
++ reply)
+ != MACH_PORT_NULL);
+
+ if (crit)
+@@ -949,6 +960,9 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
+ && signo != SIGILL && signo != SIGTRAP)
+ ss->actions[signo].sa_handler = SIG_DFL;
+
++ /* Any sigsuspend call must return after the handler does. */
++ wake_sigsuspend (ss);
++
+ /* Start the thread running the handler (or possibly waiting for an
+ RPC reply before running the handler). */
+ err = __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
+@@ -962,95 +976,129 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
+ }
+ }
+
+- /* The signal has either been ignored or is now being handled. We can
+- consider it delivered and reply to the killer. */
+- reply ();
++ return 1;
++}
+
+- /* We get here unless the signal was fatal. We still hold SS->lock.
+- Check for pending signals, and loop to post them. */
+- {
+- /* Return nonzero if SS has any signals pending we should worry about.
+- We don't worry about any pending signals if we are stopped, nor if
+- SS is in a critical section. We are guaranteed to get a sig_post
+- message before any of them become deliverable: either the SIGCONT
+- signal, or a sig_post with SIGNO==0 as an explicit poll when the
+- thread finishes its critical section. */
+- inline int signals_pending (void)
+- {
+- if (_hurd_stopped || __spin_lock_locked (&ss->critical_section_lock))
+- return 0;
+- return pending = ss->pending & ~ss->blocked;
+- }
++/* Return the set of pending signals in SS which should be delivered. */
++static sigset_t
++pending_signals (struct hurd_sigstate *ss)
++{
++ /* We don't worry about any pending signals if we are stopped, nor if
++ SS is in a critical section. We are guaranteed to get a sig_post
++ message before any of them become deliverable: either the SIGCONT
++ signal, or a sig_post with SIGNO==0 as an explicit poll when the
++ thread finishes its critical section. */
++ if (_hurd_stopped || __spin_lock_locked (&ss->critical_section_lock))
++ return 0;
+
+- check_pending_signals:
+- untraced = 0;
++ return ss->pending & ~ss->blocked;
++}
+
+- if (signals_pending ())
+- {
+- for (signo = 1; signo < NSIG; ++signo)
+- if (__sigismember (&pending, signo))
+- {
+- deliver_pending:
+- __sigdelset (&ss->pending, signo);
+- *detail = ss->pending_data[signo];
+- __spin_unlock (&ss->lock);
+- goto post_signal;
+- }
+- }
++/* Post the specified pending signals in SS and return 1. If one of
++ them is traced, abort immediately and return 0. SS must be locked on
++ entry and will be unlocked in all cases. */
++static int
++post_pending (struct hurd_sigstate *ss, sigset_t pending, void (*reply) (void))
++{
++ int signo;
++ struct hurd_signal_detail detail;
+
+- /* No pending signals left undelivered for this thread.
+- If we were sent signal 0, we need to check for pending
+- signals for all threads. */
+- if (signo == 0)
+- {
+- __spin_unlock (&ss->lock);
+- __mutex_lock (&_hurd_siglock);
+- for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
+- {
+- __spin_lock (&ss->lock);
+- for (signo = 1; signo < NSIG; ++signo)
+- if (__sigismember (&ss->pending, signo)
+- && (!__sigismember (&ss->blocked, signo)
+- /* We "deliver" immediately pending blocked signals whose
+- action might be to ignore, so that if ignored they are
+- dropped right away. */
+- || ss->actions[signo].sa_handler == SIG_IGN
+- || ss->actions[signo].sa_handler == SIG_DFL))
+- {
+- mutex_unlock (&_hurd_siglock);
+- goto deliver_pending;
+- }
+- __spin_unlock (&ss->lock);
+- }
+- __mutex_unlock (&_hurd_siglock);
+- }
+- else
++ for (signo = 1; signo < NSIG; ++signo)
++ if (__sigismember (&pending, signo))
+ {
+- /* No more signals pending; SS->lock is still locked.
+- Wake up any sigsuspend call that is blocking SS->thread. */
+- if (ss->suspended != MACH_PORT_NULL)
+- {
+- /* There is a sigsuspend waiting. Tell it to wake up. */
+- error_t err;
+- mach_msg_header_t msg;
+- msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND, 0);
+- msg.msgh_remote_port = ss->suspended;
+- msg.msgh_local_port = MACH_PORT_NULL;
+- /* These values do not matter. */
+- msg.msgh_id = 8675309; /* Jenny, Jenny. */
+- ss->suspended = MACH_PORT_NULL;
+- err = __mach_msg (&msg, MACH_SEND_MSG, sizeof msg, 0,
+- MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+- MACH_PORT_NULL);
+- assert_perror (err);
+- }
++ __sigdelset (&ss->pending, signo);
++ detail = ss->pending_data[signo];
+ __spin_unlock (&ss->lock);
++
++ /* Will reacquire the lock, except if the signal is traced. */
++ if (! post_signal (ss, signo, &detail, 0, reply))
++ return 0;
+ }
+- }
+
+- /* All pending signals delivered to all threads.
+- Now we can send the reply message even for signal 0. */
+- reply ();
++ /* No more signals pending; SS->lock is still locked. */
++ __spin_unlock (&ss->lock);
++
++ return 1;
++}
++
++/* Post all the pending signals of all threads and return 1. If a traced
++ signal is encountered, abort immediately and return 0. */
++static int
++post_all_pending_signals (void (*reply) (void))
++{
++ struct hurd_sigstate *ss;
++ sigset_t pending;
++
++ for (;;)
++ {
++ __mutex_lock (&_hurd_siglock);
++ for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
++ {
++ __spin_lock (&ss->lock);
++
++ pending = pending_signals (ss);
++ if (pending)
++ /* post_pending() below will unlock SS. */
++ break;
++
++ __spin_unlock (&ss->lock);
++ }
++ __mutex_unlock (&_hurd_siglock);
++
++ if (! pending)
++ return 1;
++ if (! post_pending (ss, pending, reply))
++ return 0;
++ }
++}
++
++/* Deliver a signal. SS is not locked. */
++void
++_hurd_internal_post_signal (struct hurd_sigstate *ss,
++ int signo, struct hurd_signal_detail *detail,
++ mach_port_t reply_port,
++ mach_msg_type_name_t reply_port_type,
++ int untraced)
++{
++ /* Reply to this sig_post message. */
++ __typeof (__msg_sig_post_reply) *reply_rpc
++ = (untraced ? __msg_sig_post_untraced_reply : __msg_sig_post_reply);
++ void reply (void)
++ {
++ error_t err;
++ if (reply_port == MACH_PORT_NULL)
++ return;
++ err = (*reply_rpc) (reply_port, reply_port_type, 0);
++ reply_port = MACH_PORT_NULL;
++ if (err != MACH_SEND_INVALID_DEST) /* Ignore dead reply port. */
++ assert_perror (err);
++ }
++
++ if (! post_signal (ss, signo, detail, untraced, reply))
++ return;
++
++ /* The signal was neither fatal nor traced. We still hold SS->lock. */
++ if (signo != 0)
++ {
++ /* The signal has either been ignored or is now being handled. We can
++ consider it delivered and reply to the killer. */
++ reply ();
++
++ /* Post any pending signals for this thread. */
++ if (! post_pending (ss, pending_signals (ss), reply))
++ return;
++ }
++ else
++ {
++ /* We need to check for pending signals for all threads. */
++ __spin_unlock (&ss->lock);
++ if (! post_all_pending_signals (reply))
++ return;
++
++ /* All pending signals delivered to all threads.
++ Now we can send the reply message even for signal 0. */
++ reply ();
++ }
+ }
+
+ /* Decide whether REFPORT enables the sender to send us a SIGNO signal.
diff --git a/debian/patches/hurd-i386/submitted-hurdsig-global-dispositions.diff b/debian/patches/hurd-i386/submitted-hurdsig-global-dispositions.diff
new file mode 100644
index 0000000..50c7b54
--- /dev/null
+++ b/debian/patches/hurd-i386/submitted-hurdsig-global-dispositions.diff
@@ -0,0 +1,1238 @@
+diff --git a/Versions.def b/Versions.def
+index 98c2800..d20b95c 100644
+--- a/Versions.def
++++ b/Versions.def
+@@ -39,6 +39,7 @@ libc {
+ GCC_3.0
+ %endif
+ GLIBC_PRIVATE
++ GLIBC_2.13_DEBIAN_11
+ }
+ libcrypt {
+ GLIBC_2.0
+diff --git a/hurd/Versions b/hurd/Versions
+index 83c8ab1..b697019 100644
+--- a/hurd/Versions
++++ b/hurd/Versions
+@@ -156,6 +156,14 @@ libc {
+ # functions used in macros & inline functions
+ __errno_location;
+ }
++ GLIBC_2.13_DEBIAN_11 {
++ # functions used by libpthread and <hurd/signal.h>
++ _hurd_sigstate_set_global_rcv;
++ _hurd_sigstate_lock;
++ _hurd_sigstate_pending;
++ _hurd_sigstate_unlock;
++ _hurd_sigstate_delete;
++ }
+
+ %if !SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
+ HURD_CTHREADS_0.3 {
+diff --git a/hurd/ctty-input.c b/hurd/ctty-input.c
+index ef8395a..4da33c7 100644
+--- a/hurd/ctty-input.c
++++ b/hurd/ctty-input.c
+@@ -1,5 +1,5 @@
+ /* _hurd_ctty_input -- Do an input RPC and generate SIGTTIN if necessary.
+- Copyright (C) 1995,97,99 Free Software Foundation, Inc.
++ Copyright (C) 1995,97,99,2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -44,12 +44,15 @@ _hurd_ctty_input (io_t port, io_t ctty, error_t (*rpc) (io_t))
+ else
+ {
+ struct hurd_sigstate *ss = _hurd_self_sigstate ();
+- __spin_lock (&ss->lock);
++ struct sigaction *actions;
++
++ _hurd_sigstate_lock (ss);
++ actions = _hurd_sigstate_actions (ss);
+ if (__sigismember (&ss->blocked, SIGTTIN) ||
+- ss->actions[SIGTTIN].sa_handler == SIG_IGN)
++ actions[SIGTTIN].sa_handler == SIG_IGN)
+ /* We are blocking or ignoring SIGTTIN. Just fail. */
+ err = EIO;
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+
+ if (err == EBACKGROUND)
+ {
+@@ -66,10 +69,11 @@ _hurd_ctty_input (io_t port, io_t ctty, error_t (*rpc) (io_t))
+ SIGTTIN or resumed after being stopped. Now this is
+ still a "system call", so check to see if we should
+ restart it. */
+- __spin_lock (&ss->lock);
+- if (!(ss->actions[SIGTTIN].sa_flags & SA_RESTART))
++ _hurd_sigstate_lock (ss);
++ actions = _hurd_sigstate_actions (ss);
++ if (!(actions[SIGTTIN].sa_flags & SA_RESTART))
+ err = EINTR;
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+ }
+ }
+ }
+diff --git a/hurd/ctty-output.c b/hurd/ctty-output.c
+index 92ab95a..6e4bd74 100644
+--- a/hurd/ctty-output.c
++++ b/hurd/ctty-output.c
+@@ -1,5 +1,5 @@
+ /* _hurd_ctty_output -- Do an output RPC and generate SIGTTOU if necessary.
+- Copyright (C) 1995,97,99 Free Software Foundation, Inc.
++ Copyright (C) 1995,97,99,2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -35,16 +35,19 @@ _hurd_ctty_output (io_t port, io_t ctty, error_t (*rpc) (io_t))
+
+ do
+ {
++ struct sigaction *actions;
++
+ /* Don't use the ctty io port if we are blocking or ignoring
+ SIGTTOU. We redo this check at the top of the loop in case
+ the signal handler changed the state. */
+- __spin_lock (&ss->lock);
++ _hurd_sigstate_lock (ss);
++ actions = _hurd_sigstate_actions (ss);
+ if (__sigismember (&ss->blocked, SIGTTOU) ||
+- ss->actions[SIGTTOU].sa_handler == SIG_IGN)
++ actions[SIGTTOU].sa_handler == SIG_IGN)
+ err = EIO;
+ else
+ err = 0;
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+
+ if (err)
+ return (*rpc) (port);
+@@ -71,10 +74,11 @@ _hurd_ctty_output (io_t port, io_t ctty, error_t (*rpc) (io_t))
+ SIGTTOU or resumed after being stopped. Now this is
+ still a "system call", so check to see if we should
+ restart it. */
+- __spin_lock (&ss->lock);
+- if (!(ss->actions[SIGTTOU].sa_flags & SA_RESTART))
++ _hurd_sigstate_lock (ss);
++ actions = _hurd_sigstate_actions (ss);
++ if (!(actions[SIGTTOU].sa_flags & SA_RESTART))
+ err = EINTR;
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+ }
+ }
+ /* If the last RPC generated a SIGTTOU, loop to try it again. */
+diff --git a/hurd/hurd/signal.h b/hurd/hurd/signal.h
+index 21e30c5..1c4733a 100644
+--- a/hurd/hurd/signal.h
++++ b/hurd/hurd/signal.h
+@@ -1,5 +1,5 @@
+ /* Implementing POSIX.1 signals under the Hurd.
+- Copyright (C) 1993,94,95,96,98,99,2002,2007,2008
++ Copyright (C) 1993,94,95,96,98,99,2002,2007,2008,2011
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+@@ -71,7 +71,13 @@ struct hurd_sigstate
+
+ sigset_t blocked; /* What signals are blocked. */
+ sigset_t pending; /* Pending signals, possibly blocked. */
++
++ /* Signal handlers. ACTIONS[0] is used to mark the threads with POSIX
++ semantics: if sa_handler is SIG_IGN instead of SIG_DFL, this thread
++ will receive global signals and use the process-wide action vector
++ instead of this one. */
+ struct sigaction actions[NSIG];
++
+ struct sigaltstack sigaltstack;
+
+ /* Chain of thread-local signal preemptors; see <hurd/sigpreempt.h>.
+@@ -127,6 +133,26 @@ extern struct hurd_sigstate *_hurd_self_sigstate (void)
+ by different threads. */
+ __attribute__ ((__const__));
+
++/* Process-wide signal state. */
++
++extern struct hurd_sigstate *_hurd_global_sigstate;
++
++/* Mark the given thread as a process-wide signal receiver. */
++
++extern void _hurd_sigstate_set_global_rcv (struct hurd_sigstate *ss);
++
++/* A thread can either use its own action vector and pending signal set
++ or use the global ones, depending on wether it has been marked as a
++ global receiver. The accessors below take that into account. */
++
++extern void _hurd_sigstate_lock (struct hurd_sigstate *ss);
++extern struct sigaction *_hurd_sigstate_actions (struct hurd_sigstate *ss);
++extern sigset_t _hurd_sigstate_pending (const struct hurd_sigstate *ss);
++extern void _hurd_sigstate_unlock (struct hurd_sigstate *ss);
++
++/* Used by libpthread to remove stale sigstate structures. */
++extern void _hurd_sigstate_delete (thread_t thread);
++
+ #ifndef _HURD_SIGNAL_H_EXTERN_INLINE
+ #define _HURD_SIGNAL_H_EXTERN_INLINE __extern_inline
+ #endif
+@@ -150,12 +176,6 @@ extern thread_t _hurd_msgport_thread;
+
+ extern mach_port_t _hurd_msgport;
+
+-
+-/* Thread to receive process-global signals. */
+-
+-extern thread_t _hurd_sigthread;
+-
+-
+ /* Resource limit on core file size. Enforced by hurdsig.c. */
+ extern int _hurd_core_limit;
+
+@@ -203,10 +223,10 @@ _hurd_critical_section_unlock (void *our_lock)
+ /* It was us who acquired the critical section lock. Unlock it. */
+ struct hurd_sigstate *ss = our_lock;
+ sigset_t pending;
+- __spin_lock (&ss->lock);
++ _hurd_sigstate_lock (ss);
+ __spin_unlock (&ss->critical_section_lock);
+- pending = ss->pending & ~ss->blocked;
+- __spin_unlock (&ss->lock);
++ pending = _hurd_sigstate_pending(ss) & ~ss->blocked;
++ _hurd_sigstate_unlock (ss);
+ if (! __sigisemptyset (&pending))
+ /* There are unblocked signals pending, which weren't
+ delivered because we were in the critical section.
+diff --git a/hurd/hurdexec.c b/hurd/hurdexec.c
+index beae869..ee3162f 100644
+--- a/hurd/hurdexec.c
++++ b/hurd/hurdexec.c
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1991,92,93,94,95,96,97,99,2001,02
++/* Copyright (C) 1991,92,93,94,95,96,97,99,2001,2002,2011
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+@@ -109,12 +109,13 @@ _hurd_exec (task_t task, file_t file,
+ assert (! __spin_lock_locked (&ss->critical_section_lock));
+ __spin_lock (&ss->critical_section_lock);
+
+- __spin_lock (&ss->lock);
++ _hurd_sigstate_lock (ss);
++ struct sigaction *actions = _hurd_sigstate_actions (ss);
+ ints[INIT_SIGMASK] = ss->blocked;
+- ints[INIT_SIGPENDING] = ss->pending;
++ ints[INIT_SIGPENDING] = _hurd_sigstate_pending (ss);
+ ints[INIT_SIGIGN] = 0;
+ for (i = 1; i < NSIG; ++i)
+- if (ss->actions[i].sa_handler == SIG_IGN)
++ if (actions[i].sa_handler == SIG_IGN)
+ ints[INIT_SIGIGN] |= __sigmask (i);
+
+ /* We hold the sigstate lock until the exec has failed so that no signal
+@@ -125,7 +126,7 @@ _hurd_exec (task_t task, file_t file,
+ critical section flag avoids anything we call trying to acquire the
+ sigstate lock. */
+
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+
+ /* Pack up the descriptor table to give the new program. */
+ __mutex_lock (&_hurd_dtable_lock);
+diff --git a/hurd/hurdmsg.c b/hurd/hurdmsg.c
+index ffcce61..fdc7551 100644
+--- a/hurd/hurdmsg.c
++++ b/hurd/hurdmsg.c
+@@ -1,4 +1,5 @@
+-/* Copyright (C) 1992, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
++/* Copyright (C) 1992, 1994, 1995, 1996, 1997, 2011
++ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -122,17 +123,9 @@ get_int (int which, int *value)
+ case INIT_UMASK:
+ *value = _hurd_umask;
+ return 0;
+- case INIT_SIGMASK:
+- {
+- struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+- __spin_lock (&ss->lock);
+- *value = ss->blocked;
+- __spin_unlock (&ss->lock);
+- return 0;
+- }
+ case INIT_SIGPENDING:
+ {
+- struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
++ struct hurd_sigstate *ss = _hurd_global_sigstate;
+ __spin_lock (&ss->lock);
+ *value = ss->pending;
+ __spin_unlock (&ss->lock);
+@@ -140,7 +133,7 @@ get_int (int which, int *value)
+ }
+ case INIT_SIGIGN:
+ {
+- struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
++ struct hurd_sigstate *ss = _hurd_global_sigstate;
+ sigset_t ign;
+ int sig;
+ __spin_lock (&ss->lock);
+@@ -208,17 +201,9 @@ set_int (int which, int value)
+ return 0;
+
+ /* These are pretty odd things to do. But you asked for it. */
+- case INIT_SIGMASK:
+- {
+- struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
+- __spin_lock (&ss->lock);
+- ss->blocked = value;
+- __spin_unlock (&ss->lock);
+- return 0;
+- }
+ case INIT_SIGPENDING:
+ {
+- struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
++ struct hurd_sigstate *ss = _hurd_global_sigstate;
+ __spin_lock (&ss->lock);
+ ss->pending = value;
+ __spin_unlock (&ss->lock);
+@@ -226,7 +211,7 @@ set_int (int which, int value)
+ }
+ case INIT_SIGIGN:
+ {
+- struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
++ struct hurd_sigstate *ss = _hurd_global_sigstate;
+ int sig;
+ const sigset_t ign = value;
+ __spin_lock (&ss->lock);
+diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
+index 74a01a6..67037e8 100644
+--- a/hurd/hurdsig.c
++++ b/hurd/hurdsig.c
+@@ -44,9 +44,6 @@ mach_port_t _hurd_msgport;
+ /* Thread listening on it. */
+ thread_t _hurd_msgport_thread;
+
+-/* Thread which receives task-global signals. */
+-thread_t _hurd_sigthread;
+-
+ /* These are set up by _hurdsig_init. */
+ unsigned long int __hurd_sigthread_stack_base;
+ unsigned long int __hurd_sigthread_stack_end;
+@@ -55,6 +52,9 @@ unsigned long int *__hurd_sigthread_variables;
+ /* Linked-list of per-thread signal state. */
+ struct hurd_sigstate *_hurd_sigstates;
+
++/* Sigstate for the task-global signals. */
++struct hurd_sigstate *_hurd_global_sigstate;
++
+ /* Timeout for RPC's after interrupt_operation. */
+ mach_msg_timeout_t _hurd_interrupted_rpc_timeout = 3000;
+
+@@ -83,7 +83,7 @@ _hurd_thread_sigstate (thread_t thread)
+ {
+ ss = malloc (sizeof (*ss));
+ if (ss == NULL)
+- __libc_fatal ("hurd: Can't allocate thread sigstate\n");
++ __libc_fatal ("hurd: Can't allocate sigstate\n");
+ ss->thread = thread;
+ __spin_lock_init (&ss->lock);
+
+@@ -96,16 +96,19 @@ _hurd_thread_sigstate (thread_t thread)
+ ss->intr_port = MACH_PORT_NULL;
+ ss->context = NULL;
+
+- /* Initialize the sigaction vector from the default signal receiving
+- thread's state, and its from the system defaults. */
+- if (thread == _hurd_sigthread)
+- default_sigaction (ss->actions);
++ if (thread == MACH_PORT_NULL)
++ {
++ /* Process-wide sigstate, use the system defaults. */
++ default_sigaction (ss->actions);
++
++ /* The global sigstate is not added to the _hurd_sigstates list.
++ It is created with _hurd_thread_sigstate (MACH_PORT_NULL)
++ but should be accessed through _hurd_global_sigstate. */
++ }
+ else
+ {
+- struct hurd_sigstate *s;
+- for (s = _hurd_sigstates; s != NULL; s = s->next)
+- if (s->thread == _hurd_sigthread)
+- break;
++ /* Use the global actions as a default for new threads. */
++ struct hurd_sigstate *s = _hurd_global_sigstate;
+ if (s)
+ {
+ __spin_lock (&s->lock);
+@@ -114,14 +117,108 @@ _hurd_thread_sigstate (thread_t thread)
+ }
+ else
+ default_sigaction (ss->actions);
+- }
+
+- ss->next = _hurd_sigstates;
+- _hurd_sigstates = ss;
++ ss->next = _hurd_sigstates;
++ _hurd_sigstates = ss;
++ }
+ }
+ __mutex_unlock (&_hurd_siglock);
+ return ss;
+ }
++
++/* Destroy a sigstate structure. Called by libpthread just before the
++ * corresponding thread is terminated (the kernel thread port must remain valid
++ * until this function is called.) */
++void
++_hurd_sigstate_delete (thread_t thread)
++{
++ struct hurd_sigstate **ssp, *ss;
++
++ __mutex_lock (&_hurd_siglock);
++ for (ssp = &_hurd_sigstates; *ssp; ssp = &(*ssp)->next)
++ if ((*ssp)->thread == thread)
++ break;
++
++ ss = *ssp;
++ if (ss)
++ *ssp = ss->next;
++
++ __mutex_unlock (&_hurd_siglock);
++ if (ss)
++ free (ss);
++}
++
++/* Make SS a global receiver, with pthread signal semantics. */
++void
++_hurd_sigstate_set_global_rcv (struct hurd_sigstate *ss)
++{
++ assert (ss->thread != MACH_PORT_NULL);
++ ss->actions[0].sa_handler = SIG_IGN;
++}
++
++/* Check whether SS is a global receiver. */
++static int
++sigstate_is_global_rcv (const struct hurd_sigstate *ss)
++{
++ return ss->actions[0].sa_handler == SIG_IGN;
++}
++
++/* Lock/unlock a hurd_sigstate structure. If the accessors below require
++ it, the global sigstate will be locked as well. */
++void
++_hurd_sigstate_lock (struct hurd_sigstate *ss)
++{
++ if (sigstate_is_global_rcv (ss))
++ __spin_lock (&_hurd_global_sigstate->lock);
++ __spin_lock (&ss->lock);
++}
++void
++_hurd_sigstate_unlock (struct hurd_sigstate *ss)
++{
++ __spin_unlock (&ss->lock);
++ if (sigstate_is_global_rcv (ss))
++ __spin_unlock (&_hurd_global_sigstate->lock);
++}
++
++/* Retreive a thread's full set of pending signals, including the global
++ ones if appropriate. SS must be locked. */
++sigset_t
++_hurd_sigstate_pending (const struct hurd_sigstate *ss)
++{
++ sigset_t pending = ss->pending;
++ if (sigstate_is_global_rcv (ss))
++ __sigorset (&pending, &pending, &_hurd_global_sigstate->pending);
++ return pending;
++}
++
++/* Clear a pending signal and return the associated detailed
++ signal information. SS must be locked, and must have signal SIGNO
++ pending, either directly or through the global sigstate. */
++static struct hurd_signal_detail
++sigstate_clear_pending (struct hurd_sigstate *ss, int signo)
++{
++ if (sigstate_is_global_rcv (ss)
++ && __sigismember (&_hurd_global_sigstate->pending, signo))
++ {
++ __sigdelset (&_hurd_global_sigstate->pending, signo);
++ return _hurd_global_sigstate->pending_data[signo];
++ }
++
++ assert (__sigismember (&ss->pending, signo));
++ __sigdelset (&ss->pending, signo);
++ return ss->pending_data[signo];
++}
++
++/* Retreive a thread's action vector. SS must be locked. */
++struct sigaction *
++_hurd_sigstate_actions (struct hurd_sigstate *ss)
++{
++ if (sigstate_is_global_rcv (ss))
++ return _hurd_global_sigstate->actions;
++ else
++ return ss->actions;
++}
++
+
+ /* Signal delivery itself is on this page. */
+
+@@ -216,6 +313,8 @@ static void
+ abort_thread (struct hurd_sigstate *ss, struct machine_thread_all_state *state,
+ void (*reply) (void))
+ {
++ assert (ss->thread != MACH_PORT_NULL);
++
+ if (!(state->set & THREAD_ABORTED))
+ {
+ error_t err = __thread_abort (ss->thread);
+@@ -355,7 +454,7 @@ _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
+ call above will retry their RPCs unless we clear SS->intr_port.
+ So we clear it for the thread taking a signal when SA_RESTART is
+ clear, so that its call returns EINTR. */
+- if (! signo || !(ss->actions[signo].sa_flags & SA_RESTART))
++ if (! signo || !(_hurd_sigstate_actions (ss) [signo].sa_flags & SA_RESTART))
+ ss->intr_port = MACH_PORT_NULL;
+ }
+
+@@ -478,9 +577,11 @@ weak_alias (_hurdsig_preemptors, _hurdsig_preempters)
+ sigmask (SIGSTOP) | sigmask (SIGTSTP))
+
+ /* Actual delivery of a single signal. Called with SS unlocked. When
+- the signal is delivered, return 1 with SS locked. If the signal is
+- being traced, return 0 with SS unlocked. */
+-static int
++ the signal is delivered, return SS, locked (or, if SS was originally
++ _hurd_global_sigstate, the sigstate of the actual thread the signal
++ was delivered to). If the signal is being traced, return NULL with
++ SS unlocked. */
++static struct hurd_sigstate *
+ post_signal (struct hurd_sigstate *ss,
+ int signo, struct hurd_signal_detail *detail,
+ int untraced, void (*reply) (void))
+@@ -533,8 +634,12 @@ post_signal (struct hurd_sigstate *ss,
+ assert_perror (err);
+ for (i = 0; i < nthreads; ++i)
+ {
+- if (threads[i] != _hurd_msgport_thread &&
+- (act != handle || threads[i] != ss->thread))
++ if (act == handle && threads[i] == ss->thread)
++ {
++ /* The thread that will run the handler is kept suspended. */
++ ss_suspended = 1;
++ }
++ else if (threads[i] != _hurd_msgport_thread)
+ {
+ err = __thread_resume (threads[i]);
+ assert_perror (err);
+@@ -547,9 +652,6 @@ post_signal (struct hurd_sigstate *ss,
+ (vm_address_t) threads,
+ nthreads * sizeof *threads);
+ _hurd_stopped = 0;
+- if (act == handle)
+- /* The thread that will run the handler is already suspended. */
+- ss_suspended = 1;
+ }
+
+ error_t err;
+@@ -565,13 +667,43 @@ post_signal (struct hurd_sigstate *ss,
+ }
+
+ /* This call is just to check for pending signals. */
+- __spin_lock (&ss->lock);
+- return 1;
++ _hurd_sigstate_lock (ss);
++ return ss;
+ }
+
+ thread_state.set = 0; /* We know nothing. */
+
+- __spin_lock (&ss->lock);
++ _hurd_sigstate_lock (ss);
++
++ /* If this is a global signal, try to find a thread ready to accept
++ it right away. This is especially important for untraced signals,
++ since going through the global pending mask would de-untrace them. */
++ if (ss->thread == MACH_PORT_NULL)
++ {
++ struct hurd_sigstate *rss;
++
++ __mutex_lock (&_hurd_siglock);
++ for (rss = _hurd_sigstates; rss != NULL; rss = rss->next)
++ {
++ if (! sigstate_is_global_rcv (rss))
++ continue;
++
++ /* The global sigstate is already locked. */
++ __spin_lock (&rss->lock);
++ if (! __sigismember (&rss->blocked, signo))
++ {
++ ss = rss;
++ break;
++ }
++ __spin_unlock (&rss->lock);
++ }
++ __mutex_unlock (&_hurd_siglock);
++ }
++
++ /* We want the preemptors to be able to update the blocking mask
++ without affecting the delivery of this signal, so we save the
++ current value to test against later. */
++ sigset_t blocked = ss->blocked;
+
+ /* Check for a preempted signal. Preempted signals can arrive during
+ critical sections. */
+@@ -629,12 +761,12 @@ post_signal (struct hurd_sigstate *ss,
+ mark_pending ();
+ else
+ suspend ();
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+ reply ();
+- return 0;
++ return NULL;
+ }
+
+- handler = ss->actions[signo].sa_handler;
++ handler = _hurd_sigstate_actions (ss) [signo].sa_handler;
+
+ if (handler == SIG_DFL)
+ /* Figure out the default action for this signal. */
+@@ -728,7 +860,7 @@ post_signal (struct hurd_sigstate *ss,
+
+ /* Handle receipt of a blocked signal, or any signal while stopped. */
+ if (act != ignore && /* Signals ignored now are forgotten now. */
+- __sigismember (&ss->blocked, signo) ||
++ __sigismember (&blocked, signo) ||
+ (signo != SIGKILL && _hurd_stopped))
+ {
+ mark_pending ();
+@@ -764,6 +896,7 @@ post_signal (struct hurd_sigstate *ss,
+ now's the time to set it going. */
+ if (ss_suspended)
+ {
++ assert (ss->thread != MACH_PORT_NULL);
+ err = __thread_resume (ss->thread);
+ assert_perror (err);
+ ss_suspended = 0;
+@@ -808,6 +941,8 @@ post_signal (struct hurd_sigstate *ss,
+ struct sigcontext *scp, ocontext;
+ int wait_for_reply, state_changed;
+
++ assert (ss->thread != MACH_PORT_NULL);
++
+ /* Stop the thread and abort its pending RPC operations. */
+ if (! ss_suspended)
+ {
+@@ -942,23 +1077,25 @@ post_signal (struct hurd_sigstate *ss,
+ }
+ }
+
++ struct sigaction *action = & _hurd_sigstate_actions (ss) [signo];
++
+ /* Backdoor extra argument to signal handler. */
+ scp->sc_error = detail->error;
+
+ /* Block requested signals while running the handler. */
+ scp->sc_mask = ss->blocked;
+- __sigorset (&ss->blocked, &ss->blocked, &ss->actions[signo].sa_mask);
++ __sigorset (&ss->blocked, &ss->blocked, &action->sa_mask);
+
+ /* Also block SIGNO unless we're asked not to. */
+- if (! (ss->actions[signo].sa_flags & (SA_RESETHAND | SA_NODEFER)))
++ if (! (action->sa_flags & (SA_RESETHAND | SA_NODEFER)))
+ __sigaddset (&ss->blocked, signo);
+
+ /* Reset to SIG_DFL if requested. SIGILL and SIGTRAP cannot
+ be automatically reset when delivered; the system silently
+ enforces this restriction. */
+- if (ss->actions[signo].sa_flags & SA_RESETHAND
++ if (action->sa_flags & SA_RESETHAND
+ && signo != SIGILL && signo != SIGTRAP)
+- ss->actions[signo].sa_handler = SIG_DFL;
++ action->sa_handler = SIG_DFL;
+
+ /* Any sigsuspend call must return after the handler does. */
+ wake_sigsuspend (ss);
+@@ -976,7 +1113,7 @@ post_signal (struct hurd_sigstate *ss,
+ }
+ }
+
+- return 1;
++ return ss;
+ }
+
+ /* Return the set of pending signals in SS which should be delivered. */
+@@ -991,7 +1128,7 @@ pending_signals (struct hurd_sigstate *ss)
+ if (_hurd_stopped || __spin_lock_locked (&ss->critical_section_lock))
+ return 0;
+
+- return ss->pending & ~ss->blocked;
++ return _hurd_sigstate_pending (ss) & ~ss->blocked;
+ }
+
+ /* Post the specified pending signals in SS and return 1. If one of
+@@ -1003,12 +1140,15 @@ post_pending (struct hurd_sigstate *ss, sigset_t pending, void (*reply) (void))
+ int signo;
+ struct hurd_signal_detail detail;
+
++ /* Make sure SS corresponds to an actual thread, since we assume it won't
++ change in post_signal. */
++ assert (ss->thread != MACH_PORT_NULL);
++
+ for (signo = 1; signo < NSIG; ++signo)
+ if (__sigismember (&pending, signo))
+ {
+- __sigdelset (&ss->pending, signo);
+- detail = ss->pending_data[signo];
+- __spin_unlock (&ss->lock);
++ detail = sigstate_clear_pending (ss, signo);
++ _hurd_sigstate_unlock (ss);
+
+ /* Will reacquire the lock, except if the signal is traced. */
+ if (! post_signal (ss, signo, &detail, 0, reply))
+@@ -1016,7 +1156,7 @@ post_pending (struct hurd_sigstate *ss, sigset_t pending, void (*reply) (void))
+ }
+
+ /* No more signals pending; SS->lock is still locked. */
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+
+ return 1;
+ }
+@@ -1034,14 +1174,14 @@ post_all_pending_signals (void (*reply) (void))
+ __mutex_lock (&_hurd_siglock);
+ for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
+ {
+- __spin_lock (&ss->lock);
++ _hurd_sigstate_lock (ss);
+
+ pending = pending_signals (ss);
+ if (pending)
+ /* post_pending() below will unlock SS. */
+ break;
+
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+ }
+ __mutex_unlock (&_hurd_siglock);
+
+@@ -1074,11 +1214,12 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
+ assert_perror (err);
+ }
+
+- if (! post_signal (ss, signo, detail, untraced, reply))
++ ss = post_signal (ss, signo, detail, untraced, reply);
++ if (! ss)
+ return;
+
+ /* The signal was neither fatal nor traced. We still hold SS->lock. */
+- if (signo != 0)
++ if (signo != 0 && ss->thread != MACH_PORT_NULL)
+ {
+ /* The signal has either been ignored or is now being handled. We can
+ consider it delivered and reply to the killer. */
+@@ -1090,8 +1231,9 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
+ }
+ else
+ {
+- /* We need to check for pending signals for all threads. */
+- __spin_unlock (&ss->lock);
++ /* If this was a process-wide signal or a poll request, we need
++ to check for pending signals for all threads. */
++ _hurd_sigstate_unlock (ss);
+ if (! post_all_pending_signals (reply))
+ return;
+
+@@ -1217,9 +1359,10 @@ _S_msg_sig_post (mach_port_t me,
+ d.code = sigcode;
+ d.exc = 0;
+
+- /* Post the signal to the designated signal-receiving thread. This will
+- reply when the signal can be considered delivered. */
+- _hurd_internal_post_signal (_hurd_thread_sigstate (_hurd_sigthread),
++ /* Post the signal to a global receiver thread (or mark it pending in
++ the global sigstate). This will reply when the signal can be
++ considered delivered. */
++ _hurd_internal_post_signal (_hurd_global_sigstate,
+ signo, &d, reply_port, reply_port_type,
+ 0); /* Stop if traced. */
+
+@@ -1247,7 +1390,7 @@ _S_msg_sig_post_untraced (mach_port_t me,
+
+ /* Post the signal to the designated signal-receiving thread. This will
+ reply when the signal can be considered delivered. */
+- _hurd_internal_post_signal (_hurd_thread_sigstate (_hurd_sigthread),
++ _hurd_internal_post_signal (_hurd_global_sigstate,
+ signo, &d, reply_port, reply_port_type,
+ 1); /* Untraced flag. */
+
+@@ -1258,8 +1401,8 @@ extern void __mig_init (void *);
+
+ #include <mach/task_special_ports.h>
+
+-/* Initialize the message port and _hurd_sigthread and start the signal
+- thread. */
++/* Initialize the message port, _hurd_global_sigstate, and start the
++ signal thread. */
+
+ void
+ _hurdsig_init (const int *intarray, size_t intarraysize)
+@@ -1282,27 +1425,34 @@ _hurdsig_init (const int *intarray, size_t intarraysize)
+ MACH_MSG_TYPE_MAKE_SEND);
+ assert_perror (err);
+
++ /* Initialize the global signal state. */
++ _hurd_global_sigstate = _hurd_thread_sigstate (MACH_PORT_NULL);
++
++ /* We block all signals, and let actual threads pull them from the
++ pending mask. */
++ __sigfillset(& _hurd_global_sigstate->blocked);
++
+ /* Initialize the main thread's signal state. */
+ ss = _hurd_self_sigstate ();
+
+- /* Copy inherited values from our parent (or pre-exec process state)
+- into the signal settings of the main thread. */
++ /* Mark it as a process-wide signal receiver. Threads in this set use
++ the common action vector in _hurd_global_sigstate. */
++ _hurd_sigstate_set_global_rcv (ss);
++
++ /* Copy inherited signal settings from our parent (or pre-exec process
++ state) */
+ if (intarraysize > INIT_SIGMASK)
+ ss->blocked = intarray[INIT_SIGMASK];
+ if (intarraysize > INIT_SIGPENDING)
+- ss->pending = intarray[INIT_SIGPENDING];
++ _hurd_global_sigstate->pending = intarray[INIT_SIGPENDING];
+ if (intarraysize > INIT_SIGIGN && intarray[INIT_SIGIGN] != 0)
+ {
+ int signo;
+ for (signo = 1; signo < NSIG; ++signo)
+ if (intarray[INIT_SIGIGN] & __sigmask(signo))
+- ss->actions[signo].sa_handler = SIG_IGN;
++ _hurd_global_sigstate->actions[signo].sa_handler = SIG_IGN;
+ }
+
+- /* Set the default thread to receive task-global signals
+- to this one, the main (first) user thread. */
+- _hurd_sigthread = ss->thread;
+-
+ /* Start the signal thread listening on the message port. */
+
+ if (__hurd_threadvar_stack_mask == 0)
+diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
+index 3288f18..a4f3055 100644
+--- a/sysdeps/mach/hurd/fork.c
++++ b/sysdeps/mach/hurd/fork.c
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1994,1995,1996,1997,1999,2001,2002,2004,2005,2006
++/* Copyright (C) 1994,1995,1996,1997,1999,2001,2002,2004,2005,2006,2011
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+@@ -459,6 +459,7 @@ __fork (void)
+ function, accounted for by mach_port_names (and which will thus be
+ accounted for in the child below). This extra right gets consumed
+ in the child by the store into _hurd_sigthread in the child fork. */
++ /* XXX consumed? (_hurd_sigthread is no more) */
+ if (thread_refs > 1 &&
+ (err = __mach_port_mod_refs (newtask, ss->thread,
+ MACH_PORT_RIGHT_SEND,
+@@ -616,10 +617,6 @@ __fork (void)
+ for (i = 0; i < _hurd_nports; ++i)
+ __spin_unlock (&_hurd_ports[i].lock);
+
+- /* We are one of the (exactly) two threads in this new task, we
+- will take the task-global signals. */
+- _hurd_sigthread = ss->thread;
+-
+ /* Claim our sigstate structure and unchain the rest: the
+ threads existed in the parent task but don't exist in this
+ task (the child process). Delay freeing them until later
+@@ -640,6 +637,10 @@ __fork (void)
+ _hurd_sigstates = ss;
+ __mutex_unlock (&_hurd_siglock);
+
++ /* We are one of the (exactly) two threads in this new task, we
++ will take the task-global signals. */
++ _hurd_sigstate_set_global_rcv (ss);
++
+ /* Fetch our new process IDs from the proc server. No need to
+ refetch our pgrp; it is always inherited from the parent (so
+ _hurd_pgrp is already correct), and the proc server will send us a
+diff --git a/sysdeps/mach/hurd/i386/sigreturn.c b/sysdeps/mach/hurd/i386/sigreturn.c
+index 60b0d00..8cb92ef 100644
+--- a/sysdeps/mach/hurd/i386/sigreturn.c
++++ b/sysdeps/mach/hurd/i386/sigreturn.c
+@@ -1,4 +1,5 @@
+-/* Copyright (C) 1991,92,94,95,96,97,98,2001 Free Software Foundation, Inc.
++/* Copyright (C) 1991,92,94,95,96,97,98,2001,2011
++ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -39,7 +40,7 @@ __sigreturn (struct sigcontext *scp)
+ }
+
+ ss = _hurd_self_sigstate ();
+- __spin_lock (&ss->lock);
++ _hurd_sigstate_lock (ss);
+
+ /* Remove the link on the `active resources' chain added by
+ _hurd_setup_sighandler. Its purpose was to make sure
+@@ -51,19 +52,19 @@ __sigreturn (struct sigcontext *scp)
+ ss->intr_port = scp->sc_intr_port;
+
+ /* Check for pending signals that were blocked by the old set. */
+- if (ss->pending & ~ss->blocked)
++ if (_hurd_sigstate_pending (ss) & ~ss->blocked)
+ {
+ /* There are pending signals that just became unblocked. Wake up the
+ signal thread to deliver them. But first, squirrel away SCP where
+ the signal thread will notice it if it runs another handler, and
+ arrange to have us called over again in the new reality. */
+ ss->context = scp;
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+ __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
+ /* If a pending signal was handled, sig_post never returned.
+ If it did return, the pending signal didn't run a handler;
+ proceed as usual. */
+- __spin_lock (&ss->lock);
++ _hurd_sigstate_lock (ss);
+ ss->context = NULL;
+ }
+
+@@ -74,7 +75,7 @@ __sigreturn (struct sigcontext *scp)
+ abort ();
+ }
+ else
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+
+ /* Destroy the MiG reply port used by the signal handler, and restore the
+ reply port in use by the thread when interrupted. */
+diff --git a/sysdeps/mach/hurd/i386/trampoline.c b/sysdeps/mach/hurd/i386/trampoline.c
+index 99d9308..ec52847 100644
+--- a/sysdeps/mach/hurd/i386/trampoline.c
++++ b/sysdeps/mach/hurd/i386/trampoline.c
+@@ -1,5 +1,5 @@
+ /* Set thread_state for sighandler, and sigcontext to recover. i386 version.
+- Copyright (C) 1994,1995,1996,1997,1998,1999,2005,2008
++ Copyright (C) 1994,1995,1996,1997,1998,1999,2005,2008,2011
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+@@ -77,7 +77,11 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
+ interrupted RPC frame. */
+ state->basic.esp = state->basic.uesp;
+
+- if ((ss->actions[signo].sa_flags & SA_ONSTACK) &&
++ /* XXX what if handler != action->handler (for instance, if a signal
++ * preemptor took over) ? */
++ action = & _hurd_sigstate_actions (ss) [signo];
++
++ if ((action->sa_flags & SA_ONSTACK) &&
+ !(ss->sigaltstack.ss_flags & (SS_DISABLE|SS_ONSTACK)))
+ {
+ sigsp = ss->sigaltstack.ss_sp + ss->sigaltstack.ss_size;
+diff --git a/sysdeps/mach/hurd/sigaction.c b/sysdeps/mach/hurd/sigaction.c
+index fe452e8..bedf14c 100644
+--- a/sysdeps/mach/hurd/sigaction.c
++++ b/sysdeps/mach/hurd/sigaction.c
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2002, 2007
++/* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2002, 2007, 2011
+ Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+@@ -51,15 +51,15 @@ __sigaction (sig, act, oact)
+ ss = _hurd_self_sigstate ();
+
+ __spin_lock (&ss->critical_section_lock);
+- __spin_lock (&ss->lock);
+- old = ss->actions[sig];
++ _hurd_sigstate_lock (ss);
++ old = _hurd_sigstate_actions (ss) [sig];
+ if (act != NULL)
+- ss->actions[sig] = a;
++ _hurd_sigstate_actions (ss) [sig] = a;
+
+ if (act != NULL && sig == SIGCHLD &&
+ (a.sa_flags & SA_NOCLDSTOP) != (old.sa_flags & SA_NOCLDSTOP))
+ {
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+
+ /* Inform the proc server whether or not it should send us SIGCHLD for
+ stopped children. We do this in a critical section so that no
+@@ -67,8 +67,8 @@ __sigaction (sig, act, oact)
+ __USEPORT (PROC,
+ __proc_mod_stopchild (port, !(a.sa_flags & SA_NOCLDSTOP)));
+
+- __spin_lock (&ss->lock);
+- pending = ss->pending & ~ss->blocked;
++ _hurd_sigstate_lock (ss);
++ pending = _hurd_sigstate_pending (ss) & ~ss->blocked;
+ }
+ else if (act != NULL && (a.sa_handler == SIG_IGN || a.sa_handler == SIG_DFL))
+ /* We are changing to an action that might be to ignore SIG signals.
+@@ -77,11 +77,11 @@ __sigaction (sig, act, oact)
+ back and then SIG is unblocked, the signal pending now should not
+ arrive. So wake up the signal thread to check the new state and do
+ the right thing. */
+- pending = ss->pending & __sigmask (sig);
++ pending = _hurd_sigstate_pending (ss) & __sigmask (sig);
+ else
+ pending = 0;
+
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+ __spin_unlock (&ss->critical_section_lock);
+
+ if (pending)
+diff --git a/sysdeps/mach/hurd/sigpending.c b/sysdeps/mach/hurd/sigpending.c
+index 84ac927..f582d45 100644
+--- a/sysdeps/mach/hurd/sigpending.c
++++ b/sysdeps/mach/hurd/sigpending.c
+@@ -1,4 +1,5 @@
+-/* Copyright (C) 1991, 1993, 1994, 1995, 1997 Free Software Foundation, Inc.
++/* Copyright (C) 1991, 1993, 1994, 1995, 1997, 2011
++ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -38,9 +39,9 @@ sigpending (set)
+ }
+
+ ss = _hurd_self_sigstate ();
+- __spin_lock (&ss->lock);
+- pending = ss->pending;
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_lock (ss);
++ pending = _hurd_sigstate_pending (ss);
++ _hurd_sigstate_unlock (ss);
+
+ *set = pending;
+ return 0;
+diff --git a/sysdeps/mach/hurd/sigprocmask.c b/sysdeps/mach/hurd/sigprocmask.c
+index cbb5ecc..b12dc19 100644
+--- a/sysdeps/mach/hurd/sigprocmask.c
++++ b/sysdeps/mach/hurd/sigprocmask.c
+@@ -1,4 +1,5 @@
+-/* Copyright (C) 1991,92,93,94,95,96,97,2002 Free Software Foundation, Inc.
++/* Copyright (C) 1991,92,93,94,95,96,97,2002,2011
++ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -40,7 +41,7 @@ __sigprocmask (how, set, oset)
+
+ ss = _hurd_self_sigstate ();
+
+- __spin_lock (&ss->lock);
++ _hurd_sigstate_lock (ss);
+
+ old = ss->blocked;
+
+@@ -61,7 +62,7 @@ __sigprocmask (how, set, oset)
+ break;
+
+ default:
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+ errno = EINVAL;
+ return -1;
+ }
+@@ -69,9 +70,9 @@ __sigprocmask (how, set, oset)
+ ss->blocked &= ~_SIG_CANT_MASK;
+ }
+
+- pending = ss->pending & ~ss->blocked;
++ pending = _hurd_sigstate_pending (ss) & ~ss->blocked;
+
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+
+ if (oset != NULL)
+ *oset = old;
+diff --git a/sysdeps/mach/hurd/sigsuspend.c b/sysdeps/mach/hurd/sigsuspend.c
+index 7e32472..2e55e30 100644
+--- a/sysdeps/mach/hurd/sigsuspend.c
++++ b/sysdeps/mach/hurd/sigsuspend.c
+@@ -1,5 +1,5 @@
+-/* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2002, 2007
+- Free Software Foundation, Inc.
++/* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2002, 2007,
++ 2011 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+@@ -43,7 +43,7 @@ __sigsuspend (set)
+
+ ss = _hurd_self_sigstate ();
+
+- __spin_lock (&ss->lock);
++ _hurd_sigstate_lock (ss);
+
+ oldmask = ss->blocked;
+ if (set != NULL)
+@@ -51,11 +51,11 @@ __sigsuspend (set)
+ ss->blocked = newmask & ~_SIG_CANT_MASK;
+
+ /* Notice if any pending signals just became unblocked. */
+- pending = ss->pending & ~ss->blocked;
++ pending = _hurd_sigstate_pending (ss) & ~ss->blocked;
+
+ /* Tell the signal thread to message us when a signal arrives. */
+ ss->suspended = wait;
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+
+ if (pending)
+ /* Tell the signal thread to check for pending signals. */
+@@ -66,10 +66,11 @@ __sigsuspend (set)
+ MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+ __mach_port_destroy (__mach_task_self (), wait);
+
+- __spin_lock (&ss->lock);
+- ss->blocked = oldmask; /* Restore the old mask. */
+- pending = ss->pending & ~ss->blocked; /* Again check for pending signals. */
+- __spin_unlock (&ss->lock);
++ /* Restore the old mask and check for pending signals again. */
++ _hurd_sigstate_lock (ss);
++ ss->blocked = oldmask;
++ pending = _hurd_sigstate_pending(ss) & ~ss->blocked;
++ _hurd_sigstate_unlock (ss);
+
+ if (pending)
+ /* Tell the signal thread to check for pending signals. */
+diff --git a/sysdeps/mach/hurd/sigwait.c b/sysdeps/mach/hurd/sigwait.c
+index 9794076..af50f74 100644
+--- a/sysdeps/mach/hurd/sigwait.c
++++ b/sysdeps/mach/hurd/sigwait.c
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 1996,97,2001,02 Free Software Foundation, Inc.
++/* Copyright (C) 1996,97,2001,2002,2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -28,7 +28,7 @@ int
+ __sigwait (const sigset_t *set, int *sig)
+ {
+ struct hurd_sigstate *ss;
+- sigset_t mask, ready;
++ sigset_t mask, ready, blocked;
+ int signo = 0;
+ struct hurd_signal_preemptor preemptor;
+ jmp_buf buf;
+@@ -50,8 +50,8 @@ __sigwait (const sigset_t *set, int *sig)
+ /* Make sure this is all kosher */
+ assert (__sigismember (&mask, signo));
+
+- /* Make sure this signal is unblocked */
+- __sigdelset (&ss->blocked, signo);
++ /* Restore the blocking mask. */
++ ss->blocked = blocked;
+
+ return pe->handler;
+ }
+@@ -72,10 +72,11 @@ __sigwait (const sigset_t *set, int *sig)
+ __sigemptyset (&mask);
+
+ ss = _hurd_self_sigstate ();
+- __spin_lock (&ss->lock);
++ _hurd_sigstate_lock (ss);
+
+ /* See if one of these signals is currently pending. */
+- __sigandset (&ready, &ss->pending, &mask);
++ sigset_t pending = _hurd_sigstate_pending (ss);
++ __sigandset (&ready, &pending, &mask);
+ if (! __sigisemptyset (&ready))
+ {
+ for (signo = 1; signo < NSIG; signo++)
+@@ -103,7 +104,11 @@ __sigwait (const sigset_t *set, int *sig)
+ preemptor.next = ss->preemptors;
+ ss->preemptors = &preemptor;
+
+- __spin_unlock (&ss->lock);
++ /* Unblock the expected signals */
++ blocked = ss->blocked;
++ ss->blocked &= ~mask;
++
++ _hurd_sigstate_unlock (ss);
+
+ /* Wait. */
+ __mach_msg (&msg, MACH_RCV_MSG, 0, sizeof (msg), wait,
+@@ -114,7 +119,7 @@ __sigwait (const sigset_t *set, int *sig)
+ {
+ assert (signo);
+
+- __spin_lock (&ss->lock);
++ _hurd_sigstate_lock (ss);
+
+ /* Delete our preemptor. */
+ assert (ss->preemptors == &preemptor);
+@@ -123,7 +128,7 @@ __sigwait (const sigset_t *set, int *sig)
+
+
+ all_done:
+- spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+
+ __mach_port_destroy (__mach_task_self (), wait);
+ *sig = signo;
+diff --git a/sysdeps/mach/hurd/spawni.c b/sysdeps/mach/hurd/spawni.c
+index 244ca2d..373da8d 100644
+--- a/sysdeps/mach/hurd/spawni.c
++++ b/sysdeps/mach/hurd/spawni.c
+@@ -1,5 +1,5 @@
+ /* spawn a new process running an executable. Hurd version.
+- Copyright (C) 2001,02,04 Free Software Foundation, Inc.
++ Copyright (C) 2001,2002,2004,2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -239,26 +239,29 @@ __spawni (pid_t *pid, const char *file,
+ assert (! __spin_lock_locked (&ss->critical_section_lock));
+ __spin_lock (&ss->critical_section_lock);
+
+- __spin_lock (&ss->lock);
++ _hurd_sigstate_lock (ss);
+ ints[INIT_SIGMASK] = ss->blocked;
+- ints[INIT_SIGPENDING] = ss->pending;
++ ints[INIT_SIGPENDING] = _hurd_sigstate_pending (ss); /* XXX really? */
+ ints[INIT_SIGIGN] = 0;
+ /* Unless we were asked to reset all handlers to SIG_DFL,
+ pass down the set of signals that were set to SIG_IGN. */
+- if ((flags & POSIX_SPAWN_SETSIGDEF) == 0)
+- for (i = 1; i < NSIG; ++i)
+- if (ss->actions[i].sa_handler == SIG_IGN)
+- ints[INIT_SIGIGN] |= __sigmask (i);
+-
+- /* We hold the sigstate lock until the exec has failed so that no signal
+- can arrive between when we pack the blocked and ignored signals, and
+- when the exec actually happens. A signal handler could change what
++ {
++ struct sigaction *actions = _hurd_sigstate_actions (ss);
++ if ((flags & POSIX_SPAWN_SETSIGDEF) == 0)
++ for (i = 1; i < NSIG; ++i)
++ if (actions[i].sa_handler == SIG_IGN)
++ ints[INIT_SIGIGN] |= __sigmask (i);
++ }
++
++ /* We hold the critical section lock until the exec has failed so that no
++ signal can arrive between when we pack the blocked and ignored signals,
++ and when the exec actually happens. A signal handler could change what
+ signals are blocked and ignored. Either the change will be reflected
+ in the exec, or the signal will never be delivered. Setting the
+ critical section flag avoids anything we call trying to acquire the
+ sigstate lock. */
+
+- __spin_unlock (&ss->lock);
++ _hurd_sigstate_unlock (ss);
+
+ /* Set signal mask. */
+ if ((flags & POSIX_SPAWN_SETSIGMASK) != 0)
diff --git a/debian/patches/series b/debian/patches/series
index 4252087..6103a3b 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -141,8 +141,11 @@ hurd-i386/submitted-add-needed.diff
hurd-i386/local-ED.diff
hurd-i386/unsubmitted-pthread_posix-option.diff
hurd-i386/local-madvise_warn.diff
-hurd-i386/submitted-PTRACE_CONTINUE.diff
hurd-i386/submitted-ldsodefs.h.diff
+hurd-i386/submitted-hurdsig-fixes.diff
+hurd-i386/submitted-hurdsig-global-dispositions.diff
+hurd-i386/submitted-hurdsig-SA_SIGINFO.diff
+hurd-i386/submitted-hurdsig-fixes-2.diff
ia64/local-dlfptr.diff
ia64/submitted-sysconf.diff
Reply to: