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