diff options
Diffstat (limited to 'hurd')
-rw-r--r-- | hurd/ctty-input.c | 16 | ||||
-rw-r--r-- | hurd/ctty-output.c | 16 | ||||
-rw-r--r-- | hurd/hurd/signal.h | 38 | ||||
-rw-r--r-- | hurd/hurdexec.c | 9 | ||||
-rw-r--r-- | hurd/hurdmsg.c | 24 | ||||
-rw-r--r-- | hurd/hurdsig.c | 272 |
6 files changed, 269 insertions, 106 deletions
diff --git a/hurd/ctty-input.c b/hurd/ctty-input.c index 4c22987455..f7e9e08b7a 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 387befba6f..1adedf37a1 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/hurd/signal.h b/hurd/hurd/signal.h index d4079efe00..db60e6f0a1 100644 --- a/hurd/hurd/signal.h +++ b/hurd/hurd/signal.h @@ -69,7 +69,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>. @@ -125,6 +131,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 @@ -148,12 +174,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; @@ -201,10 +221,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 0ced7f32b4..77bf833742 100644 --- a/hurd/hurdexec.c +++ b/hurd/hurdexec.c @@ -107,12 +107,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 @@ -123,7 +124,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 b4b7161977..ec0b01df90 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 4872651894..72c582f00b 100644 --- a/hurd/hurdsig.c +++ b/hurd/hurdsig.c @@ -42,9 +42,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; @@ -53,6 +50,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; @@ -81,7 +81,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); @@ -94,16 +94,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); @@ -112,14 +115,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. */ @@ -214,6 +311,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); @@ -353,7 +452,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; } @@ -476,9 +575,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)) @@ -531,8 +632,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); @@ -545,9 +650,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; @@ -563,13 +665,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. */ @@ -627,12 +759,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. */ @@ -726,7 +858,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 (); @@ -762,6 +894,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; @@ -806,6 +939,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) { @@ -940,23 +1075,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); @@ -974,7 +1111,7 @@ post_signal (struct hurd_sigstate *ss, } } - return 1; + return ss; } /* Return the set of pending signals in SS which should be delivered. */ @@ -989,7 +1126,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 @@ -1001,12 +1138,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)) @@ -1014,7 +1154,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; } @@ -1032,14 +1172,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); @@ -1072,11 +1212,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. */ @@ -1088,8 +1229,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; @@ -1215,9 +1357,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. */ @@ -1245,7 +1388,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. */ @@ -1256,8 +1399,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) @@ -1280,27 +1423,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) |