Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/libpthread More signal rearranging:



details:   https://anonhg.NetBSD.org/src/rev/0e5de0f53e2e
branches:  trunk
changeset: 542269:0e5de0f53e2e
user:      nathanw <nathanw%NetBSD.org@localhost>
date:      Sat Jan 25 00:43:38 2003 +0000

description:
More signal rearranging:

 - Signal handlers now simply continue executing the current thread,
   rather than trying to put themselves back on the queue that they came
   from, which was rather fragile. As a result, all callers of
   pthread__block() must be prepared to handle spurious wakeups.

 - When a signal arrives for a thread that is blocked in the kernel,
   note this in another field in pthread_st and set a flag. Process the
   signal and set up the trampoline for the handler *after* the thread
   unblocks, so that both the trampoline and the returned state from
   the kernel are preserved.

 - Factor out some code into a pthread__deliver_signal() routine;
   the signal-taking code in pthread_sigmask() should be able to use this
   soon.

This is still gross, and there are still some terrible MP issues lurking here,
but progress crawls along.

diffstat:

 lib/libpthread/pthread_int.h |   14 ++-
 lib/libpthread/pthread_sa.c  |   23 ++++--
 lib/libpthread/pthread_sig.c |  137 +++++++++++++++++-------------------------
 3 files changed, 79 insertions(+), 95 deletions(-)

diffs (truncated from 327 to 300 lines):

diff -r 3047c6558547 -r 0e5de0f53e2e lib/libpthread/pthread_int.h
--- a/lib/libpthread/pthread_int.h      Sat Jan 25 00:37:01 2003 +0000
+++ b/lib/libpthread/pthread_int.h      Sat Jan 25 00:43:38 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread_int.h,v 1.3 2003/01/18 18:45:54 christos Exp $ */
+/*     $NetBSD: pthread_int.h,v 1.4 2003/01/25 00:43:38 nathanw Exp $  */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -71,6 +71,8 @@
 
 struct pthread_st {
        unsigned int    pt_magic;
+       /* Identifier, for debugging and for preventing recycling. */
+       int             pt_num;
 
        int     pt_type;        /* normal, upcall, or idle */
        int     pt_state;       /* running, blocked, etc. */
@@ -100,6 +102,7 @@
 
        sigset_t        pt_sigmask;     /* Signals we won't take. */
        sigset_t        pt_siglist;     /* Signals pending for us. */
+       sigset_t        pt_sigblocked;  /* Signals delivered while blocked. */
        pthread_spin_t  pt_siglock;     /* Lock on above */
 
        void *          pt_exitval;     /* Read by pthread_join() */
@@ -140,9 +143,6 @@
         */
        pthread_spin_t* pt_heldlock;
 
-       /* Identifier, for debugging. */
-       int             pt_num;
-
        /* Thread-specific data */
        void*           pt_specific[PTHREAD_KEYS_MAX];
 
@@ -180,7 +180,7 @@
 #define PT_FLAG_CS_DISABLED    0x0004  /* Cancellation disabled */
 #define PT_FLAG_CS_ASYNC       0x0008  /* Cancellation is async */
 #define PT_FLAG_CS_PENDING     0x0010
-#define PT_FLAG_SIGCATCH       0x0020  /* Interrupt sleep on a signal */
+#define PT_FLAG_SIGDEFERRED     0x0020 /* There are signals to take */
 
 #define PT_MAGIC       0x11110001
 #define PT_DEAD                0xDEAD0001
@@ -341,7 +341,9 @@
 
 void   pthread__signal_init(void);
 
-void   pthread__signal(pthread_t t, int sig, int code);
+void   pthread__signal(pthread_t self, pthread_t t, int sig, int code);
+void   pthread__deliver_signal(pthread_t self, pthread_t t, int sig, int code);
+void   pthread__signal_deferred(pthread_t self, pthread_t t);
 
 void   pthread__destroy_tsd(pthread_t self);
 
diff -r 3047c6558547 -r 0e5de0f53e2e lib/libpthread/pthread_sa.c
--- a/lib/libpthread/pthread_sa.c       Sat Jan 25 00:37:01 2003 +0000
+++ b/lib/libpthread/pthread_sa.c       Sat Jan 25 00:43:38 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread_sa.c,v 1.3 2003/01/18 18:45:56 christos Exp $  */
+/*     $NetBSD: pthread_sa.c,v 1.4 2003/01/25 00:43:38 nathanw Exp $   */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
 {
        pthread_t t, self, next, intqueue;
        int first = 1;
-       int deliversig = 0, runalarms = 0;
+       int runalarms = 0;
        siginfo_t *si;
 
        PTHREADD_ADD(PTHREADD_UPCALLS);
@@ -130,7 +130,6 @@
                break;
        case SA_UPCALL_SIGNAL:
                PTHREADD_ADD(PTHREADD_UP_SIGNAL);
-               deliversig = 1;
                break;
        case SA_UPCALL_SIGEV:
                PTHREADD_ADD(PTHREADD_UP_SIGEV);
@@ -189,15 +188,23 @@
         * This also means that a thread that was interrupted to take
         * a signal will be on a run queue, and not in upcall limbo.
         */
-       if (deliversig) {
+       if (type == SA_UPCALL_SIGNAL) {
                si = arg;
                if (ev)
-                       pthread__signal(pthread__sa_id(sas[1]), si->si_signo,
-                           si->si_code);
+                       pthread__signal(self, pthread__sa_id(sas[1]),
+                           si->si_signo, si->si_code);
                else
-                       pthread__signal(NULL, si->si_signo, si->si_code);
+                       pthread__signal(self, NULL, si->si_signo, si->si_code);
+       } else if (type == SA_UPCALL_UNBLOCKED) {
+               /*
+                * A signal may have been presented to this thread while
+                * it was in the kernel.
+                */
+               t = pthread__sa_id(sas[1]);
+               if (t->pt_flags & PT_FLAG_SIGDEFERRED)
+                       pthread__signal_deferred(self, t);
        }
-       
+
        /*
         * At this point everything on our list should be scheduled
         * (or was an upcall).
diff -r 3047c6558547 -r 0e5de0f53e2e lib/libpthread/pthread_sig.c
--- a/lib/libpthread/pthread_sig.c      Sat Jan 25 00:37:01 2003 +0000
+++ b/lib/libpthread/pthread_sig.c      Sat Jan 25 00:43:38 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread_sig.c,v 1.4 2003/01/24 17:43:45 jdolecek Exp $ */
+/*     $NetBSD: pthread_sig.c,v 1.5 2003/01/25 00:43:38 nathanw Exp $  */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -90,8 +90,8 @@
 
 
 static void 
-pthread__signal_tramp(int, int, struct sigaction *, ucontext_t *, sigset_t *,
-    int, struct pthread_queue_t *, pthread_spin_t *);
+pthread__signal_tramp(int, int, void (*)(int, int, struct sigcontext *),
+    ucontext_t *, sigset_t *);
 
 __strong_alias(__libc_thr_sigsetmask,pthread_sigmask)
 
@@ -167,7 +167,6 @@
        }
        pthread_sigmask(SIG_SETMASK, sigmask, &oldmask);
 
-       self->pt_flags |= PT_FLAG_SIGCATCH;
        self->pt_state = PT_STATE_BLOCKED_QUEUE;
        self->pt_sleepobj = &pt_sigsuspended_cond;
        self->pt_sleepq = &pt_sigsuspended;
@@ -178,7 +177,6 @@
        pthread__block(self, &pt_sigsuspended_lock);
 
        pthread__testcancel(self);
-       self->pt_flags &= ~PT_FLAG_SIGCATCH;
 
        pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
 
@@ -353,13 +351,10 @@
  * willing thread, if t is null.
  */
 void
-pthread__signal(pthread_t t, int sig, int code)
+pthread__signal(pthread_t self, pthread_t t, int sig, int code)
 {
-       pthread_t self, target, good, okay;
-       sigset_t oldmask, *maskp;
-       ucontext_t *uc;
+       pthread_t target, good, okay;
 
-       self = pthread__self();
        if (t) {
                target = t;
                pthread_spinlock(self, &target->pt_siglock);
@@ -455,14 +450,6 @@
         * target process is a bug.
         */
        assert(target->pt_state != PT_STATE_RUNNING);
-       /*
-        * Prevent anyone else from considering this thread for handling
-        * more instances of this signal.
-        */
-       oldmask = target->pt_sigmask;
-       __sigplusset(&target->pt_sigmask, &pt_sigacts[sig].sa_mask);
-       __sigaddset14(&target->pt_sigmask, sig);
-       pthread_spinunlock(self, &target->pt_siglock);
 
        /*
         * Holding the state lock blocks out cancellation and any other
@@ -483,14 +470,41 @@
        case PT_STATE_BLOCKED_SYS:
                /*
                 * The target is not on a queue at all, and won't run
-                * again for a while. Try to wake it from its torpor.
+                * again for a while. Try to wake it from its torpor, then
+                * mark the signal for later processing.
                 */
+               __sigaddset14(&target->pt_sigblocked, sig);
+               __sigaddset14(&target->pt_sigmask, sig);
+               target->pt_flags |= PT_FLAG_SIGDEFERRED;
+               pthread_spinunlock(self, &target->pt_siglock);
+               pthread_spinunlock(self, &target->pt_statelock);
                _lwp_wakeup(target->pt_blockedlwp);
-               break;
+               return;
        default:
                ;
        }
 
+       pthread__deliver_signal(self, target, sig, code);
+       pthread__sched(self, target);
+       pthread_spinunlock(self, &target->pt_statelock);
+}
+
+/* Must be called with target's siglock held */
+void
+pthread__deliver_signal(pthread_t self, pthread_t target, int sig, int code)
+{
+       sigset_t oldmask, *maskp;
+       ucontext_t *uc;
+
+       /*
+        * Prevent anyone else from considering this thread for handling
+        * more instances of this signal.
+        */
+       oldmask = target->pt_sigmask;
+       __sigplusset(&target->pt_sigmask, &pt_sigacts[sig].sa_mask);
+       __sigaddset14(&target->pt_sigmask, sig);
+       pthread_spinunlock(self, &target->pt_siglock);
+
        /*
         * We'd like to just pass oldmask to the
         * pthread__signal_tramp(), but makecontext() can't reasonably
@@ -519,38 +533,36 @@
 
        SDPRINTF(("(makecontext %p): target %p: sig: %d %d uc: %p oldmask: %08x\n",
            self, target, sig, code, target->pt_uc, maskp->__bits[0]));
-       makecontext(uc, pthread__signal_tramp, 8,
-           sig, code, &pt_sigacts[sig], target->pt_uc, maskp,
-           target->pt_state, target->pt_sleepq, target->pt_sleeplock);
+       makecontext(uc, pthread__signal_tramp, 5,
+           sig, code, pt_sigacts[sig].sa_handler, target->pt_uc, maskp);
        target->pt_uc = uc;
-
-       if (target->pt_state != PT_STATE_BLOCKED_SYS)
-               pthread__sched(self, target);
-       pthread_spinunlock(self, &target->pt_statelock);
 }
 
+void
+pthread__signal_deferred(pthread_t self, pthread_t t)
+{
+       int i;
+
+       pthread_spinlock(self, &t->pt_siglock);
+
+       while ((i = firstsig(&t->pt_sigblocked)) != 0) {
+               __sigdelset14(&t->pt_sigblocked, i);
+               pthread__deliver_signal(self, t, i, 0);
+       }
+       t->pt_flags &= ~PT_FLAG_SIGDEFERRED;
+
+       pthread_spinunlock(self, &t->pt_siglock);
+}
 
 static void 
-pthread__signal_tramp(int sig, int code, struct sigaction *act, 
-    ucontext_t *uc, sigset_t *oldmask, int oldstate,
-    struct pthread_queue_t *oldsleepq, pthread_spin_t *oldsleeplock)
+pthread__signal_tramp(int sig, int code,
+    void (*handler)(int, int, struct sigcontext *),
+    ucontext_t *uc, sigset_t *oldmask)
 {
-       void (*handler)(int, int, struct sigcontext *);
        struct pthread__sigcontext psc;
-       pthread_t self, next;
-
-       self = pthread__self();
 
-       SDPRINTF(("(tramp %p) sig %d uc %p oldmask %08x oldstate %d q %p\n", 
-           self, sig, uc, oldmask->__bits[0], oldstate, oldsleepq));
-
-       /*
-        * We should only ever get here if a handler is set. Signal
-        * actions are process-global; a signal set to SIG_DFL or
-        * SIG_IGN should be handled in the kernel (by being ignored
-        * or killing the process) and never get this far.
-        */
-       handler = (void (*)(int, int, struct sigcontext *)) act->sa_handler;
+       SDPRINTF(("(tramp %p) sig %d uc %p oldmask %08x\n", 
+           pthread__self(), sig, uc, oldmask->__bits[0]));
 
        /*
         * XXX we don't support siginfo here yet.
@@ -568,43 +580,6 @@
        pthread_sigmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
 
        /*
-        * Go back to whatever queue we were found on, unless SIGCATCH
-        * is set.  When we are continued, the first thing we do will
-        * be to jump back to the previous context.
-        */
-       if (self->pt_flags & PT_FLAG_SIGCATCH)
-               _setcontext_u(uc);
-               
-       next = pthread__next(self);
-       next->pt_state = PT_STATE_RUNNING;
-       pthread_spinlock(self, &self->pt_statelock);
-       if (oldstate == PT_STATE_RUNNABLE) {
-               pthread_spinlock(self, &pthread__runqueue_lock);
-               self->pt_state = PT_STATE_RUNNABLE;



Home | Main Index | Thread Index | Old Index