Source-Changes-HG archive

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

[src/trunk]: src fix SA/pthread pagefault failure:



details:   https://anonhg.NetBSD.org/src/rev/b4e5e3ebde11
branches:  trunk
changeset: 552030:b4e5e3ebde11
user:      cl <cl%NetBSD.org@localhost>
date:      Tue Sep 16 13:51:31 2003 +0000

description:
fix SA/pthread pagefault failure:
- prevent BLOCKED upcalls on double page faults and during upcalls
- make libpthread handle blocked threads which hold locks
- prevent UNBLOCKED upcalls from overtaking their BLOCKED upcall
this adds a new syscall sa_unblockyield
see also http://mail-index.netbsd.org/tech-kern/2003/09/15/0020.html

diffstat:

 include/sa.h                 |   3 +-
 lib/libc/sys/Makefile.inc    |   4 +-
 lib/libpthread/pthread_run.c |   7 ++-
 lib/libpthread/pthread_sa.c  |  86 ++++++++++++++++++++++++++++++++++---------
 4 files changed, 77 insertions(+), 23 deletions(-)

diffs (252 lines):

diff -r 9c185db95b77 -r b4e5e3ebde11 include/sa.h
--- a/include/sa.h      Tue Sep 16 13:49:23 2003 +0000
+++ b/include/sa.h      Tue Sep 16 13:51:31 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sa.h,v 1.2 2003/01/18 10:32:11 thorpej Exp $   */
+/*     $NetBSD: sa.h,v 1.3 2003/09/16 13:51:31 cl Exp $        */
 
 /*-
  * Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -53,6 +53,7 @@
 int    sa_setconcurrency __P((int));
 int    sa_yield __P((void));
 int    sa_preempt __P((int));
+int    sa_unblockyield __P((int, void *, stack_t *));
 __END_DECLS
 
 #endif /* !_SA_H_ */
diff -r 9c185db95b77 -r b4e5e3ebde11 lib/libc/sys/Makefile.inc
--- a/lib/libc/sys/Makefile.inc Tue Sep 16 13:49:23 2003 +0000
+++ b/lib/libc/sys/Makefile.inc Tue Sep 16 13:51:31 2003 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: Makefile.inc,v 1.143 2003/09/13 22:50:21 christos Exp $
+#      $NetBSD: Makefile.inc,v 1.144 2003/09/16 13:51:34 cl Exp $
 #      @(#)Makefile.inc        8.3 (Berkeley) 10/24/94
 
 # sys sources
@@ -79,7 +79,7 @@
        _lwp_suspend.S _lwp_continue.S _lwp_wakeup.S \
        _lwp_getprivate.S _lwp_setprivate.S \
        sa_register.S sa_stacks.S sa_enable.S sa_setconcurrency.S sa_yield.S \
-       sa_preempt.S \
+       sa_preempt.S sa_unblockyield.S \
        timer_create.S timer_delete.S timer_gettime.S timer_getoverrun.S \
        timer_settime.S
 
diff -r 9c185db95b77 -r b4e5e3ebde11 lib/libpthread/pthread_run.c
--- a/lib/libpthread/pthread_run.c      Tue Sep 16 13:49:23 2003 +0000
+++ b/lib/libpthread/pthread_run.c      Tue Sep 16 13:51:31 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread_run.c,v 1.11 2003/06/26 01:26:39 nathanw Exp $ */
+/*     $NetBSD: pthread_run.c,v 1.12 2003/09/16 13:51:35 cl Exp $      */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: pthread_run.c,v 1.11 2003/06/26 01:26:39 nathanw Exp $");
+__RCSID("$NetBSD: pthread_run.c,v 1.12 2003/09/16 13:51:35 cl Exp $");
 
 #include <ucontext.h>
 
@@ -193,6 +193,8 @@
 {
        pthread_t idlethread, qhead, next;
 
+       /* XXXconcurrency: only reidle threads on same vp */
+
        qhead = NULL;
        pthread_spinlock(self, &pthread__deadqueue_lock);
        idlethread = PTQ_FIRST(&pthread__reidlequeue);
@@ -227,6 +229,7 @@
        for ( ; qhead && (qhead != self) ; qhead = next) {
                next = qhead->pt_next;
                pthread__assert(qhead->pt_spinlocks == 0);
+               pthread__assert(qhead->pt_type != PT_THREAD_UPCALL);
                if (qhead->pt_type == PT_THREAD_NORMAL) {
                        qhead->pt_state = PT_STATE_RUNNABLE;
                        qhead->pt_next = NULL;
diff -r 9c185db95b77 -r b4e5e3ebde11 lib/libpthread/pthread_sa.c
--- a/lib/libpthread/pthread_sa.c       Tue Sep 16 13:49:23 2003 +0000
+++ b/lib/libpthread/pthread_sa.c       Tue Sep 16 13:51:31 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread_sa.c,v 1.15 2003/09/12 00:37:17 christos Exp $ */
+/*     $NetBSD: pthread_sa.c,v 1.16 2003/09/16 13:51:35 cl Exp $       */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: pthread_sa.c,v 1.15 2003/09/12 00:37:17 christos Exp $");
+__RCSID("$NetBSD: pthread_sa.c,v 1.16 2003/09/16 13:51:35 cl Exp $");
 
 #include <err.h>
 #include <errno.h>
@@ -89,7 +89,7 @@
 pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg)
 {
        pthread_t t, self, next, intqueue, schedqueue;
-       int flags, first = 1;
+       int flags;
        siginfo_t *si;
 
        PTHREADD_ADD(PTHREADD_UPCALLS);
@@ -104,17 +104,52 @@
            type, sas[0]->sa_id, ev ? sas[1]->sa_id : 0, 
            intr ? sas[ev+intr]->sa_id : 0));
 
-       if (type == SA_UPCALL_BLOCKED)
-               first++; /* Don't handle this SA in the usual processing. */
-
-       /*
-        * Do per-thread work, including saving the context.
-        * Briefly run any threads that were in a critical section.
-        * This includes any upcalls that have been interupted, so
-        * they can do their own version of this dance.
-        */
-       if ((ev + intr) >= first) {
-               pthread__find_interrupted(sas + first, ev + intr,
+       if (type == SA_UPCALL_BLOCKED) {
+               /* Don't handle this SA in the usual processing. */
+               t = pthread__sa_id(sas[1]);
+               pthread__assert(t->pt_type != PT_THREAD_UPCALL);
+               pthread__assert(self->pt_spinlocks == 0);
+               if ((t->pt_spinlocks > 0) || (t->pt_next)) {
+                       SDPRINTF(("(up %p) unblocking %p "
+                                    "(uc: T %p pc: %lx sp: %lx) "
+                                    "spinlocks: %d, pt_next: %p\n",
+                                    self, t, sas[1]->sa_context,
+                                    pthread__uc_pc(sas[1]->sa_context),
+                                    pthread__uc_sp(sas[1]->sa_context),
+                                    t->pt_spinlocks, t->pt_next));
+                       if (sa_unblockyield(sas[1]->sa_id, &self->pt_next,
+                               &self->pt_stack) != 0)
+                               pthread__abort();
+                       SDPRINTF(("(up %p) unblocking switchto to %p "
+                                    "(uc: T %p pc: %lx) chain %p\n",
+                                    self, t, sas[1]->sa_context,
+                                    pthread__uc_pc(sas[1]->sa_context),
+                                    self->pt_next));
+                       self->pt_switchtouc = sas[1]->sa_context;
+                       self->pt_switchto = t;
+                       pthread__switch(self, self->pt_next);
+                       /*NOTREACHED*/
+                       pthread__abort();
+               }
+               /* We can take spinlocks now */
+               if (t->pt_type == PT_THREAD_IDLE) {
+                       SDPRINTF(("(up %p) unblocking idle %p (uc: %c %p)\n",
+                                    self, t, PUC(t)));
+                       if (sa_unblockyield(sas[1]->sa_id, NULL,
+                               &self->pt_stack) != 0)
+                               pthread__abort();
+                       /* XXX need flaglock? */
+                       if ((t->pt_flags & PT_FLAG_IDLED) == 0)
+                               pthread__sched_bulk(self, t);
+               }
+       } else {
+               /*
+                * Do per-thread work, including saving the context.
+                * Briefly run any threads that were in a critical section.
+                * This includes any upcalls that have been interupted, so
+                * they can do their own version of this dance.
+                */
+               pthread__find_interrupted(sas + 1, ev + intr,
                    &intqueue, &schedqueue, self);
                if (intqueue != self)
                        pthread__resolve_locks(self, &intqueue);
@@ -129,7 +164,11 @@
 
        switch (type) {
        case SA_UPCALL_BLOCKED:
+               PTHREADD_ADD(PTHREADD_UP_BLOCK);
                t = pthread__sa_id(sas[1]);
+               pthread__assert(t->pt_type != PT_THREAD_UPCALL);
+               if (t->pt_type == PT_THREAD_IDLE)
+                       break;
                pthread_spinlock(self, &t->pt_statelock);
                t->pt_state = PT_STATE_BLOCKED_SYS;
                t->pt_blockedlwp = sas[1]->sa_id;
@@ -142,8 +181,6 @@
                t->pt_trapuc = sas[1]->sa_context;
                SDPRINTF(("(up %p) blocker %d %p(%d)\n", self, 1, t,
                             t->pt_type));
-
-               PTHREADD_ADD(PTHREADD_UP_BLOCK);
                break;
        case SA_UPCALL_NEWPROC:
                PTHREADD_ADD(PTHREADD_UP_NEW);
@@ -317,10 +354,14 @@
                }
                pthread__assert(victim != self);
                if (resume) {
+                       pthread__assert(victim->pt_parent == NULL);
                        victim->pt_parent = self;
+                       pthread__assert(victim->pt_next == NULL);
                        victim->pt_next = nextint;
                        nextint = victim;
                } else {
+                       pthread__assert(victim->pt_parent == NULL);
+                       pthread__assert(victim->pt_next == NULL);
                        victim->pt_next = nextsched;
                        nextsched = victim;
                }
@@ -420,6 +461,11 @@
                                if (victim->pt_switchto) {
                                        /* We're done with you. */
                                        SDPRINTF((" recyclable"));
+                                       /*
+                                        * Clear trap context, which is
+                                        * no longer useful.
+                                        */
+                                       victim->pt_trapuc = NULL;
                                        if (prev)
                                                prev->pt_next = next;
                                        else
@@ -474,14 +520,14 @@
                                SDPRINTF((" switchto: %p (uc %p)", switchto,
                                             switchto->pt_uc));
 
-                               pthread__assert(switchto->pt_spinlocks == 0);
                                /*
                                 * Threads can have switchto set to themselves
                                 * if they hit new_preempt. Don't put them
                                 * on the run queue twice.
                                 */
                                if (switchto != victim) {
-                                       if (switchto->pt_next) {
+                                       if ((switchto->pt_next) ||
+                                           (switchto->pt_spinlocks != 0)) {
                                                /*
                                                 * The thread being switched
                                                 * to was preempted and
@@ -494,7 +540,9 @@
                                                      tmp->pt_parent != NULL; 
                                                      tmp = tmp->pt_parent)
                                                        SDPRINTF((" parent: %p", tmp));
+                                               pthread__assert(tmp->pt_parent == NULL);
                                                tmp->pt_parent = self;
+                                               pthread__assert(tmp->pt_next == NULL);
                                                tmp->pt_next = intqueue;
                                                intqueue = tmp;
                                        } else {
@@ -519,6 +567,7 @@
                                     self, intqueue, PUC(intqueue), 
                                     pthread__uc_pc(UC(intqueue)), 
                                     pthread__uc_sp(UC(intqueue))));
+                       pthread__assert(intqueue->pt_state != PT_STATE_BLOCKED_SYS);
                        pthread__switch(self, intqueue);
                        SDPRINTF(("(rl %p) returned from chain\n",
                            self));
@@ -536,6 +585,7 @@
                                     PUC(self->pt_next),
                                     pthread__uc_pc(UC(self->pt_next)), 
                                     pthread__uc_sp(UC(self->pt_next))));
+                       pthread__assert(self->pt_next->pt_state != PT_STATE_BLOCKED_SYS);
                        pthread__switch(self, self->pt_next);
                }
 



Home | Main Index | Thread Index | Old Index