Source-Changes-HG archive

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

[src/netbsd-3]: src/lib/libpthread Pullup revs 1.43-1.44 (requested by chs in...



details:   https://anonhg.NetBSD.org/src/rev/eda77d72bd9b
branches:  netbsd-3
changeset: 577426:eda77d72bd9b
user:      jmc <jmc%NetBSD.org@localhost>
date:      Tue Nov 01 20:01:38 2005 +0000

description:
Pullup revs 1.43-1.44 (requested by chs in ticket #926)
 In pthread_mutex_lock_slow(), pthread_rwlock_timedrdlock() and sem_wait(),
 call pthread__start() if it hasn't already been called. this avoids
 an internal assertion from the library if these routines are used
 before any threads are created and they need to sleep.
 PR#20256, PR#24241, PR#25722, PR#26096

 Fix the interaction between sigtimedwait() and pthread_kill(),
 both waking up a sleeping thread and avoiding going to sleep if
 a signal is already pending. PR#30348

 In pthread_kill() and pthread_suspend_np(), return without doing anything
 f the target thread is a zombie.
 In all the functions that didn't do so already, verify a pthread_t before
 dereferencing it (under #ifdef ERRORCHECK, since these checks are not
 mandated by the standard).

 Starting the pthread library (ie. calling pthread__start()) before
 any threads are created turned out to be not such a good idea.
 there are stronger requirements on what has to work in a forked child
 while a process is still single-threaded. so take all that stuff
 back out and fix the problems with single-threaded programs that
 are linked with libpthread differently, by checking if the library
 has been started and doing completely different stuff if it hasn't been:
 - for pthread_rwlock_timedrdlock(), just fail with EDEADLK immediately.
 - for sem_wait(), the only thing that can unlock the semaphore is a
 signal handler, so use sigsuspend() to wait for a signal.
 - for pthread_mutex_lock_slow(), just go into an infinite loop
 waiting for signals.

 If mlock() fails in pthread_create(), return EAGAIN instead of
 failing an assertion.

diffstat:

 lib/libpthread/pthread_sig.c |  109 +++++++++++++++++++++++++++++++++++-------
 1 files changed, 91 insertions(+), 18 deletions(-)

diffs (268 lines):

diff -r d94c0e35d769 -r eda77d72bd9b lib/libpthread/pthread_sig.c
--- a/lib/libpthread/pthread_sig.c      Tue Nov 01 20:01:33 2005 +0000
+++ b/lib/libpthread/pthread_sig.c      Tue Nov 01 20:01:38 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread_sig.c,v 1.39.2.2 2005/08/12 06:38:14 snj Exp $ */
+/*     $NetBSD: pthread_sig.c,v 1.39.2.3 2005/11/01 20:01:38 jmc Exp $ */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: pthread_sig.c,v 1.39.2.2 2005/08/12 06:38:14 snj Exp $");
+__RCSID("$NetBSD: pthread_sig.c,v 1.39.2.3 2005/11/01 20:01:38 jmc Exp $");
 
 /* We're interposing a specific version of the signal interface. */
 #define        __LIBC12_SOURCE__
@@ -298,13 +298,13 @@
 }
 
 int
-sigtimedwait(const sigset_t * __restrict set, siginfo_t * __restrict info, const struct timespec * __restrict timeout)
+sigtimedwait(const sigset_t * __restrict set, siginfo_t * __restrict info,
+    const struct timespec * __restrict timeout)
 {
-       pthread_t self;
-       int error = 0;
-       pthread_t target;
+       pthread_t self, target;
        sigset_t wset;
        struct timespec timo;
+       int sig, error = 0;
 
        /* if threading not started yet, just do the syscall */
        if (__predict_false(pthread__started == 0))
@@ -313,31 +313,54 @@
        self = pthread__self();
        pthread__testcancel(self);
 
+       pthread_spinlock(self, &self->pt_siglock);
+
+       /*
+        * Check if one of the signals that we will be waiting for
+        * is already pending.  If so, return it immediately.
+        * XXX the MP locking of this isn't right.
+        */
+       wset = *set;
+       __sigandset(&self->pt_siglist, &wset);
+       sig = firstsig(&wset);
+       if (sig) {
+               info->si_signo = sig;
+               pthread_spinunlock(self, &self->pt_siglock);
+               pthread__testcancel(self);
+               return 0;
+       }
+
        /* also call syscall if timeout is zero (i.e. polling) */
        if (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
+               pthread_spinunlock(self, &self->pt_siglock);
                error = _sigtimedwait(set, info, timeout);
                pthread__testcancel(self);
                return (error);
        }
-
        if (timeout) {
-               if ((u_int) timeout->tv_nsec >= 1000000000)
-                       return (EINVAL);
+               if ((u_int) timeout->tv_nsec >= 1000000000) {
+                       pthread_spinunlock(self, &self->pt_siglock);
+                       errno = EINVAL;
+                       return (-1);
+               }
 
                timo = *timeout;
        }
 
+       pthread_spinunlock(self, &self->pt_siglock);
        pthread_spinlock(self, &pt_sigwaiting_lock);
 
        /*
-        * If there is already master thread running, arrange things
-        * to accomodate for eventual extra signals to wait for,
+        * If there is already a master thread running, arrange things
+        * to accomodate for eventual extra signals to wait for
         * and join the sigwaiting list.
         */
        if (pt_sigwmaster) {
                struct pt_alarm_t timoalarm;
                struct timespec etimo;
 
+               SDPRINTF(("(stw %p) not master\n", self));
+
                /*
                 * Get current time. We need it if we would become master.
                 */
@@ -382,7 +405,9 @@
 
                PTQ_INSERT_TAIL(&pt_sigwaiting, self, pt_sleep);
 
+               SDPRINTF(("(stw %p) not master blocking\n", self));
                pthread__block(self, &pt_sigwaiting_lock);
+               SDPRINTF(("(stw %p) not master unblocked\n", self));
 
                /* check if we got a signal we waited for */
                if (info->si_signo) {
@@ -442,6 +467,7 @@
 
        /* Master thread loop */
        pt_sigwmaster = self;
+       SDPRINTF(("(stw %p) i am the master\n", self));
        for(;;) {
                /* Build our wait set */
                wset = *set;
@@ -456,39 +482,50 @@
                 * We are either the only one, or wait set was setup already.
                 * Just do the syscall now.
                 */
+               SDPRINTF(("(stw %p) master blocking\n", self));
                error = __sigtimedwait(&wset, info, (timeout) ? &timo : NULL);
+               SDPRINTF(("(stw %p) master unblocking\n", self));
 
                pthread_spinlock(self, &pt_sigwaiting_lock);
                if ((error && (errno != ECANCELED || self->pt_cancel))
                    || (!error && __sigismember14(set, info->si_signo)) ) {
+
                        /*
                         * Normal function return. Clear pt_sigwmaster,
                         * and if wait queue is nonempty, make first waiter
                         * new master.
                         */
+                       SDPRINTF(("(stw %p) master normal self %d\n",
+                                 self, info->si_signo));
                        pt_sigwmaster = NULL;
                        if (!PTQ_EMPTY(&pt_sigwaiting)) {
                                pt_sigwmaster = PTQ_FIRST(&pt_sigwaiting);
+                               SDPRINTF(("(stw %p) new master %p\n", self,
+                                         pt_sigwmaster));
                                PTQ_REMOVE(&pt_sigwaiting, pt_sigwmaster,
                                        pt_sleep);
                                pthread__sched(self, pt_sigwmaster);
                        }
 
                        pthread_spinunlock(self, &pt_sigwaiting_lock);
-
                        pthread__testcancel(self);
                        return (error);
                }
 
                if (!error) {
+
                        /*
                         * Got a signal, but not from _our_ wait set.
                         * Scan the queue of sigwaiters and wakeup
                         * the first thread waiting for this signal.
                         */
                        PTQ_FOREACH(target, &pt_sigwaiting, pt_sleep) {
-                           if (__sigismember14(target->pt_sigwait, info->si_signo)) {
-                               pthread__assert(target->pt_state == PT_STATE_BLOCKED_QUEUE);
+                           if (__sigismember14(target->pt_sigwait,
+                                               info->si_signo)) {
+                               pthread__assert(target->pt_state ==
+                                               PT_STATE_BLOCKED_QUEUE);
+                               SDPRINTF(("(stw %p) master target %p\n",
+                                         self, target));
 
                                /* copy to waiter siginfo */
                                memcpy(target->pt_wsig, info, sizeof(*info));
@@ -499,6 +536,7 @@
                        }
 
                        if (!target) {
+
                                /*
                                 * Didn't find anyone waiting on this signal.
                                 * Deliver signal normally. This might
@@ -506,11 +544,14 @@
                                 * 'their' signal arrives before the master
                                 * thread would be scheduled after _lwp_wakeup().
                                 */
+                               SDPRINTF(("(stw %p) master orphaned\n", self));
                                pthread__signal(self, NULL, info);
                        } else {
+
                                /*
                                 * Signal waiter removed, adjust our wait set.
                                 */
+                               SDPRINTF(("(stw %p) master raced\n", self));
                                wset = *set;
                                PTQ_FOREACH(target, &pt_sigwaiting, pt_sleep)
                                        __sigplusset(target->pt_sigwait, &wset);
@@ -786,14 +827,38 @@
 static void
 pthread__kill(pthread_t self, pthread_t target, siginfo_t *si)
 {
+       int deliver;
 
        SDPRINTF(("(pthread__kill %p) target %p sig %d code %d\n", self, target,
            si->si_signo, si->si_code));
 
        if (__sigismember14(&target->pt_sigmask, si->si_signo)) {
-               /* Record the signal for later delivery. */
-               __sigaddset14(&target->pt_siglist, si->si_signo);
-               return;
+               SDPRINTF(("(pthread__kill %p) target masked\n", target));
+
+               /*
+                * If the target is waiting for this signal in sigtimedwait(),
+                * make the target runnable but do not deliver the signal.
+                * Otherwise record the signal for later delivery.
+                * XXX not MPsafe.
+                */
+               pthread_spinlock(self, &self->pt_statelock);
+               if (target->pt_state == PT_STATE_BLOCKED_QUEUE &&
+                   target->pt_sleepq == &pt_sigwaiting &&
+                   __sigismember14(target->pt_sigwait, si->si_signo)) {
+                       SDPRINTF(("(pthread__kill %p) stw\n", target));
+                       target->pt_wsig->si_signo = si->si_signo;
+                       pthread_spinunlock(self, &self->pt_statelock);
+                       deliver = 0;
+               } else {
+                       SDPRINTF(("(pthread__kill %p) deferring\n", target));
+                       pthread_spinunlock(self, &self->pt_statelock);
+                       __sigaddset14(&target->pt_siglist, si->si_signo);
+                       return;
+               }
+       } else {
+               SDPRINTF(("(pthread__kill %p) target %p delivering\n",
+                         self, target));
+               deliver = 1;
        }
 
        if (self == target) {
@@ -817,6 +882,8 @@
         */
        pthread_spinlock(self, &target->pt_statelock);
        if (target->pt_blockgen != target->pt_unblockgen) {
+               SDPRINTF(("(pthread__kill %p) target blocked\n", target));
+
                /*
                 * The target is not on a queue at all, and
                 * won't run again for a while. Try to wake it
@@ -832,6 +899,8 @@
                _lwp_wakeup(target->pt_blockedlwp);
                return;
        }
+       SDPRINTF(("(pthread__kill %p) target state %d\n", target,
+                 target->pt_state));
        switch (target->pt_state) {
        case PT_STATE_SUSPENDED:
                pthread_spinlock(self, &pthread__runqueue_lock);
@@ -848,11 +917,15 @@
                PTQ_REMOVE(target->pt_sleepq, target, pt_sleep);
                pthread_spinunlock(self, target->pt_sleeplock);
                break;
+       case PT_STATE_ZOMBIE:
+               pthread_spinunlock(self, &target->pt_statelock);
+               return;
        default:
                ;
        }
 
-       pthread__deliver_signal(self, target, si);
+       if (deliver)
+               pthread__deliver_signal(self, target, si);
        pthread__sched(self, target);
        pthread_spinunlock(self, &target->pt_statelock);
 }



Home | Main Index | Thread Index | Old Index