This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH 3/8] _hurd_internal_post_signal: Split out inner functions
- From: Jeremie Koenig <jk at jk dot fr dot eu dot org>
- To: bug-hurd at gnu dot org
- Cc: Jeremie Koenig <jk at jk dot fr dot eu dot org>,libc-alpha at sourceware dot org
- Date: Wed, 25 May 2011 17:59:29 +0200
- Subject: [PATCH 3/8] _hurd_internal_post_signal: Split out inner functions
- References: <1306339174-30785-1-git-send-email-jk@jk.fr.eu.org>
By having post_signal and check_pending_signal as top-level functions,
the way they communicate with the outside is made more transparent.
* hurd/hurdsig.c (_hurd_internal_post_signal): Make post_signal and
check_pending_signal top-level static helper functions.
(check_pending_signal): Fix the general poll request test being rendered
moot by earlier modifications of signo.
---
hurd/hurdsig.c | 81 +++++++++++++++++++++++++++++--------------------------
1 files changed, 43 insertions(+), 38 deletions(-)
diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index 0ea78e1..ccfea1c 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -426,86 +426,67 @@ abort_all_rpcs (int signo, struct machine_thread_all_state *state, int live)
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);
}
}
}
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))
-/* 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);
- }
-
/* 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. */
-int post_signal (void)
+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;
}
/* Suspend the process with SIGNO. */
void suspend (void)
{
/* Stop all other threads and mark ourselves stopped. */
__USEPORT (PROC,
({
/* Hold the siglock while stopping other threads to be
sure it is not held by another thread afterwards. */
__mutex_lock (&_hurd_siglock);
__proc_dostop (port, _hurd_msgport_thread);
__mutex_unlock (&_hurd_siglock);
abort_all_rpcs (signo, &thread_state, 1);
reply ();
__proc_mark_stop (port, signo, detail->code);
}));
_hurd_stopped = 1;
@@ -839,61 +820,61 @@ int post_signal (void)
_hurdsig_end_catch_fault ();
if (! machine_get_basic_state (ss->thread, &thread_state))
goto sigbomb;
loc = interrupted_reply_port_location (&thread_state, 1);
if (loc && *loc != MACH_PORT_NULL)
/* This is the reply port for the context which called
sigreturn. Since we are abandoning that context entirely
and restoring SS->context instead, destroy this port. */
__mach_port_destroy (__mach_task_self (), *loc);
/* The thread was in sigreturn, not in any interruptible RPC. */
wait_for_reply = 0;
assert (! __spin_lock_locked (&ss->critical_section_lock));
}
else
{
int crit = __spin_lock_locked (&ss->critical_section_lock);
wait_for_reply
= (_hurdsig_abort_rpcs (ss,
/* In a critical section, any RPC
should be cancelled instead of
restarted, regardless of
SA_RESTART, so the entire
"atomic" operation can be aborted
as a unit. */
crit ? 0 : signo, 1,
&thread_state, &state_changed,
- &reply)
+ reply)
!= MACH_PORT_NULL);
if (crit)
{
/* The thread is in a critical section. Mark the signal as
pending. When it finishes the critical section, it will
check for pending signals. */
mark_pending ();
if (state_changed)
/* Some cases of interrupting an RPC must change the
thread state to back out the call. Normally this
change is rolled into the warping to the handler and
sigreturn, but we are not running the handler now
because the thread is in a critical section. Instead,
mutate the thread right away for the RPC interruption
and resume it; the RPC will return early so the
critical section can end soon. */
__thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
(natural_t *) &thread_state.basic,
MACHINE_THREAD_STATE_COUNT);
/* */
ss->intr_port = MACH_PORT_NULL;
__thread_resume (ss->thread);
break;
}
}
/* Call the machine-dependent function to set the thread up
to run the signal handler, and preserve its old context. */
scp = _hurd_setup_sighandler (ss, handler, signo, detail,
@@ -941,163 +922,187 @@ int post_signal (void)
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;
/* 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;
}
-/* Try to find a non-blocked pending signal and deliver it. Called with
- SS locked. If a signal is delivered, return 1 and leave SS locked.
- If the signal is traced, or if none can be found, return 0 with
- SS unlocked. */
-int check_pending_signal (void)
+/* Try to find a non-blocked pending signal and deliver it, testing the
+ sigstate SS first. Called with SS locked. If a pending signal is delivered,
+ return the corresponding sigstate, locked. Otherwise, return NULL. */
+static struct hurd_sigstate *
+check_pending_signal (struct hurd_sigstate *ss, void (*reply) (void), int poll)
{
+ int signo;
+ struct hurd_signal_detail detail;
sigset_t pending;
/* Return nonzero if SS has any signals pending we should worry about.
We don't worry about any pending signals if we are stopped, nor if
SS is in a critical section. We are guaranteed to get a sig_post
message before any of them become deliverable: either the SIGCONT
signal, or a sig_post with SIGNO==0 as an explicit poll when the
thread finishes its critical section. */
inline int signals_pending (void)
{
if (_hurd_stopped || __spin_lock_locked (&ss->critical_section_lock))
return 0;
return pending = ss->pending & ~ss->blocked;
}
- untraced = 0;
-
if (signals_pending ())
{
for (signo = 1; signo < NSIG; ++signo)
if (__sigismember (&pending, signo))
{
deliver_pending:
__sigdelset (&ss->pending, signo);
- *detail = ss->pending_data[signo];
+ detail = ss->pending_data[signo];
__spin_unlock (&ss->lock);
- return post_signal ();
+ if (post_signal (ss, signo, &detail, 0, reply))
+ return ss;
+ else
+ return NULL;
}
}
/* 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)
+ if (poll)
{
__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);
}
- return 0;
- }
+ return NULL;
+}
+/* Deliver a signal. SS is not locked. */
+void
+_hurd_internal_post_signal (struct hurd_sigstate *ss,
+ int signo, struct hurd_signal_detail *detail,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type,
+ int untraced)
+{
+ /* Reply to this sig_post message. */
+ __typeof (__msg_sig_post_reply) *reply_rpc
+ = (untraced ? __msg_sig_post_untraced_reply : __msg_sig_post_reply);
+ void reply (void)
+ {
+ error_t err;
+ if (reply_port == MACH_PORT_NULL)
+ return;
+ err = (*reply_rpc) (reply_port, reply_port_type, 0);
+ reply_port = MACH_PORT_NULL;
+ if (err != MACH_SEND_INVALID_DEST) /* Ignore dead reply port. */
+ assert_perror (err);
+ }
- if (! post_signal ())
+ if (! post_signal (ss, signo, detail, untraced, reply))
return;
if (signo != 0)
{
/* The signal has either been ignored or is now being handled. We can
consider it delivered and reply to the killer. */
reply ();
}
/* We get here unless the signal was fatal. We still hold SS->lock.
Check for pending signals, and loop to post them. */
- while (check_pending_signal ());
+ while (ss = check_pending_signal (ss, reply, signo == 0));
/* 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.
Returns zero if so, otherwise the error code to return to the sender. */
static error_t
signal_allowed (int signo, mach_port_t refport)
{
if (signo < 0 || signo >= NSIG)
return EINVAL;
if (refport == __mach_task_self ())
/* Can send any signal. */
goto win;
/* Avoid needing to check for this below. */
if (refport == MACH_PORT_NULL)
return EPERM;
switch (signo)
{
case SIGINT:
case SIGQUIT:
case SIGTSTP:
case SIGHUP:
case SIGINFO:
--
1.7.1