Module Name:    src
Committed By:   ad
Date:           Fri Dec  6 21:36:11 UTC 2019

Modified Files:
        src/sys/kern: kern_exec.c kern_exit.c kern_idle.c kern_lwp.c kern_sig.c
            kern_sleepq.c kern_softint.c kern_synch.c
        src/sys/sys: sched.h

Log Message:
Make it possible to call mi_switch() and immediately switch to another CPU.
This seems to take about 3us on my Intel system.  Two changes required:

- Have the caller to mi_switch() be responsible for calling spc_lock().
- Avoid using l->l_cpu in mi_switch().

While here:

- Add a couple of calls to membar_enter()
- Have the idle LWP set itself to LSIDL, to match softint_thread().
- Remove unused return value from mi_switch().


To generate a diff of this commit:
cvs rdiff -u -r1.484 -r1.485 src/sys/kern/kern_exec.c
cvs rdiff -u -r1.277 -r1.278 src/sys/kern/kern_exit.c
cvs rdiff -u -r1.27 -r1.28 src/sys/kern/kern_idle.c
cvs rdiff -u -r1.216 -r1.217 src/sys/kern/kern_lwp.c
cvs rdiff -u -r1.380 -r1.381 src/sys/kern/kern_sig.c
cvs rdiff -u -r1.53 -r1.54 src/sys/kern/kern_sleepq.c
cvs rdiff -u -r1.54 -r1.55 src/sys/kern/kern_softint.c
cvs rdiff -u -r1.328 -r1.329 src/sys/kern/kern_synch.c
cvs rdiff -u -r1.79 -r1.80 src/sys/sys/sched.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/kern_exec.c
diff -u src/sys/kern/kern_exec.c:1.484 src/sys/kern/kern_exec.c:1.485
--- src/sys/kern/kern_exec.c:1.484	Sat Nov 23 19:42:52 2019
+++ src/sys/kern/kern_exec.c	Fri Dec  6 21:36:10 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_exec.c,v 1.484 2019/11/23 19:42:52 ad Exp $	*/
+/*	$NetBSD: kern_exec.c,v 1.485 2019/12/06 21:36:10 ad Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2019 The NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.484 2019/11/23 19:42:52 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.485 2019/12/06 21:36:10 ad Exp $");
 
 #include "opt_exec.h"
 #include "opt_execfmt.h"
@@ -1363,6 +1363,7 @@ execve_runproc(struct lwp *l, struct exe
 		mutex_exit(p->p_lock);
 		mutex_exit(proc_lock);
 		lwp_lock(l);
+		spc_lock(l->l_cpu);
 		mi_switch(l);
 		ksiginfo_queue_drain(&kq);
 		KERNEL_LOCK(l->l_biglocks, l);

Index: src/sys/kern/kern_exit.c
diff -u src/sys/kern/kern_exit.c:1.277 src/sys/kern/kern_exit.c:1.278
--- src/sys/kern/kern_exit.c:1.277	Thu Oct  3 22:48:44 2019
+++ src/sys/kern/kern_exit.c	Fri Dec  6 21:36:10 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_exit.c,v 1.277 2019/10/03 22:48:44 kamil Exp $	*/
+/*	$NetBSD: kern_exit.c,v 1.278 2019/12/06 21:36:10 ad Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.277 2019/10/03 22:48:44 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.278 2019/12/06 21:36:10 ad Exp $");
 
 #include "opt_ktrace.h"
 #include "opt_dtrace.h"
@@ -245,6 +245,7 @@ exit1(struct lwp *l, int exitcode, int s
 		lwp_unlock(l);
 		mutex_exit(p->p_lock);
 		lwp_lock(l);
+		spc_lock(l->l_cpu);
 		mi_switch(l);
 		KERNEL_LOCK(l->l_biglocks, l);
 		mutex_enter(p->p_lock);

Index: src/sys/kern/kern_idle.c
diff -u src/sys/kern/kern_idle.c:1.27 src/sys/kern/kern_idle.c:1.28
--- src/sys/kern/kern_idle.c:1.27	Sun Dec  1 15:34:46 2019
+++ src/sys/kern/kern_idle.c	Fri Dec  6 21:36:10 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_idle.c,v 1.27 2019/12/01 15:34:46 ad Exp $	*/
+/*	$NetBSD: kern_idle.c,v 1.28 2019/12/06 21:36:10 ad Exp $	*/
 
 /*-
  * Copyright (c)2002, 2006, 2007 YAMAMOTO Takashi,
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(0, "$NetBSD: kern_idle.c,v 1.27 2019/12/01 15:34:46 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_idle.c,v 1.28 2019/12/06 21:36:10 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/cpu.h>
@@ -93,6 +93,8 @@ idle_loop(void *dummy)
 		}
 		KASSERT(l->l_mutex == l->l_cpu->ci_schedstate.spc_lwplock);
 		lwp_lock(l);
+		l->l_stat = LSIDL;
+		spc_lock(l->l_cpu);
 		mi_switch(l);
 		KASSERT(curlwp == l);
 		KASSERT(l->l_stat == LSONPROC);

Index: src/sys/kern/kern_lwp.c
diff -u src/sys/kern/kern_lwp.c:1.216 src/sys/kern/kern_lwp.c:1.217
--- src/sys/kern/kern_lwp.c:1.216	Tue Dec  3 05:07:48 2019
+++ src/sys/kern/kern_lwp.c	Fri Dec  6 21:36:10 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_lwp.c,v 1.216 2019/12/03 05:07:48 riastradh Exp $	*/
+/*	$NetBSD: kern_lwp.c,v 1.217 2019/12/06 21:36:10 ad Exp $	*/
 
 /*-
  * Copyright (c) 2001, 2006, 2007, 2008, 2009, 2019 The NetBSD Foundation, Inc.
@@ -209,7 +209,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.216 2019/12/03 05:07:48 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.217 2019/12/06 21:36:10 ad Exp $");
 
 #include "opt_ddb.h"
 #include "opt_lockdebug.h"
@@ -1602,6 +1602,7 @@ lwp_userret(struct lwp *l)
 			lwp_unlock(l);
 			mutex_exit(p->p_lock);
 			lwp_lock(l);
+			spc_lock(l->l_cpu);
 			mi_switch(l);
 		}
 

Index: src/sys/kern/kern_sig.c
diff -u src/sys/kern/kern_sig.c:1.380 src/sys/kern/kern_sig.c:1.381
--- src/sys/kern/kern_sig.c:1.380	Thu Nov 21 18:17:36 2019
+++ src/sys/kern/kern_sig.c	Fri Dec  6 21:36:10 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_sig.c,v 1.380 2019/11/21 18:17:36 ad Exp $	*/
+/*	$NetBSD: kern_sig.c,v 1.381 2019/12/06 21:36:10 ad Exp $	*/
 
 /*-
  * Copyright (c) 2006, 2007, 2008, 2019 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.380 2019/11/21 18:17:36 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.381 2019/12/06 21:36:10 ad Exp $");
 
 #include "opt_ptrace.h"
 #include "opt_dtrace.h"
@@ -1771,6 +1771,7 @@ sigswitch_unlock_and_switch_away(struct 
 
 	mutex_exit(p->p_lock);
 	lwp_lock(l);
+	spc_lock(l->l_cpu);
 	mi_switch(l);
 	KERNEL_LOCK(biglocks, l);
 }

Index: src/sys/kern/kern_sleepq.c
diff -u src/sys/kern/kern_sleepq.c:1.53 src/sys/kern/kern_sleepq.c:1.54
--- src/sys/kern/kern_sleepq.c:1.53	Sat Nov 23 19:42:52 2019
+++ src/sys/kern/kern_sleepq.c	Fri Dec  6 21:36:10 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_sleepq.c,v 1.53 2019/11/23 19:42:52 ad Exp $	*/
+/*	$NetBSD: kern_sleepq.c,v 1.54 2019/12/06 21:36:10 ad Exp $	*/
 
 /*-
  * Copyright (c) 2006, 2007, 2008, 2009, 2019 The NetBSD Foundation, Inc.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_sleepq.c,v 1.53 2019/11/23 19:42:52 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_sleepq.c,v 1.54 2019/12/06 21:36:10 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -260,6 +260,7 @@ sleepq_block(int timo, bool catch_p)
 		if (timo) {
 			callout_schedule(&l->l_timeout_ch, timo);
 		}
+		spc_lock(l->l_cpu);
 		mi_switch(l);
 
 		/* The LWP and sleep queue are now unlocked. */

Index: src/sys/kern/kern_softint.c
diff -u src/sys/kern/kern_softint.c:1.54 src/sys/kern/kern_softint.c:1.55
--- src/sys/kern/kern_softint.c:1.54	Fri Dec  6 18:15:57 2019
+++ src/sys/kern/kern_softint.c	Fri Dec  6 21:36:10 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_softint.c,v 1.54 2019/12/06 18:15:57 ad Exp $	*/
+/*	$NetBSD: kern_softint.c,v 1.55 2019/12/06 21:36:10 ad Exp $	*/
 
 /*-
  * Copyright (c) 2007, 2008, 2019 The NetBSD Foundation, Inc.
@@ -170,7 +170,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_softint.c,v 1.54 2019/12/06 18:15:57 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_softint.c,v 1.55 2019/12/06 21:36:10 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -729,6 +729,7 @@ softint_thread(void *cookie)
 
 		lwp_lock(l);
 		l->l_stat = LSIDL;
+		spc_lock(l->l_cpu);
 		mi_switch(l);
 	}
 }

Index: src/sys/kern/kern_synch.c
diff -u src/sys/kern/kern_synch.c:1.328 src/sys/kern/kern_synch.c:1.329
--- src/sys/kern/kern_synch.c:1.328	Tue Dec  3 05:07:48 2019
+++ src/sys/kern/kern_synch.c	Fri Dec  6 21:36:10 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_synch.c,v 1.328 2019/12/03 05:07:48 riastradh Exp $	*/
+/*	$NetBSD: kern_synch.c,v 1.329 2019/12/06 21:36:10 ad Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2004, 2006, 2007, 2008, 2009, 2019
@@ -69,7 +69,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_synch.c,v 1.328 2019/12/03 05:07:48 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_synch.c,v 1.329 2019/12/06 21:36:10 ad Exp $");
 
 #include "opt_kstack.h"
 #include "opt_dtrace.h"
@@ -269,11 +269,14 @@ yield(void)
 
 	KERNEL_UNLOCK_ALL(l, &l->l_biglocks);
 	lwp_lock(l);
+
 	KASSERT(lwp_locked(l, l->l_cpu->ci_schedstate.spc_lwplock));
 	KASSERT(l->l_stat == LSONPROC);
+
 	/* Voluntary - ditch kpriority boost. */
 	l->l_kpriority = false;
-	(void)mi_switch(l);
+	spc_lock(l->l_cpu);
+	mi_switch(l);
 	KERNEL_LOCK(l->l_biglocks, l);
 }
 
@@ -288,11 +291,14 @@ preempt(void)
 
 	KERNEL_UNLOCK_ALL(l, &l->l_biglocks);
 	lwp_lock(l);
+
 	KASSERT(lwp_locked(l, l->l_cpu->ci_schedstate.spc_lwplock));
 	KASSERT(l->l_stat == LSONPROC);
+
 	/* Involuntary - keep kpriority boost. */
 	l->l_pflag |= LP_PREEMPTING;
-	(void)mi_switch(l);
+	spc_lock(l->l_cpu);
+	mi_switch(l);
 	KERNEL_LOCK(l->l_biglocks, l);
 }
 
@@ -372,7 +378,9 @@ kpreempt(uintptr_t where)
 			kpreempt_ev_immed.ev_count++;
 		}
 		lwp_lock(l);
+		/* Involuntary - keep kpriority boost. */
 		l->l_pflag |= LP_PREEMPTING;
+		spc_lock(l->l_cpu);
 		mi_switch(l);
 		l->l_nopreempt++;
 		splx(s);
@@ -501,20 +509,22 @@ nextlwp(struct cpu_info *ci, struct sche
 /*
  * The machine independent parts of context switch.
  *
- * Returns 1 if another LWP was actually run.
+ * NOTE: do not use l->l_cpu in this routine.  The caller may have enqueued
+ * itself onto another CPU's run queue, so l->l_cpu may point elsewhere.
  */
-int
+void
 mi_switch(lwp_t *l)
 {
 	struct cpu_info *ci;
 	struct schedstate_percpu *spc;
 	struct lwp *newl;
-	int retval, oldspl;
+	int oldspl;
 	struct bintime bt;
 	bool returning;
 
 	KASSERT(lwp_locked(l, NULL));
 	KASSERT(kpreempt_disabled());
+	KASSERT(mutex_owned(curcpu()->ci_schedstate.spc_mutex));
 	LOCKDEBUG_BARRIER(l->l_mutex, 1);
 
 	kstack_check_magic(l);
@@ -523,8 +533,8 @@ mi_switch(lwp_t *l)
 
 	KASSERTMSG(l == curlwp, "l %p curlwp %p", l, curlwp);
 	KASSERT((l->l_pflag & LP_RUNNING) != 0);
-	KASSERT(l->l_cpu == curcpu());
-	ci = l->l_cpu;
+	KASSERT(l->l_cpu == curcpu() || l->l_stat == LSRUN);
+	ci = curcpu();
 	spc = &ci->ci_schedstate;
 	returning = false;
 	newl = NULL;
@@ -555,31 +565,24 @@ mi_switch(lwp_t *l)
 	}
 #endif	/* !__HAVE_FAST_SOFTINTS */
 
-	/* Lock the runqueue */
-	KASSERT(l->l_stat != LSRUN);
-	mutex_spin_enter(spc->spc_mutex);
-
 	/*
 	 * If on the CPU and we have gotten this far, then we must yield.
 	 */
 	if (l->l_stat == LSONPROC && l != newl) {
 		KASSERT(lwp_locked(l, spc->spc_lwplock));
-		if ((l->l_flag & LW_IDLE) == 0) {
-			l->l_stat = LSRUN;
-			lwp_setlock(l, spc->spc_mutex);
-			sched_enqueue(l);
-			/*
-			 * Handle migration.  Note that "migrating LWP" may
-			 * be reset here, if interrupt/preemption happens
-			 * early in idle LWP.
-			 */
-			if (l->l_target_cpu != NULL &&
-			    (l->l_pflag & LP_BOUND) == 0) {
-				KASSERT((l->l_pflag & LP_INTR) == 0);
-				spc->spc_migrating = l;
-			}
-		} else
-			l->l_stat = LSIDL;
+		KASSERT((l->l_flag & LW_IDLE) == 0);
+		l->l_stat = LSRUN;
+		lwp_setlock(l, spc->spc_mutex);
+		sched_enqueue(l);
+		/*
+		 * Handle migration.  Note that "migrating LWP" may
+		 * be reset here, if interrupt/preemption happens
+		 * early in idle LWP.
+		 */
+		if (l->l_target_cpu != NULL && (l->l_pflag & LP_BOUND) == 0) {
+			KASSERT((l->l_pflag & LP_INTR) == 0);
+			spc->spc_migrating = l;
+		}
 	}
 
 	/* Pick new LWP to run. */
@@ -694,6 +697,7 @@ mi_switch(lwp_t *l)
 			while (newl->l_ctxswtch)
 				SPINLOCK_BACKOFF(count);
 		}
+		membar_enter();
 
 		/*
 		 * If DTrace has set the active vtime enum to anything
@@ -743,28 +747,25 @@ mi_switch(lwp_t *l)
 			l->l_lwpctl->lc_pctr++;
 		}
 
-		KASSERT(l->l_cpu == ci);
-		splx(oldspl);
 		/*
-		 * note that, unless the caller disabled preemption,
-		 * we can be preempted at any time after the above splx() call.
+		 * Note that, unless the caller disabled preemption, we can
+		 * be preempted at any time after this splx().
 		 */
-		retval = 1;
+		splx(oldspl);
 	} else {
 		/* Nothing to do - just unlock and return. */
 		mutex_spin_exit(spc->spc_mutex);
 		l->l_pflag &= ~LP_PREEMPTING;
 		lwp_unlock(l);
-		retval = 0;
 	}
 
+	/* Only now is it safe to consider l_cpu again. */
 	KASSERT(l == curlwp);
+	KASSERT(l->l_cpu == ci);
 	KASSERT(l->l_stat == LSONPROC);
 
 	SYSCALL_TIME_WAKEUP(l);
 	LOCKDEBUG_BARRIER(NULL, 1);
-
-	return retval;
 }
 
 /*
@@ -848,6 +849,7 @@ lwp_exit_switchaway(lwp_t *l)
 		while (newl->l_ctxswtch)
 			SPINLOCK_BACKOFF(count);
 	}
+	membar_enter();
 
 	/*
 	 * If DTrace has set the active vtime enum to anything

Index: src/sys/sys/sched.h
diff -u src/sys/sys/sched.h:1.79 src/sys/sys/sched.h:1.80
--- src/sys/sys/sched.h:1.79	Tue Dec  3 22:28:41 2019
+++ src/sys/sys/sched.h	Fri Dec  6 21:36:10 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: sched.h,v 1.79 2019/12/03 22:28:41 ad Exp $	*/
+/*	$NetBSD: sched.h,v 1.80 2019/12/06 21:36:10 ad Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2007, 2008, 2019
@@ -266,7 +266,7 @@ void		sched_print_runqueue(void (*pr)(co
 bool		kpreempt(uintptr_t);
 void		preempt(void);
 void		yield(void);
-int		mi_switch(struct lwp *);
+void		mi_switch(struct lwp *);
 void		updatertime(lwp_t *, const struct bintime *);
 void		sched_idle(void);
 void		suspendsched(void);

Reply via email to