>From 8430ac692ffb3d03f5bd225cacdb087a42844c30 Mon Sep 17 00:00:00 2001 From: Jeremie Koenig Date: Sat, 11 Sep 2010 12:52:15 +0000 Subject: [PATCH 5/8] Hurd signals: make sigsuspend POSIX-conformant. * 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 6923c87..16c01d0 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.2.3