summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2019-02-21 22:01:52 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2019-02-21 22:01:52 +0100
commit4249f9406ce2e7edde69e5452e7580fb674dcd5a (patch)
tree9ad68bf325866fb9642b06b96eca1c6fa37f7bcc
parent0c1d4f975c38f3385e12038d72aee2f028999e5e (diff)
parent09ac56ee3bd5e4b9684e09c0653062a71125345d (diff)
Merge commit 'refs/top-bases/t/libpthread_sigs' into t/libpthread_sigs
-rw-r--r--hurd/ctty-input.c16
-rw-r--r--hurd/ctty-output.c16
-rw-r--r--hurd/exc2signal.c33
-rw-r--r--hurd/hurd/signal.h43
-rw-r--r--hurd/hurd/sigpreempt.h4
-rw-r--r--hurd/hurdexec.c9
-rw-r--r--hurd/hurdfault.c2
-rw-r--r--hurd/hurdinit.c2
-rw-r--r--hurd/hurdmsg.c24
-rw-r--r--hurd/hurdsig.c511
-rw-r--r--sysdeps/mach/hurd/bits/sigaction.h86
-rw-r--r--sysdeps/mach/hurd/fork.c24
-rw-r--r--sysdeps/mach/hurd/i386/bits/sigcontext.h4
-rw-r--r--sysdeps/mach/hurd/i386/exc2signal.c122
-rw-r--r--sysdeps/mach/hurd/i386/sigreturn.c10
-rw-r--r--sysdeps/mach/hurd/i386/trampoline.c128
-rw-r--r--sysdeps/mach/hurd/kill.c2
-rw-r--r--sysdeps/mach/hurd/setitimer.c2
-rw-r--r--sysdeps/mach/hurd/sigaction.c16
-rw-r--r--sysdeps/mach/hurd/sigpending.c6
-rw-r--r--sysdeps/mach/hurd/sigprocmask.c8
-rw-r--r--sysdeps/mach/hurd/sigsuspend.c15
-rw-r--r--sysdeps/mach/hurd/sigwait.c21
-rw-r--r--sysdeps/mach/hurd/spawni.c25
24 files changed, 808 insertions, 321 deletions
diff --git a/hurd/ctty-input.c b/hurd/ctty-input.c
index ec4092b855..de4cb950e8 100644
--- a/hurd/ctty-input.c
+++ b/hurd/ctty-input.c
@@ -43,12 +43,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)
{
@@ -65,10 +68,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 12fdf78159..dc9bba8af1 100644
--- a/hurd/ctty-output.c
+++ b/hurd/ctty-output.c
@@ -34,16 +34,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);
@@ -70,10 +73,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/exc2signal.c b/hurd/exc2signal.c
index 10aa1ca4cf..0ecc5eb178 100644
--- a/hurd/exc2signal.c
+++ b/hurd/exc2signal.c
@@ -25,8 +25,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;
@@ -38,11 +38,18 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
break;
case EXC_BAD_ACCESS:
- if (detail->exc_code == KERN_PROTECTION_FAILURE)
- *signo = SIGSEGV;
- else
- *signo = SIGBUS;
- detail->code = detail->exc_subcode;
+ switch (detail->exc_code)
+ {
+ case KERN_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;
@@ -68,4 +75,16 @@ _hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
break;
}
}
+
+void
+_hurd_exception2signal (struct hurd_signal_detail *detail, int *signo)
+{
+ exception2signal (detail, signo, 1);
+}
libc_hidden_def (_hurd_exception2signal)
+
+void
+_hurd_exception2signal_legacy (struct hurd_signal_detail *detail, int *signo)
+{
+ exception2signal (detail, signo, 0);
+}
diff --git a/hurd/hurd/signal.h b/hurd/hurd/signal.h
index f84c4ef485..f5b6432c95 100644
--- a/hurd/hurd/signal.h
+++ b/hurd/hurd/signal.h
@@ -73,7 +73,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];
+
stack_t sigaltstack;
/* Chain of thread-local signal preemptors; see <hurd/sigpreempt.h>.
@@ -129,6 +135,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
@@ -154,12 +180,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;
@@ -222,10 +242,10 @@ _hurd_critical_section_unlock (void *our_lock)
/* It was us who acquired the critical section lock. Unlock it. */
struct hurd_sigstate *ss = (struct hurd_sigstate *) 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.
@@ -265,6 +285,11 @@ extern int _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/hurd/sigpreempt.h b/hurd/hurd/sigpreempt.h
index a1df82e2c6..51b422c512 100644
--- a/hurd/hurd/sigpreempt.h
+++ b/hurd/hurd/sigpreempt.h
@@ -50,9 +50,9 @@ struct hurd_signal_preemptor
struct hurd_signal_preemptor *next; /* List structure. */
};
-#define HURD_PREEMPT_SIGNAL_P(preemptor, signo, sigcode) \
+#define HURD_PREEMPT_SIGNAL_P(preemptor, signo, address) \
(((preemptor)->signals & sigmask (signo)) && \
- (sigcode) >= (preemptor)->first && (sigcode) <= (preemptor)->last)
+ (address) >= (preemptor)->first && (address) <= (preemptor)->last)
/* Signal preemptors applying to all threads; locked by _hurd_siglock. */
diff --git a/hurd/hurdexec.c b/hurd/hurdexec.c
index 732c9ec34b..12ba819259 100644
--- a/hurd/hurdexec.c
+++ b/hurd/hurdexec.c
@@ -126,12 +126,13 @@ _hurd_exec_paths (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
@@ -142,7 +143,7 @@ _hurd_exec_paths (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/hurdfault.c b/hurd/hurdfault.c
index 39a4522811..e9a9a4f9cc 100644
--- a/hurd/hurdfault.c
+++ b/hurd/hurdfault.c
@@ -70,7 +70,7 @@ _hurdsig_fault_catch_exception_raise (mach_port_t port,
codes into a signal number and subcode. */
_hurd_exception2signal (&d, &signo);
- return HURD_PREEMPT_SIGNAL_P (&_hurdsig_fault_preemptor, signo, d.code)
+ return HURD_PREEMPT_SIGNAL_P (&_hurdsig_fault_preemptor, signo, d.exc_subcode)
? 0 : EGREGIOUS;
}
diff --git a/hurd/hurdinit.c b/hurd/hurdinit.c
index 6af1ddf610..9d654f0d1e 100644
--- a/hurd/hurdinit.c
+++ b/hurd/hurdinit.c
@@ -175,7 +175,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/hurd/hurdmsg.c b/hurd/hurdmsg.c
index 63e5e81b87..0a73b54574 100644
--- a/hurd/hurdmsg.c
+++ b/hurd/hurdmsg.c
@@ -121,17 +121,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);
@@ -139,7 +131,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);
@@ -207,17 +199,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);
@@ -225,7 +209,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 aa82f63413..3ea61ccf0f 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -46,9 +46,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;
@@ -56,6 +53,9 @@ unsigned long int __hurd_sigthread_stack_end;
/* 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;
@@ -84,7 +84,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);
@@ -97,16 +97,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);
@@ -115,15 +118,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;
}
libc_hidden_def (_hurd_thread_sigstate)
+
+/* 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. */
@@ -218,6 +314,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);
@@ -364,7 +462,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;
}
@@ -452,6 +550,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;
@@ -462,35 +584,20 @@ 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 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))
{
- 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)
{
@@ -535,8 +642,12 @@ _hurd_internal_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);
@@ -549,27 +660,58 @@ _hurd_internal_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;
+ 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;
+ _hurd_sigstate_lock (ss);
+ return ss;
}
- post_signal:
-
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. */
@@ -578,7 +720,7 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
{ /* PE cannot be null. */
do
{
- if (HURD_PREEMPT_SIGNAL_P (pe, signo, detail->code))
+ if (HURD_PREEMPT_SIGNAL_P (pe, signo, detail->exc_subcode))
{
if (pe->preemptor)
{
@@ -627,12 +769,12 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
mark_pending ();
else
suspend ();
- __spin_unlock (&ss->lock);
+ _hurd_sigstate_unlock (ss);
reply ();
- return;
+ 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. */
@@ -726,7 +868,7 @@ _hurd_internal_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 ();
@@ -762,6 +904,7 @@ _hurd_internal_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;
@@ -806,6 +949,8 @@ _hurd_internal_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)
{
@@ -873,7 +1018,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)
@@ -942,23 +1087,28 @@ _hurd_internal_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);
/* Start the thread running the handler (or possibly waiting for an
RPC reply before running the handler). */
@@ -973,95 +1123,134 @@ _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 ss;
+}
- /* 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)
+/* 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;
+
+ return _hurd_sigstate_pending (ss) & ~ss->blocked;
+}
+
+/* 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;
+
+ /* 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))
{
- if (_hurd_stopped || __spin_lock_locked (&ss->critical_section_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))
return 0;
- return pending = ss->pending & ~ss->blocked;
}
- check_pending_signals:
- untraced = 0;
+ /* No more signals pending; SS->lock is still locked. */
+ _hurd_sigstate_unlock (ss);
- 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;
- }
- }
+ return 1;
+}
- /* 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
- {
- /* 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);
- }
- __spin_unlock (&ss->lock);
- }
- }
+/* 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 = 0;
+
+ for (;;)
+ {
+ __mutex_lock (&_hurd_siglock);
+ for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
+ {
+ _hurd_sigstate_lock (ss);
+
+ pending = pending_signals (ss);
+ if (pending)
+ /* post_pending() below will unlock SS. */
+ break;
+
+ _hurd_sigstate_unlock (ss);
+ }
+ __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);
+ }
+
+ ss = post_signal (ss, signo, detail, untraced, reply);
+ if (! ss)
+ return;
- /* All pending signals delivered to all threads.
- Now we can send the reply message even for signal 0. */
- reply ();
+ /* The signal was neither fatal nor traced. We still hold SS->lock. */
+ 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. */
+ reply ();
+
+ /* Post any pending signals for this thread. */
+ if (! post_pending (ss, pending_signals (ss), reply))
+ return;
+ }
+ else
+ {
+ /* 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;
+
+ /* 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.
@@ -1180,9 +1369,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. */
@@ -1210,7 +1400,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. */
@@ -1221,8 +1411,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)
@@ -1245,27 +1435,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. */
#pragma weak __cthread_fork
diff --git a/sysdeps/mach/hurd/bits/sigaction.h b/sysdeps/mach/hurd/bits/sigaction.h
new file mode 100644
index 0000000000..444947c62b
--- /dev/null
+++ b/sysdeps/mach/hurd/bits/sigaction.h
@@ -0,0 +1,86 @@
+/* Copyright (C) 1991-2015 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 _BITS_SIGACTION_H
+#define _BITS_SIGACTION_H 1
+
+#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. */
+#if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED
+ 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_XOPEN_EXTENDED || defined __USE_MISC
+# define SA_ONSTACK 0x0001 /* Take signal on signal stack. */
+#endif
+#if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K8
+# 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. */
+#endif
+#define SA_NOCLDSTOP 0x0008 /* Don't send SIGCHLD when children stop. */
+#define SA_SIGINFO 0x0040 /* Signal handler with SA_SIGINFO args */
+
+#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. */
+
+#endif
diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
index 2d1e64c8d1..3d8e45df13 100644
--- a/sysdeps/mach/hurd/fork.c
+++ b/sysdeps/mach/hurd/fork.c
@@ -444,6 +444,7 @@ __fork (void)
(err = __mach_port_insert_right (newtask, ss->thread,
thread, MACH_MSG_TYPE_COPY_SEND)))
LOSE;
+ /* XXX consumed? (_hurd_sigthread is no more) */
if (thread_refs > 1 &&
(err = __mach_port_mod_refs (newtask, ss->thread,
MACH_PORT_RIGHT_SEND,
@@ -608,10 +609,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
@@ -631,6 +628,25 @@ __fork (void)
ss->next = NULL;
_hurd_sigstates = ss;
__mutex_unlock (&_hurd_siglock);
+ /* Earlier on, the global sigstate may have been tainted and now needs to
+ be reinitialized. Nobody is interested in its present state anymore:
+ we're not, the signal thread will be restarted, and there are no other
+ threads.
+
+ We can't simply allocate a fresh global sigstate here, as
+ _hurd_thread_sigstate will call malloc and that will deadlock trying
+ to determine the current thread's sigstate. */
+#if 0
+ _hurd_thread_sigstate_init (_hurd_global_sigstate, MACH_PORT_NULL);
+#else
+ /* Only reinitialize the lock -- otherwise we might have to do additional
+ setup as done in hurdsig.c:_hurdsig_init. */
+ __spin_lock_init (&_hurd_global_sigstate->lock);
+#endif
+
+ /* 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
diff --git a/sysdeps/mach/hurd/i386/bits/sigcontext.h b/sysdeps/mach/hurd/i386/bits/sigcontext.h
index f493bc9750..b6bf76a25e 100644
--- a/sysdeps/mach/hurd/i386/bits/sigcontext.h
+++ b/sysdeps/mach/hurd/i386/bits/sigcontext.h
@@ -97,6 +97,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 57bc05df99..1b94e79e04 100644
--- a/sysdeps/mach/hurd/i386/exc2signal.c
+++ b/sysdeps/mach/hurd/i386/exc2signal.c
@@ -23,8 +23,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;
@@ -36,44 +36,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 = posix ? BUS_ADRERR : detail->exc_subcode;
+ 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;
@@ -82,51 +100,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;
@@ -143,7 +153,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
{
@@ -154,13 +164,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);
+}
libc_hidden_def (_hurd_exception2signal)
+
+void
+_hurd_exception2signal_legacy (struct hurd_signal_detail *detail, int *signo)
+{
+ exception2signal (detail, signo, 0);
+}
diff --git a/sysdeps/mach/hurd/i386/sigreturn.c b/sysdeps/mach/hurd/i386/sigreturn.c
index 07633e17c8..4462b5e792 100644
--- a/sysdeps/mach/hurd/i386/sigreturn.c
+++ b/sysdeps/mach/hurd/i386/sigreturn.c
@@ -38,7 +38,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
@@ -50,19 +50,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;
}
@@ -73,7 +73,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 0e795f9389..7eca1db020 100644
--- a/sysdeps/mach/hurd/i386/trampoline.c
+++ b/sysdeps/mach/hurd/i386/trampoline.c
@@ -19,13 +19,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,
@@ -37,20 +90,44 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
void firewall (void);
extern const void _hurd_intr_rpc_msg_cx_sp;
extern const void _hurd_intr_rpc_msg_sp_restored;
+ const 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;
+ /* sigaction for preemptors */
+ static const struct sigaction legacy_sigaction = {
+ .sa_flags = SA_RESTART
+ };
+
if (ss->context)
{
/* We have a previous sigcontext that sigreturn was about
@@ -74,7 +151,15 @@ _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) &&
+ action = & _hurd_sigstate_actions (ss) [signo];
+ if ( (action->sa_flags & SA_SIGINFO)
+ && handler != (__sighandler_t) action->sa_sigaction
+ || !(action->sa_flags & SA_SIGINFO)
+ && handler != action->sa_handler)
+ /* A signal preemptor took over, use legacy semantic. */
+ action = &legacy_sigaction;
+
+ if ((action->sa_flags & SA_ONSTACK) &&
!(ss->sigaltstack.ss_flags & (SS_DISABLE|SS_ONSTACK)))
{
sigsp = ss->sigaltstack.ss_sp + ss->sigaltstack.ss_size;
@@ -134,15 +219,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
@@ -156,6 +235,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 7e64e7c9d7..f9c9a57030 100644
--- a/sysdeps/mach/hurd/kill.c
+++ b/sysdeps/mach/hurd/kill.c
@@ -64,7 +64,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 f5dfb7da84..b924b33c5f 100644
--- a/sysdeps/mach/hurd/setitimer.c
+++ b/sysdeps/mach/hurd/setitimer.c
@@ -103,7 +103,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/sysdeps/mach/hurd/sigaction.c b/sysdeps/mach/hurd/sigaction.c
index 5f010064c9..abf9931d6e 100644
--- a/sysdeps/mach/hurd/sigaction.c
+++ b/sysdeps/mach/hurd/sigaction.c
@@ -46,15 +46,15 @@ __sigaction (int sig, const struct sigaction *act, struct sigaction *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
@@ -62,8 +62,8 @@ __sigaction (int sig, const struct sigaction *act, struct sigaction *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.
@@ -72,11 +72,11 @@ __sigaction (int sig, const struct sigaction *act, struct sigaction *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 ea41ddc427..63b76bbf99 100644
--- a/sysdeps/mach/hurd/sigpending.c
+++ b/sysdeps/mach/hurd/sigpending.c
@@ -36,9 +36,9 @@ sigpending (sigset_t *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 e2587afcbc..5ef1bbde59 100644
--- a/sysdeps/mach/hurd/sigprocmask.c
+++ b/sysdeps/mach/hurd/sigprocmask.c
@@ -36,7 +36,7 @@ __sigprocmask (int how, const sigset_t *set, sigset_t *oset)
ss = _hurd_self_sigstate ();
- __spin_lock (&ss->lock);
+ _hurd_sigstate_lock (ss);
old = ss->blocked;
@@ -57,7 +57,7 @@ __sigprocmask (int how, const sigset_t *set, sigset_t *oset)
break;
default:
- __spin_unlock (&ss->lock);
+ _hurd_sigstate_unlock (ss);
errno = EINVAL;
return -1;
}
@@ -65,9 +65,9 @@ __sigprocmask (int how, const sigset_t *set, sigset_t *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 7da3897722..ca52ec5770 100644
--- a/sysdeps/mach/hurd/sigsuspend.c
+++ b/sysdeps/mach/hurd/sigsuspend.c
@@ -40,7 +40,7 @@ __sigsuspend (const sigset_t *set)
ss = _hurd_self_sigstate ();
- __spin_lock (&ss->lock);
+ _hurd_sigstate_lock (ss);
oldmask = ss->blocked;
if (set != NULL)
@@ -48,11 +48,11 @@ __sigsuspend (const sigset_t *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. */
@@ -63,10 +63,11 @@ __sigsuspend (const sigset_t *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 ce17cce895..f8e7043178 100644
--- a/sysdeps/mach/hurd/sigwait.c
+++ b/sysdeps/mach/hurd/sigwait.c
@@ -27,7 +27,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;
@@ -49,8 +49,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;
}
@@ -71,10 +71,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++)
@@ -102,7 +103,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,
@@ -113,7 +118,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);
@@ -122,7 +127,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 9351c13e56..681d86d726 100644
--- a/sysdeps/mach/hurd/spawni.c
+++ b/sysdeps/mach/hurd/spawni.c
@@ -242,26 +242,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)