Source-Changes-HG archive

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

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



details:   https://anonhg.NetBSD.org/src/rev/0afa962cc1d0
branches:  trunk
changeset: 552028:0afa962cc1d0
user:      cl <cl%NetBSD.org@localhost>
date:      Tue Sep 16 13:46:24 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:

 sys/kern/kern_exit.c     |    7 +-
 sys/kern/kern_sa.c       |  262 ++++++++++++++++++++++++++++++++++++++++++++--
 sys/kern/syscalls.master |    7 +-
 sys/sys/lwp.h            |    4 +-
 sys/sys/savar.h          |    6 +-
 5 files changed, 267 insertions(+), 19 deletions(-)

diffs (truncated from 507 to 300 lines):

diff -r 4181fa0124c9 -r 0afa962cc1d0 sys/kern/kern_exit.c
--- a/sys/kern/kern_exit.c      Tue Sep 16 13:22:57 2003 +0000
+++ b/sys/kern/kern_exit.c      Tue Sep 16 13:46:24 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_exit.c,v 1.123 2003/09/13 15:32:40 christos Exp $ */
+/*     $NetBSD: kern_exit.c,v 1.124 2003/09/16 13:46:24 cl Exp $       */
 
 /*-
  * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
@@ -74,7 +74,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.123 2003/09/13 15:32:40 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.124 2003/09/16 13:46:24 cl Exp $");
 
 #include "opt_ktrace.h"
 #include "opt_perfctrs.h"
@@ -499,6 +499,9 @@
                if(l2->l_flag & L_SA_WANTS_VP)
                        wakeup(l2);
 
+               if (l2->l_wchan == &l2->l_upcallstack)
+                       wakeup(&l2->l_upcallstack);
+
                if ((l2->l_stat == LSSLEEP && (l2->l_flag & L_SINTR)) ||
                    l2->l_stat == LSSUSPENDED || l2->l_stat == LSSTOP) {
                        SCHED_LOCK(s);
diff -r 4181fa0124c9 -r 0afa962cc1d0 sys/kern/kern_sa.c
--- a/sys/kern/kern_sa.c        Tue Sep 16 13:22:57 2003 +0000
+++ b/sys/kern/kern_sa.c        Tue Sep 16 13:46:24 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_sa.c,v 1.23 2003/09/11 01:32:10 cl Exp $  */
+/*     $NetBSD: kern_sa.c,v 1.24 2003/09/16 13:46:24 cl Exp $  */
 
 /*-
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_sa.c,v 1.23 2003/09/11 01:32:10 cl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_sa.c,v 1.24 2003/09/16 13:46:24 cl Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -57,6 +57,8 @@
 static int sa_newcachelwp(struct lwp *);
 static struct lwp *sa_vp_repossess(struct lwp *l);
 
+static int sa_pagefault(struct lwp *, ucontext_t *);
+
 void sa_upcall_getstate(struct sadata_upcall *, struct lwp *, struct lwp *);
 
 MALLOC_DEFINE(M_SA, "sa", "Scheduler activations");
@@ -156,6 +158,10 @@
                sa->sa_stacks = malloc(sizeof(stack_t) * SA_NUMSTACKS,
                    M_SA, M_WAITOK);
                sa->sa_nstacks = 0;
+               sa->sa_vp_faultaddr = NULL;
+               sa->sa_vp_ofaultaddr = NULL;
+               sa->sa_vp_stacks_low = NULL;
+               sa->sa_vp_stacks_high = NULL;
                LIST_INIT(&sa->sa_lwpcache);
                SIMPLEQ_INIT(&sa->sa_upcalls);
                p->p_sa = sa;
@@ -183,7 +189,8 @@
                syscallarg(stack_t *) stacks;
        } */ *uap = v;
        struct sadata *sa = l->l_proc->p_sa;
-       int error, count;
+       struct lwp *l2;
+       int count, error, f, i;
 
        /* We have to be using scheduler activations */
        if (sa == NULL)
@@ -194,14 +201,35 @@
                return (EINVAL);
        count = min(count, SA_NUMSTACKS - sa->sa_nstacks);
 
+       SA_LWP_STATE_LOCK(l, f);
        error = copyin(SCARG(uap, stacks), sa->sa_stacks + sa->sa_nstacks,
            sizeof(stack_t) * count);
+       SA_LWP_STATE_UNLOCK(l, f);
        if (error)
                return (error);
 
+       for (i = sa->sa_nstacks; i < sa->sa_nstacks + count; i++) {
+               LIST_FOREACH(l2, &l->l_proc->p_lwps, l_sibling) {
+                       if ((l2->l_upcallstack == sa->sa_stacks[i].ss_sp)) {
+                               l2->l_upcallstack = NULL;
+                               wakeup(&l2->l_upcallstack);
+                       }
+               }
+       }
+
        if ((sa->sa_nstacks == 0) && (sa->sa_vp_wait_count != 0))
                l->l_flag |= L_SA_UPCALL; 
 
+       if (sa->sa_vp_stacks_low == 0) {
+               sa->sa_vp_stacks_low = (uintptr_t)sa->sa_stacks[0].ss_sp;
+               sa->sa_vp_stacks_high = (uintptr_t)sa->sa_stacks[count - 1].ss_sp +
+                       sa->sa_stacks[count - 1].ss_size;
+               DPRINTFN(11,("sys_sa_stacks(%d.%d): low 0x%llx high 0x%llx\n",
+                            l->l_proc->p_pid, l->l_lid,
+                            (unsigned long long)sa->sa_vp_stacks_low,
+                            (unsigned long long)sa->sa_vp_stacks_high));
+       }
+
        sa->sa_nstacks += count;
        DPRINTFN(9, ("sa_stacks(%d.%d) nstacks + %d = %2d\n",
            l->l_proc->p_pid, l->l_lid, count, sa->sa_nstacks));
@@ -278,8 +306,11 @@
 {
        struct proc *p = l->l_proc;
 
-       if (p->p_sa == NULL || !(p->p_flag & P_SA))
+       if (p->p_sa == NULL || !(p->p_flag & P_SA)) {
+               DPRINTFN(1,("sys_sa_yield(%d.%d) proc %p not SA (p_sa %p, flag %s)\n",
+                   p->p_pid, l->l_lid, p, p->p_sa, p->p_flag & P_SA ? "T" : "F"));
                return (EINVAL);
+       }
 
        sa_yield(l);
 
@@ -397,6 +428,127 @@
 }
 
 
+int
+sys_sa_unblockyield(struct lwp *l, void *v, register_t *retval)
+{
+       struct sys_sa_unblockyield_args /* {
+               syscallarg(int) sa_id;
+               syscallarg(void *) up_preempted;
+               syscallarg(stack_t *) up_stack;
+       } */ *uap = v;
+       struct sadata *sa = l->l_proc->p_sa;
+       struct proc *p = l->l_proc;
+       struct lwp *l2;
+       int error, f, s;
+       void *preempted;
+
+       if (sa == NULL)
+               return (EINVAL);
+
+       if (sa->sa_nstacks == SA_NUMSTACKS)
+               return (EINVAL);
+
+       SA_LWP_STATE_LOCK(l, f);
+       error = copyin(SCARG(uap, up_stack), sa->sa_stacks + sa->sa_nstacks,
+           sizeof(stack_t));
+       if (error) {
+               SA_LWP_STATE_UNLOCK(l, f);
+               return (error);
+       }
+
+       if (SCARG(uap, up_preempted) != NULL) {
+               error = copyin(SCARG(uap, up_preempted), &preempted,
+                   sizeof(void *));
+               if (error) {
+                       SA_LWP_STATE_UNLOCK(l, f);
+                       return (error);
+               }
+       } else
+               preempted = (void *)-1;
+       SA_LWP_STATE_UNLOCK(l, f);
+
+       SCHED_LOCK(s);
+       LIST_FOREACH(l2, &p->p_lwps, l_sibling) {
+               if (l2->l_lid == SCARG(uap, sa_id)) {
+                       KDASSERT(l2->l_upcallstack ==
+                           sa->sa_stacks[sa->sa_nstacks].ss_sp);
+                       break;
+               }
+       }
+       KDASSERT(l2 != NULL);
+
+       /*
+        * upcall not interrupted: (*up_preempted == NULL)
+        * - lwp ready: (wchan == upcallstacks)
+        * ==> recycle stack, put lwp on vp,
+        *     unsleep lwp, make runnable, recycle upcall lwp (=l)
+        * - lwp not ready:
+        * ==> recycle stack, put lwp on vp, recycle upcall lwp (=l)
+        *
+        * upcall interrupted: (*up_preempted != NULL || up_preempted == NULL)
+        * ==> recycle upcall lwp
+        */
+
+       if (preempted != NULL) {
+               DPRINTFN(11,("sys_sa_unblockyield(%d.%d) recycle %d "
+                            "(was %sready) upcall stack %p\n",
+                            p->p_pid, l->l_lid, l2->l_lid, 
+                            (l2->l_wchan == &l2->l_upcallstack) ? "" :
+                            "not ", sa->sa_stacks[sa->sa_nstacks].ss_sp));
+
+               l2->l_upcallstack = (void *)-1;
+               if (l2->l_wchan == &l2->l_upcallstack) {
+                       unsleep(l2);
+                       if (l2->l_stat == LSSLEEP) {
+                               l2->l_slptime = 0;
+                               l2->l_stat = LSRUN;
+                               l2->l_proc->p_nrlwps++;
+                               if (l2->l_flag & L_INMEM)
+                                       setrunqueue(l2);
+                               else
+                                       sched_wakeup((caddr_t)&proc0);
+                       }
+               }
+       } else {
+               DPRINTFN(11,("sys_sa_unblockyield(%d.%d) resuming %d "
+                            "(is %sready) upcall stack %p\n",
+                            p->p_pid, l->l_lid, l2->l_lid, 
+                            (l2->l_wchan == &l2->l_upcallstack) ? "" :
+                            "not ", sa->sa_stacks[sa->sa_nstacks].ss_sp));
+
+               sa->sa_vp = l2;
+               sa->sa_nstacks += 1;
+               l2->l_flag &= ~L_SA_BLOCKING;
+               l2->l_upcallstack = NULL;
+
+               if (l2->l_wchan == &l2->l_upcallstack) {
+                       unsleep(l2);
+                       if (l2->l_stat == LSSLEEP) {
+                               l2->l_slptime = 0;
+                               l2->l_stat = LSRUN;
+                               l2->l_proc->p_nrlwps++;
+                               if (l2->l_flag & L_INMEM)
+                                       setrunqueue(l2);
+                               else
+                                       sched_wakeup((caddr_t)&proc0);
+                       }
+               }
+
+               p->p_nrlwps--;
+               sa_putcachelwp(p, l);
+               mi_switch(l, NULL);
+               /* mostly NOTREACHED */
+               SCHED_ASSERT_UNLOCKED();
+               splx(s);
+               KDASSERT(p->p_flag & P_WEXIT);
+               lwp_exit(l);
+       }
+
+       SCHED_UNLOCK(s);
+       return (0);
+}
+
+
 /*
  * Set up the user-level stack and trapframe to do an upcall.
  *
@@ -410,7 +562,7 @@
        struct sadata_upcall *sau;
        struct sadata *sa = l->l_proc->p_sa;
        stack_t st;
-       int f;
+       int error, f;
 
        /* XXX prevent recursive upcalls if we sleep formemory */
        SA_LWP_STATE_LOCK(l, f);
@@ -428,15 +580,23 @@
        DPRINTFN(9,("sa_upcall(%d.%d) nstacks--   = %2d\n", 
            l->l_proc->p_pid, l->l_lid, sa->sa_nstacks));
 
-       return sa_upcall0(l, type, event, interrupted, argsize, arg, sau, &st);
+       error = sa_upcall0(l, type, event, interrupted, argsize, arg, sau, &st);
+       if (error) {
+               sa->sa_stacks[sa->sa_nstacks++] = st;
+               sadata_upcall_free(sau);
+               return (error);
+       }
+
+       SIMPLEQ_INSERT_TAIL(&sa->sa_upcalls, sau, sau_next);
+       l->l_flag |= L_SA_UPCALL;
+
+       return (0);
 }
 
 int
 sa_upcall0(struct lwp *l, int type, struct lwp *event, struct lwp *interrupted,
     size_t argsize, void *arg, struct sadata_upcall *sau, stack_t *st)
 {
-       struct proc *p = l->l_proc;
-       struct sadata *sa = p->p_sa;
 
        KDASSERT((event == NULL) || (event != interrupted));
 
@@ -453,9 +613,6 @@
        } else
                sa_upcall_getstate(sau, event, interrupted);
 
-       SIMPLEQ_INSERT_TAIL(&sa->sa_upcalls, sau, sau_next);
-       l->l_flag |= L_SA_UPCALL;
-
        return (0);
 }
 
@@ -496,6 +653,38 @@



Home | Main Index | Thread Index | Old Index