summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2010-01-09 02:44:18 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2010-01-09 02:44:18 +0000
commitf2617840a5643c0e6a47e64f8eab71eba7f568ef (patch)
treedcc96e8830abbf49a82567913e61ad3cdac40dc4
parentaf5121682d87ee62dec06c6d60c20d8527fec470 (diff)
Add code to stop scheduling processes on CPUs, effectively halting that CPU.
Use this to do a shutdown with only the boot processor running. This should avoid nasty races during shutdown. help from art@, ok deraadt@, miod@
-rw-r--r--sys/kern/kern_sched.c17
-rw-r--r--sys/kern/kern_xxx.c25
-rw-r--r--sys/sys/sched.h4
3 files changed, 42 insertions, 4 deletions
diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c
index 58b2ab73436..7625440b7ee 100644
--- a/sys/kern/kern_sched.c
+++ b/sys/kern/kern_sched.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sched.c,v 1.16 2009/11/29 23:12:30 kettenis Exp $ */
+/* $OpenBSD: kern_sched.c,v 1.17 2010/01/09 02:44:17 kettenis Exp $ */
/*
* Copyright (c) 2007, 2008 Artur Grabowski <art@openbsd.org>
*
@@ -148,8 +148,14 @@ sched_idle(void *v)
cpuset_add(&sched_idle_cpus, ci);
cpu_idle_enter();
- while (spc->spc_whichqs == 0)
+ while (spc->spc_whichqs == 0) {
+ if (spc->spc_schedflags & SPCF_SHOULDHALT) {
+ atomic_setbits_int(&spc->spc_schedflags,
+ SPCF_HALTED);
+ wakeup(spc);
+ }
cpu_idle_cycle();
+ }
cpu_idle_leave();
cpuset_del(&sched_idle_cpus, ci);
}
@@ -246,6 +252,13 @@ sched_chooseproc(void)
SCHED_ASSERT_LOCKED();
+ if (spc->spc_schedflags & SPCF_SHOULDHALT) {
+ p = spc->spc_idleproc;
+ KASSERT(p);
+ p->p_stat = SRUN;
+ return (p);
+ }
+
again:
if (spc->spc_whichqs) {
queue = ffs(spc->spc_whichqs) - 1;
diff --git a/sys/kern/kern_xxx.c b/sys/kern/kern_xxx.c
index 654ed83dc4f..359c97541f2 100644
--- a/sys/kern/kern_xxx.c
+++ b/sys/kern/kern_xxx.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_xxx.c,v 1.14 2009/11/29 23:12:30 kettenis Exp $ */
+/* $OpenBSD: kern_xxx.c,v 1.15 2010/01/09 02:44:17 kettenis Exp $ */
/* $NetBSD: kern_xxx.c,v 1.32 1996/04/22 01:38:41 christos Exp $ */
/*
@@ -68,6 +68,29 @@ sys_reboot(struct proc *p, void *v, register_t *retval)
}
}
+ /*
+ * Make sure we stop the secondary CPUs.
+ */
+ CPU_INFO_FOREACH(cii, ci) {
+ struct schedstate_percpu *spc = &ci->ci_schedstate;
+
+ if (CPU_IS_PRIMARY(ci))
+ continue;
+ atomic_setbits_int(&spc->spc_schedflags, SPCF_SHOULDHALT);
+ }
+ CPU_INFO_FOREACH(cii, ci) {
+ struct schedstate_percpu *spc = &ci->ci_schedstate;
+ struct sleep_state sls;
+
+ if (CPU_IS_PRIMARY(ci))
+ continue;
+ while ((spc->spc_schedflags & SPCF_HALTED) == 0) {
+ sleep_setup(&sls, spc, PZERO, "schedstate");
+ sleep_finish(&sls,
+ (spc->spc_schedflags & SPCF_HALTED) == 0);
+ }
+ }
+
if_downall();
boot(SCARG(uap, opt));
diff --git a/sys/sys/sched.h b/sys/sys/sched.h
index 5e5d9297bbd..9304a631628 100644
--- a/sys/sys/sched.h
+++ b/sys/sys/sched.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sched.h,v 1.24 2009/11/29 23:12:30 kettenis Exp $ */
+/* $OpenBSD: sched.h,v 1.25 2010/01/09 02:44:17 kettenis Exp $ */
/* $NetBSD: sched.h,v 1.2 1999/02/28 18:14:58 ross Exp $ */
/*-
@@ -122,6 +122,8 @@ struct schedstate_percpu {
#define SPCF_SEENRR 0x0001 /* process has seen roundrobin() */
#define SPCF_SHOULDYIELD 0x0002 /* process should yield the CPU */
#define SPCF_SWITCHCLEAR (SPCF_SEENRR|SPCF_SHOULDYIELD)
+#define SPCF_SHOULDHALT 0x0004 /* CPU should be vacated */
+#define SPCF_HALTED 0x0008 /* CPU has been halted */
#define SCHED_PPQ (128 / SCHED_NQS) /* priorities per queue */
#define NICE_WEIGHT 2 /* priorities per nice level */