diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-01-09 02:44:18 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-01-09 02:44:18 +0000 |
commit | f2617840a5643c0e6a47e64f8eab71eba7f568ef (patch) | |
tree | dcc96e8830abbf49a82567913e61ad3cdac40dc4 | |
parent | af5121682d87ee62dec06c6d60c20d8527fec470 (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.c | 17 | ||||
-rw-r--r-- | sys/kern/kern_xxx.c | 25 | ||||
-rw-r--r-- | sys/sys/sched.h | 4 |
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 */ |