[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 1/8] _hurd_internal_post_signal: Split into more functions
From: |
Jeremie Koenig |
Subject: |
[PATCH 1/8] _hurd_internal_post_signal: Split into more functions |
Date: |
Wed, 25 May 2011 17:59:27 +0200 |
* hurd/hurdsig.c (_hurd_internal_post_signal): Use inner functions
instead of gotos for the overall flow control.
This patch should change nothing besides replacing gotos with function
calls and return statements.
Note that the "signo == 0" test at the beginning of post_signal, is now
done on every call. However, only the first call ever has a zero signo,
so this does not change the overall behavior.
---
hurd/hurdsig.c | 47 +++++++++++++++++++++++++++++++++++------------
1 files changed, 35 insertions(+), 12 deletions(-)
diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index 4cb5e3c..c139805 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -455,60 +455,66 @@ weak_alias (_hurdsig_preemptors, _hurdsig_preempters)
/* 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)
{
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);
}
+/* 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)
+{
+
/* 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;
}
/* Resume the process after a suspension. */
void resume (void)
{
/* Resume the process from being stopped. */
@@ -526,65 +532,63 @@ _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))
{
err = __thread_resume (threads[i]);
assert_perror (err);
}
err = __mach_port_deallocate (__mach_task_self (),
threads[i]);
assert_perror (err);
}
__vm_deallocate (__mach_task_self (),
(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;
}
if (signo == 0)
{
if (untraced)
/* This is PTRACE_CONTINUE. */
resume ();
/* This call is just to check for pending signals. */
__spin_lock (&ss->lock);
- goto check_pending_signals;
+ return 1;
}
- post_signal:
-
thread_state.set = 0; /* We know nothing. */
__spin_lock (&ss->lock);
/* Check for a preempted signal. Preempted signals can arrive during
critical sections. */
{
inline sighandler_t try_preemptor (struct hurd_signal_preemptor *pe)
{ /* PE cannot be null. */
do
{
if (HURD_PREEMPT_SIGNAL_P (pe, signo, detail->code))
{
if (pe->preemptor)
{
sighandler_t handler = (*pe->preemptor) (pe, ss,
&signo, detail);
if (handler != SIG_ERR)
return handler;
}
else
return pe->handler;
}
pe = pe->next;
} while (pe != 0);
return SIG_ERR;
}
handler = ss->preemptors ? try_preemptor (ss->preemptors) : SIG_ERR;
@@ -593,61 +597,61 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
{
__mutex_lock (&_hurd_siglock);
handler = try_preemptor (_hurdsig_preemptors);
__mutex_unlock (&_hurd_siglock);
}
}
ss_suspended = 0;
if (handler == SIG_IGN)
/* Ignore the signal altogether. */
act = ignore;
else if (handler != SIG_ERR)
/* Run the preemption-provided handler. */
act = handle;
else
{
/* No preemption. Do normal handling. */
if (!untraced && __sigismember (&_hurdsig_traced, signo))
{
/* We are being traced. Stop to tell the debugger of the signal. */
if (_hurd_stopped)
/* Already stopped. Mark the signal as pending;
when resumed, we will notice it and stop again. */
mark_pending ();
else
suspend ();
__spin_unlock (&ss->lock);
reply ();
- return;
+ return 0;
}
handler = ss->actions[signo].sa_handler;
if (handler == SIG_DFL)
/* Figure out the default action for this signal. */
switch (signo)
{
case 0:
/* A sig_post msg with SIGNO==0 is sent to
tell us to check for pending signals. */
act = ignore;
break;
case SIGTTIN:
case SIGTTOU:
case SIGSTOP:
case SIGTSTP:
act = stop;
break;
case SIGCONT:
case SIGIO:
case SIGURG:
case SIGCHLD:
case SIGWINCH:
act = ignore;
break;
case SIGQUIT:
@@ -935,146 +939,165 @@ _hurd_internal_post_signal (struct hurd_sigstate *ss,
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;
/* 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;
}
}
- /* The signal has either been ignored or is now being handled. We can
- consider it delivered and reply to the killer. */
- reply ();
+ return 1;
+}
- /* We get here unless the signal was fatal. We still hold SS->lock.
- Check for pending signals, and loop to post them. */
- {
+/* 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)
+{
/* 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;
}
- check_pending_signals:
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];
__spin_unlock (&ss->lock);
- goto post_signal;
+
+ return post_signal ();
}
}
/* 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);
}
+
+ return 0;
}
+
+ if (! post_signal ())
+ 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 ());
+
/* 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:
case SIGTTIN:
--
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 <=
- [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, 2011/05/25
- [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