Tweak change to move SA support from userret() to lwp_userret().

1) Since we want to check for upcalls only once, take LW_SA_UPCALL
out of the while(l->l_flags & LW_USERRET) loop.

2) since the goal is to keep SA code out of userret() (and especially
all the emulations that include userret() but will never do SA),
ALWAYS set LW_SA_UPCALL when we set SAVP_FLAG_NOUPCALLS. Drop the
test for it in lwp_userret() since it will never be set bare.

3) Adapt sa_upcall_userret() to clear LW_SA_UPCALL if it's no longer
needed. If we have gained upcalls since sa_yield(), we will deliver
them next time around.

Tested by skrll at.
This commit is contained in:
wrstuden 2008-10-28 22:11:36 +00:00
parent 836c38aba9
commit 04ca26c586
2 changed files with 29 additions and 8 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: compat_sa.c,v 1.5 2008/10/27 16:52:04 wrstuden Exp $ */
/* $NetBSD: compat_sa.c,v 1.6 2008/10/28 22:11:36 wrstuden Exp $ */
/*-
* Copyright (c) 2001, 2004, 2005, 2006 The NetBSD Foundation, Inc.
@ -41,7 +41,7 @@
#include "opt_ktrace.h"
#include "opt_multiprocessor.h"
#include "opt_sa.h"
__KERNEL_RCSID(0, "$NetBSD: compat_sa.c,v 1.5 2008/10/27 16:52:04 wrstuden Exp $");
__KERNEL_RCSID(0, "$NetBSD: compat_sa.c,v 1.6 2008/10/28 22:11:36 wrstuden Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -1117,6 +1117,13 @@ sa_yield(struct lwp *l)
* upcalls.
*/
vp->savp_pflags |= SAVP_FLAG_NOUPCALLS;
/*
* Now force us to call into sa_upcall_userret()
* which will clear SAVP_FLAG_NOUPCALLS
*/
lwp_lock(l);
l->l_flag |= LW_SA_UPCALL;
lwp_unlock(l);
}
}
@ -1997,11 +2004,25 @@ sa_upcall_userret(struct lwp *l)
vp = l->l_savp;
if (vp->savp_pflags & SAVP_FLAG_NOUPCALLS) {
int do_clear = 0;
/*
* We made upcalls in sa_yield() (otherwise we would
* still be in the loop there!). Don't do it again.
* Clear LW_SA_UPCALL, unless there are upcalls to deliver.
* they will get delivered next time we return to user mode.
*/
vp->savp_pflags &= ~SAVP_FLAG_NOUPCALLS;
mutex_enter(&vp->savp_mutex);
if ((vp->savp_woken_count == 0)
&& SIMPLEQ_EMPTY(&vp->savp_upcalls)) {
do_clear = 1;
}
mutex_exit(&vp->savp_mutex);
if (do_clear) {
lwp_lock(l);
l->l_flag &= ~LW_SA_UPCALL;
lwp_unlock(l);
}
DPRINTFN(7,("sa_upcall_userret(%d.%d %x) skipping processing\n",
p->p_pid, l->l_lid, l->l_flag));
return;

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_lwp.c,v 1.125 2008/10/21 11:51:23 ad Exp $ */
/* $NetBSD: kern_lwp.c,v 1.126 2008/10/28 22:11:36 wrstuden Exp $ */
/*-
* Copyright (c) 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@ -206,7 +206,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.125 2008/10/21 11:51:23 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.126 2008/10/28 22:11:36 wrstuden Exp $");
#include "opt_ddb.h"
#include "opt_lockdebug.h"
@ -1251,8 +1251,11 @@ lwp_userret(struct lwp *l)
/*
* It should be safe to do this read unlocked on a multiprocessor
* system..
*
* LW_SA_UPCALL will be handled after the while() loop, so don't
* consider it now.
*/
while ((l->l_flag & LW_USERRET) != 0) {
while ((l->l_flag & (LW_USERRET & ~(LW_SA_UPCALL))) != 0) {
/*
* Process pending signals first, unless the process
* is dumping core or exiting, where we will instead
@ -1317,9 +1320,6 @@ lwp_userret(struct lwp *l)
timerupcall(l);
if (l->l_flag & LW_SA_UPCALL)
sa_upcall_userret(l);
else if (__predict_false((l->l_savp)
&& (l->l_savp->savp_pflags & SAVP_FLAG_NOUPCALLS)))
l->l_savp->savp_pflags &= ~SAVP_FLAG_NOUPCALLS;
#endif /* KERN_SA */
}