avoid calling into the pool code while holding sched_lock

since both pool_get() and pool_put() can call wakeup().
instead, allocate the struct sadata_upcall before taking
sched_lock in mi_switch() and free it after releasing sched_lock.

clean up some modularity warts by adding a callback to
struct sadata_upcall for freeing sa_arg.
This commit is contained in:
chs 2005-10-02 17:51:27 +00:00
parent 9c47d944e4
commit 7c02feca68
6 changed files with 115 additions and 133 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_sa.c,v 1.65 2005/09/07 23:31:06 christos Exp $ */
/* $NetBSD: kern_sa.c,v 1.66 2005/10/02 17:51:27 chs Exp $ */
/*-
* Copyright (c) 2001, 2004, 2005 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_sa.c,v 1.65 2005/09/07 23:31:06 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_sa.c,v 1.66 2005/10/02 17:51:27 chs Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -70,8 +70,8 @@ static struct lwp *sa_vp_repossess(struct lwp *l);
static __inline int sa_pagefault(struct lwp *, ucontext_t *);
static int sa_upcall0(struct lwp *, int, struct lwp *, struct lwp *,
size_t, void *, struct sadata_upcall *);
static void sa_upcall0(struct sadata_upcall *, int, struct lwp *, struct lwp *,
size_t, void *, void (*)(void *));
static void sa_upcall_getstate(union sau_state *, struct lwp *);
MALLOC_DEFINE(M_SA, "sa", "Scheduler activations");
@ -109,39 +109,30 @@ SPLAY_GENERATE(sasttree, sastack, sast_node, sast_compare);
struct sadata_upcall *
sadata_upcall_alloc(int waitok)
{
struct sadata_upcall *sau;
/* XXX zero the memory? */
return (pool_get(&saupcall_pool, waitok ? PR_WAITOK : PR_NOWAIT));
sau = pool_get(&saupcall_pool, waitok ? PR_WAITOK : PR_NOWAIT);
if (sau) {
sau->sau_arg = NULL;
}
return sau;
}
/*
* sadata_upcall_free:
*
* Free an sadata_upcall structure, and any associated
* argument data.
* Free an sadata_upcall structure and any associated argument data.
*/
void
sadata_upcall_free(struct sadata_upcall *sau)
{
extern struct pool siginfo_pool; /* XXX Ew. */
/*
* XXX We have to know what the origin of sau_arg is
* XXX in order to do the right thing, here. Sucks
* XXX to be a non-garbage-collecting kernel.
*/
if (sau->sau_arg) {
switch (sau->sau_type) {
case SA_UPCALL_SIGNAL:
case SA_UPCALL_SIGEV:
pool_put(&siginfo_pool, sau->sau_arg);
break;
default:
panic("sadata_free: unknown type of sau_arg: %d",
sau->sau_type);
}
if (sau == NULL) {
return;
}
if (sau->sau_arg) {
(*sau->sau_argfreefunc)(sau->sau_arg);
}
pool_put(&saupcall_pool, sau);
}
@ -443,7 +434,7 @@ sys_sa_enable(struct lwp *l, void *v, register_t *retval)
if (p->p_flag & P_SA) /* Already running! */
return (EBUSY);
error = sa_upcall(l, SA_UPCALL_NEWPROC, l, NULL, 0, NULL);
error = sa_upcall(l, SA_UPCALL_NEWPROC, l, NULL, 0, NULL, NULL);
if (error)
return (error);
@ -496,7 +487,7 @@ sa_increaseconcurrency(struct lwp *l, int concurrency)
l2->l_savp->savp_lwp = l2;
cpu_setfunc(l2, sa_switchcall, NULL);
error = sa_upcall(l2, SA_UPCALL_NEWPROC,
NULL, NULL, 0, NULL);
NULL, NULL, 0, NULL, NULL);
if (error) {
/* free new savp */
SLIST_REMOVE(&sa->sa_vps, l2->l_savp,
@ -587,11 +578,14 @@ sys_sa_setconcurrency(struct lwp *l, void *v, register_t *retval)
vp->savp_lwp->l_flag &=
~(L_SA_IDLE|L_SA_YIELD|L_SINTR);
SCHED_UNLOCK(s);
DPRINTFN(11,("sys_sa_concurrency(%d.%d) NEWPROC vp %d\n",
l->l_proc->p_pid, l->l_lid, vp->savp_id));
DPRINTFN(11,("sys_sa_concurrency(%d.%d) "
"NEWPROC vp %d\n",
l->l_proc->p_pid, l->l_lid,
vp->savp_id));
cpu_setfunc(vp->savp_lwp, sa_switchcall, NULL);
/* error = */ sa_upcall(vp->savp_lwp, SA_UPCALL_NEWPROC,
NULL, NULL, 0, NULL);
/* error = */ sa_upcall(vp->savp_lwp,
SA_UPCALL_NEWPROC,
NULL, NULL, 0, NULL, NULL);
SCHED_LOCK(s);
sa->sa_concurrency++;
setrunnable(vp->savp_lwp);
@ -721,7 +715,7 @@ sa_preempt(struct lwp *l)
*/
if (sa->sa_flag & SA_FLAG_PREEMPT)
sa_upcall(l, SA_UPCALL_PREEMPTED | SA_UPCALL_DEFER_EVENT,
l, NULL, 0, NULL);
l, NULL, 0, NULL, NULL);
}
@ -733,13 +727,13 @@ sa_preempt(struct lwp *l)
*/
int
sa_upcall(struct lwp *l, int type, struct lwp *event, struct lwp *interrupted,
size_t argsize, void *arg)
size_t argsize, void *arg, void (*func)(void *))
{
struct sadata_upcall *sau;
struct sadata *sa = l->l_proc->p_sa;
struct sadata_vp *vp = l->l_savp;
struct sastack *sast;
int error, f;
int f;
/* XXX prevent recursive upcalls if we sleep for memory */
SA_LWP_STATE_LOCK(l, f);
@ -754,12 +748,7 @@ sa_upcall(struct lwp *l, int type, struct lwp *event, struct lwp *interrupted,
SA_LWP_STATE_LOCK(l, f);
sau = sadata_upcall_alloc(1);
SA_LWP_STATE_UNLOCK(l, f);
error = sa_upcall0(l, type, event, interrupted, argsize, arg, sau);
if (error) {
sadata_upcall_free(sau);
sa_setstackfree(sast, sa);
return (error);
}
sa_upcall0(sau, type, event, interrupted, argsize, arg, func);
sau->sau_stack = sast->sast_stack;
SIMPLEQ_INSERT_TAIL(&vp->savp_upcalls, sau, sau_next);
@ -768,15 +757,14 @@ sa_upcall(struct lwp *l, int type, struct lwp *event, struct lwp *interrupted,
return (0);
}
static int
sa_upcall0(struct lwp *l, int type, struct lwp *event, struct lwp *interrupted,
size_t argsize, void *arg, struct sadata_upcall *sau)
static void
sa_upcall0(struct sadata_upcall *sau, int type, struct lwp *event,
struct lwp *interrupted, size_t argsize, void *arg, void (*func)(void *))
{
KDASSERT((event == NULL) || (event != interrupted));
sau->sau_flags = 0;
sau->sau_arg = 0;
if (type & SA_UPCALL_DEFER_EVENT) {
sau->sau_event.ss_deferred.ss_lwp = event;
@ -792,8 +780,7 @@ sa_upcall0(struct lwp *l, int type, struct lwp *event, struct lwp *interrupted,
sau->sau_type = type & SA_UPCALL_TYPE_MASK;
sau->sau_argsize = argsize;
sau->sau_arg = arg;
return (0);
sau->sau_argfreefunc = func;
}
@ -868,14 +855,15 @@ sa_pagefault(struct lwp *l, ucontext_t *l_ctx)
* TSLEEP() ITSELF! We are called with sched_lock held, and must
* hold it right through the mi_switch() call.
*/
void
sa_switch(struct lwp *l, int type)
sa_switch(struct lwp *l, struct sadata_upcall *sau, int type)
{
struct proc *p = l->l_proc;
struct sadata_vp *vp = l->l_savp;
struct sadata_upcall *sau;
struct lwp *l2;
int error, s;
struct sadata_upcall *freesau = NULL;
int s;
DPRINTFN(4,("sa_switch(%d.%d type %d VP %d)\n", p->p_pid, l->l_lid,
type, vp->savp_lwp ? vp->savp_lwp->l_lid : 0));
@ -884,10 +872,12 @@ sa_switch(struct lwp *l, int type)
if (p->p_flag & P_WEXIT) {
mi_switch(l, NULL);
sadata_upcall_free(sau);
return;
}
if (l->l_flag & L_SA_YIELD) {
/*
* Case 0: we're blocking in sa_yield
*/
@ -902,6 +892,7 @@ sa_switch(struct lwp *l, int type)
s = splsched();
SCHED_UNLOCK(s);
}
sadata_upcall_free(sau);
return;
} else if (vp->savp_lwp == l) {
/*
@ -910,6 +901,15 @@ sa_switch(struct lwp *l, int type)
* UNBLOCKED upcall.
*/
if (sau == NULL) {
#ifdef DIAGNOSTIC
printf("sa_switch(%d.%d): no upcall data.\n",
p->p_pid, l->l_lid);
#endif
mi_switch(l, NULL);
return;
}
/*
* The process of allocating a new LWP could cause
* sleeps. We're called from inside sleep, so that
@ -931,38 +931,12 @@ sa_switch(struct lwp *l, int type)
p->p_pid, l->l_lid);
#endif
mi_switch(l, NULL);
return;
}
/*
* XXX We need to allocate the sadata_upcall structure here,
* XXX since we can't sleep while waiting for memory inside
* XXX sa_upcall(). It would be nice if we could safely
* XXX allocate the sadata_upcall structure on the stack, here.
*/
sau = sadata_upcall_alloc(0);
if (sau == NULL) {
#ifdef DIAGNOSTIC
printf("sa_switch(%d.%d): couldn't allocate upcall data.\n",
p->p_pid, l->l_lid);
#endif
sa_putcachelwp(p, l2); /* PHOLD from sa_getcachelwp */
mi_switch(l, NULL);
sadata_upcall_free(sau);
return;
}
cpu_setfunc(l2, sa_switchcall, sau);
error = sa_upcall0(l2, SA_UPCALL_BLOCKED, l, NULL, 0, NULL,
sau);
if (error) {
#ifdef DIAGNOSTIC
printf("sa_switch(%d.%d): Error %d from sa_upcall()\n",
p->p_pid, l->l_lid, error);
#endif
sa_putcachelwp(p, l2); /* PHOLD from sa_getcachelwp */
mi_switch(l, NULL);
return;
}
sa_upcall0(sau, SA_UPCALL_BLOCKED, l, NULL, 0, NULL, NULL);
/*
* Perform the double/upcall pagefault check.
@ -975,9 +949,9 @@ sa_switch(struct lwp *l, int type)
*/
if ((l->l_flag & L_SA_PAGEFAULT) && sa_pagefault(l,
&sau->sau_event.ss_captured.ss_ctx) != 0) {
sadata_upcall_free(sau);
sa_putcachelwp(p, l2); /* PHOLD from sa_getcachelwp */
mi_switch(l, NULL);
sadata_upcall_free(sau);
DPRINTFN(10,("sa_switch(%d.%d) page fault resolved\n",
p->p_pid, l->l_lid));
if (vp->savp_faultaddr == vp->savp_ofaultaddr)
@ -997,6 +971,7 @@ sa_switch(struct lwp *l, int type)
KDASSERT(l2 != l);
} else if (vp->savp_lwp != NULL) {
/*
* Case 2: We've been woken up while another LWP was
* on the VP, but we're going back to sleep without
@ -1007,11 +982,13 @@ sa_switch(struct lwp *l, int type)
* go. If the LWP on the VP was idling, don't make it
* run again, though.
*/
freesau = sau;
if (vp->savp_lwp->l_flag & L_SA_YIELD)
l2 = NULL;
else {
l2 = vp->savp_lwp; /* XXXUPSXXX Unfair advantage for l2 ? */
if((l2->l_stat != LSRUN) || ((l2->l_flag & L_INMEM) == 0))
/* XXXUPSXXX Unfair advantage for l2 ? */
l2 = vp->savp_lwp;
if (l2->l_stat != LSRUN || (l2->l_flag & L_INMEM) == 0)
l2 = NULL;
}
} else {
@ -1022,7 +999,7 @@ sa_switch(struct lwp *l, int type)
DPRINTFN(4,("sa_switch(%d.%d) switching to LWP %d.\n",
p->p_pid, l->l_lid, l2 ? l2->l_lid : 0));
mi_switch(l, l2);
sadata_upcall_free(freesau);
DPRINTFN(4,("sa_switch(%d.%d flag %x) returned.\n",
p->p_pid, l->l_lid, l->l_flag));
KDASSERT(l->l_wchan == 0);
@ -1043,13 +1020,14 @@ sa_switchcall(void *arg)
l2 = curlwp;
p = l2->l_proc;
vp = l2->l_savp;
if (p->p_flag & P_WEXIT)
lwp_exit(l2);
KDASSERT(vp->savp_lwp == l2);
sau = arg;
if (p->p_flag & P_WEXIT) {
sadata_upcall_free(sau);
lwp_exit(l2);
}
KDASSERT(vp->savp_lwp == l2);
DPRINTFN(6,("sa_switchcall(%d.%d)\n", p->p_pid, l2->l_lid));
l2->l_flag &= ~L_SA;
@ -1219,7 +1197,6 @@ sa_unblock_userret(struct lwp *l)
lwp_exit(l);
sau = sadata_upcall_alloc(1);
sau->sau_arg = NULL;
if (p->p_flag & P_WEXIT) {
sadata_upcall_free(sau);
lwp_exit(l);
@ -1235,19 +1212,8 @@ sa_unblock_userret(struct lwp *l)
* Defer saving the event lwp's state because a
* PREEMPT upcall could be on the queue already.
*/
if (sa_upcall0(l, SA_UPCALL_UNBLOCKED | SA_UPCALL_DEFER_EVENT,
l, l2, 0, NULL, sau) != 0) {
/*
* We were supposed to deliver an UNBLOCKED
* upcall, but don't have resources to do so.
*/
#ifdef DIAGNOSTIC
printf("sa_unblock_userret: out of upcall resources"
" for %d.%d\n", p->p_pid, l->l_lid);
#endif
sigexit(l, SIGABRT);
/* NOTREACHED */
}
sa_upcall0(sau, SA_UPCALL_UNBLOCKED | SA_UPCALL_DEFER_EVENT,
l, l2, 0, NULL, NULL);
sau->sau_stack = sast->sast_stack;
SCHED_LOCK(s);
@ -1309,25 +1275,12 @@ sa_upcall_userret(struct lwp *l)
p->p_pid, l->l_lid, l2->l_lid));
sau = sadata_upcall_alloc(1);
sau->sau_arg = NULL;
if (p->p_flag & P_WEXIT) {
sadata_upcall_free(sau);
lwp_exit(l);
}
if (sa_upcall0(l, SA_UPCALL_UNBLOCKED, l2, l, 0, NULL,
sau) != 0) {
/*
* We were supposed to deliver an UNBLOCKED
* upcall, but don't have resources to do so.
*/
#ifdef DIAGNOSTIC
printf("sa_upcall_userret: out of upcall resources"
" for %d.%d\n", p->p_pid, l->l_lid);
#endif
sigexit(l, SIGABRT);
/* NOTREACHED */
}
sa_upcall0(sau, SA_UPCALL_UNBLOCKED, l2, l, 0, NULL, NULL);
sau->sau_stack = sast->sast_stack;
SIMPLEQ_INSERT_TAIL(&vp->savp_upcalls, sau, sau_next);

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_sig.c,v 1.208 2005/07/23 22:02:13 cube Exp $ */
/* $NetBSD: kern_sig.c,v 1.209 2005/10/02 17:51:27 chs Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.208 2005/07/23 22:02:13 cube Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.209 2005/10/02 17:51:27 chs Exp $");
#include "opt_ktrace.h"
#include "opt_compat_sunos.h"
@ -1388,6 +1388,20 @@ kpsignal2(struct proc *p, const ksiginfo_t *ksi, int dolock)
SCHED_UNLOCK(s);
}
siginfo_t *
siginfo_alloc(int flags)
{
return pool_get(&siginfo_pool, flags);
}
void
siginfo_free(void *arg)
{
pool_put(&siginfo_pool, arg);
}
void
kpsendsig(struct lwp *l, const ksiginfo_t *ksi, const sigset_t *mask)
{
@ -1402,7 +1416,7 @@ kpsendsig(struct lwp *l, const ksiginfo_t *ksi, const sigset_t *mask)
f = l->l_flag & L_SA;
l->l_flag &= ~L_SA;
si = pool_get(&siginfo_pool, PR_WAITOK);
si = siginfo_alloc(PR_WAITOK);
si->_info = ksi->ksi_info;
le = li = NULL;
if (KSI_TRAP_P(ksi))
@ -1410,8 +1424,8 @@ kpsendsig(struct lwp *l, const ksiginfo_t *ksi, const sigset_t *mask)
else
li = l;
if (sa_upcall(l, SA_UPCALL_SIGNAL | SA_UPCALL_DEFER, le, li,
sizeof(*si), si) != 0) {
pool_put(&siginfo_pool, si);
sizeof(*si), si, siginfo_free) != 0) {
siginfo_free(si);
if (KSI_TRAP_P(ksi))
/* XXX What do we do here?? */;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_synch.c,v 1.149 2005/05/29 22:24:15 christos Exp $ */
/* $NetBSD: kern_synch.c,v 1.150 2005/10/02 17:51:27 chs Exp $ */
/*-
* Copyright (c) 1999, 2000, 2004 The NetBSD Foundation, Inc.
@ -76,7 +76,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_synch.c,v 1.149 2005/05/29 22:24:15 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_synch.c,v 1.150 2005/10/02 17:51:27 chs Exp $");
#include "opt_ddb.h"
#include "opt_ktrace.h"
@ -384,6 +384,7 @@ ltsleep(__volatile const void *ident, int priority, const char *wmesg, int timo,
struct lwp *l = curlwp;
struct proc *p = l ? l->l_proc : NULL;
struct slpque *qp;
struct sadata_upcall *sau;
int sig, s;
int catch = priority & PCATCH;
int relock = (priority & PNORELOCK) == 0;
@ -420,6 +421,18 @@ ltsleep(__volatile const void *ident, int priority, const char *wmesg, int timo,
ktrcsw(p, 1, 0);
#endif
/*
* XXX We need to allocate the sadata_upcall structure here,
* XXX since we can't sleep while waiting for memory inside
* XXX sa_upcall(). It would be nice if we could safely
* XXX allocate the sadata_upcall structure on the stack, here.
*/
if (l->l_flag & L_SA) {
sau = sadata_upcall_alloc(0);
} else {
sau = NULL;
}
SCHED_LOCK(s);
#ifdef DIAGNOSTIC
@ -490,7 +503,7 @@ ltsleep(__volatile const void *ident, int priority, const char *wmesg, int timo,
p->p_stats->p_ru.ru_nvcsw++;
SCHED_ASSERT_LOCKED();
if (l->l_flag & L_SA)
sa_switch(l, SA_UPCALL_BLOCKED);
sa_switch(l, sau, SA_UPCALL_BLOCKED);
else
mi_switch(l, NULL);

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_time.c,v 1.93 2005/09/23 12:10:33 jmmv Exp $ */
/* $NetBSD: kern_time.c,v 1.94 2005/10/02 17:51:27 chs Exp $ */
/*-
* Copyright (c) 2000, 2004, 2005 The NetBSD Foundation, Inc.
@ -68,7 +68,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_time.c,v 1.93 2005/09/23 12:10:33 jmmv Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_time.c,v 1.94 2005/10/02 17:51:27 chs Exp $");
#include "fs_nfs.h"
#include "opt_nfs.h"
@ -102,7 +102,6 @@ __KERNEL_RCSID(0, "$NetBSD: kern_time.c,v 1.93 2005/09/23 12:10:33 jmmv Exp $");
static void timerupcall(struct lwp *, void *);
/* Time of day and interval timer support.
*
* These routines provide the kernel entry points to get and set
@ -874,7 +873,6 @@ timerupcall(struct lwp *l, void *arg)
{
struct ptimers *pt = (struct ptimers *)arg;
unsigned int i, fired, done;
extern struct pool siginfo_pool; /* XXX Ew. */
KDASSERT(l->l_proc->p_sa);
/* Bail out if we do not own the virtual processor */
@ -892,11 +890,11 @@ timerupcall(struct lwp *l, void *arg)
f = l->l_flag & L_SA;
l->l_flag &= ~L_SA;
si = pool_get(&siginfo_pool, PR_WAITOK);
si = siginfo_alloc(PR_WAITOK);
si->_info = pt->pts_timers[i]->pt_info.ksi_info;
if (sa_upcall(l, SA_UPCALL_SIGEV | SA_UPCALL_DEFER, NULL, l,
sizeof(*si), si) != 0) {
pool_put(&siginfo_pool, si);
sizeof(*si), si, siginfo_free) != 0) {
siginfo_free(si);
/* XXX What do we do here?? */
} else
done |= mask;

View File

@ -1,4 +1,4 @@
/* $NetBSD: savar.h,v 1.15 2004/03/14 01:08:47 cl Exp $ */
/* $NetBSD: savar.h,v 1.16 2005/10/02 17:51:27 chs Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -63,6 +63,7 @@ struct sadata_upcall {
int sau_type;
size_t sau_argsize;
void *sau_arg;
void (*sau_argfreefunc)(void *);
stack_t sau_stack;
union sau_state sau_event;
union sau_state sau_interrupted;
@ -131,10 +132,11 @@ struct sadata_upcall *sadata_upcall_alloc(int);
void sadata_upcall_free(struct sadata_upcall *);
void sa_release(struct proc *);
void sa_switch(struct lwp *, int);
void sa_switch(struct lwp *, struct sadata_upcall *, int);
void sa_preempt(struct lwp *);
void sa_yield(struct lwp *);
int sa_upcall(struct lwp *, int, struct lwp *, struct lwp *, size_t, void *);
int sa_upcall(struct lwp *, int, struct lwp *, struct lwp *, size_t, void *,
void (*)(void *));
void sa_putcachelwp(struct proc *, struct lwp *);
struct lwp *sa_getcachelwp(struct sadata_vp *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: signalvar.h,v 1.58 2005/09/13 01:42:51 christos Exp $ */
/* $NetBSD: signalvar.h,v 1.59 2005/10/02 17:51:27 chs Exp $ */
/*
* Copyright (c) 1991, 1993
@ -177,6 +177,8 @@ void sigactsunshare(struct proc *);
void sigactsfree(struct sigacts *);
void kpsendsig(struct lwp *, const struct ksiginfo *, const sigset_t *);
siginfo_t *siginfo_alloc(int);
void siginfo_free(void *);
int __sigtimedwait1(struct lwp *, void *, register_t *, copyinout_t,
copyinout_t, copyinout_t);