[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 6/8] Hurd signals: make sigsuspend POSIX-conformant.
From: |
Jeremie Koenig |
Subject: |
[PATCH 6/8] Hurd signals: make sigsuspend POSIX-conformant. |
Date: |
Wed, 25 May 2011 17:59:32 +0200 |
* hurd/hurdsig.c (wake_sigsuspend): New function.
(post_signal): wake up sigsuspend calls in the "handle" case.
(post_signals): no longer wake up sigsuspend calls indiscriminately.
---
hurd/hurdsig.c | 46 ++++++++++++++++++++++++++++------------------
1 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index 234da1e..b6fbb14 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -416,60 +416,84 @@ abort_all_rpcs (int signo, struct
machine_thread_all_state *state, int live)
if (state_changed)
/* Aborting the RPC needed to change this thread's state,
and it might ever run again. So write back its state. */
__thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
(natural_t *) &state->basic,
MACHINE_THREAD_STATE_COUNT);
}
}
/* Wait for replies from all the successfully interrupted RPCs. */
while (nthreads-- > 0)
if (reply_ports[nthreads] != MACH_PORT_NULL)
{
error_t err;
mach_msg_header_t head;
err = __mach_msg (&head, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, sizeof head,
reply_ports[nthreads],
_hurd_interrupted_rpc_timeout, MACH_PORT_NULL);
switch (err)
{
case MACH_RCV_TIMED_OUT:
case MACH_RCV_TOO_LARGE:
break;
default:
assert_perror (err);
}
}
}
+/* 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;
/* XXX temporary to deal with spelling fix */
weak_alias (_hurdsig_preemptors, _hurdsig_preempters)
/* Mask of stop signals. */
#define STOPSIGS (sigmask (SIGTTIN) | sigmask (SIGTTOU) | \
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
post_signal (struct hurd_sigstate *ss,
int signo, struct hurd_signal_detail *detail,
int untraced, void (*reply) (void))
{
struct machine_thread_all_state thread_state;
enum { stop, ignore, core, term, handle } act;
int ss_suspended;
/* Mark the signal as pending. */
void mark_pending (void)
{
__sigaddset (&ss->pending, signo);
/* Save the details to be given to the handler when SIGNO is
unblocked. */
ss->pending_data[signo] = *detail;
}
@@ -906,130 +930,116 @@ post_signal (struct hurd_sigstate *ss,
{
/* After the handler runs we will restore to the state in
SS->context, not the state of the thread now. So restore
that context's reply port and intr port. */
scp->sc_reply_port = ss->context->sc_reply_port;
scp->sc_intr_port = ss->context->sc_intr_port;
ss->context = NULL;
}
}
/* 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);
/* Also block SIGNO unless we're asked not to. */
if (! (ss->actions[signo].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
&& 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,
(natural_t *) &thread_state.basic,
MACHINE_THREAD_STATE_COUNT);
assert_perror (err);
err = __thread_resume (ss->thread);
assert_perror (err);
thread_state.set = 0; /* Everything we know is now wrong. */
break;
}
}
return 1;
}
/* 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 ss->pending & ~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;
for (signo = 1; signo < NSIG; ++signo)
if (__sigismember (&pending, signo))
{
__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;
}
- /* 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);
- }
+ /* 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)
--
1.7.1
- [PATCH 0/8] Hurd signal code improvements, Jeremie Koenig, 2011/05/25
- [PATCH 7/8] Hurd signals: fix uninitialized value., Jeremie Koenig, 2011/05/25
- [PATCH 1/8] _hurd_internal_post_signal: Split into more functions, Jeremie Koenig, 2011/05/25
- [PATCH 5/8] Hurd signals: reindent, Jeremie Koenig, 2011/05/25
- [PATCH 4/8] Hurd signal cleanup: refactor check_pending_signals, Jeremie Koenig, 2011/05/25
- [PATCH 6/8] Hurd signals: make sigsuspend POSIX-conformant.,
Jeremie Koenig <=
- [PATCH 2/8] _hurd_internal_post_signal: Scope variables more restrictively, Jeremie Koenig, 2011/05/25
- [PATCH 3/8] _hurd_internal_post_signal: Split out inner functions, Jeremie Koenig, 2011/05/25
- [PATCH 8/8] Hurd signals: implement global signal dispositions, Jeremie Koenig, 2011/05/25
- Re: [PATCH 0/8] Hurd signal code improvements, Jérémie Koenig, 2011/05/25