commit ee4c68e21f83ddd8b40d058a8caf16cd1381760e Author: Andriy Gapon Date: Mon May 9 00:08:44 2011 +0300 change generic_stop_cpus to use the same approach as hard_stop_cpus diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index 35c8a14..7125c75 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -1410,6 +1410,10 @@ cpustop_handler(void) cpu = PCPU_GET(cpuid); + /* Just return if this is a belated NMI */ + if (!CPU_ISSET(cpu, &stopping_cpus)) + return; + savectx(&stoppcbs[cpu]); /* Indicate that we are stopped */ diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c index 607c0ef..1ba7f08 100644 --- a/sys/i386/i386/mp_machdep.c +++ b/sys/i386/i386/mp_machdep.c @@ -1509,6 +1509,10 @@ cpustop_handler(void) cpu = PCPU_GET(cpuid); + /* Just return if this is a belated NMI */ + if (!CPU_ISSET(cpu, &stopping_cpus)) + return; + savectx(&stoppcbs[cpu]); /* Indicate that we are stopped */ diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c index 288ee4a..1046c9b 100644 --- a/sys/kern/subr_smp.c +++ b/sys/kern/subr_smp.c @@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$"); volatile cpuset_t stopped_cpus; volatile cpuset_t started_cpus; volatile cpuset_t suspended_cpus; +volatile cpuset_t stopping_cpus; volatile cpuset_t hard_stopped_cpus; volatile cpuset_t hard_started_cpus; volatile cpuset_t hard_stopping_cpus; @@ -209,7 +210,8 @@ generic_stop_cpus(cpuset_t map, u_int type) #ifdef KTR char cpusetbuf[CPUSETBUFSIZ]; #endif - static volatile u_int stopping_cpu = NOCPU; + static volatile u_int stopper_cpu = NOCPU; + int cpu; int i; volatile cpuset_t *cpus; @@ -227,13 +229,28 @@ generic_stop_cpus(cpuset_t map, u_int type) CTR2(KTR_SMP, "stop_cpus(%s) with %u type", cpusetobj_strprint(cpusetbuf, &map), type); - if (stopping_cpu != PCPU_GET(cpuid)) - while (atomic_cmpset_int(&stopping_cpu, NOCPU, - PCPU_GET(cpuid)) == 0) - while (stopping_cpu != NOCPU) - cpu_spinwait(); /* spin */ + /* Ensure non-preemtable context, just in case. */ + spinlock_enter(); + + cpu = PCPU_GET(cpuid); + + if (cpu != stopper_cpu) { + while (atomic_cmpset_int(&stopper_cpu, NOCPU, cpu) == 0) + while (stopper_cpu != NOCPU) { + if (CPU_ISSET(cpu, &stopping_cpus)) + cpustop_handler(); + else + cpu_spinwait(); + } + } else { + /* + * Recursion here is not expected. + */ + panic("cpu stop recursion\n"); + } /* send the stop IPI to all CPUs in map */ + stopping_cpus = map; ipi_selected(map, type); #if defined(__amd64__) || defined(__i386__) @@ -254,7 +271,8 @@ generic_stop_cpus(cpuset_t map, u_int type) } } - stopping_cpu = NOCPU; + stopper_cpu = NOCPU; + spinlock_exit(); return (1); } diff --git a/sys/sys/smp.h b/sys/sys/smp.h index 267dafb..a9c37e4 100644 --- a/sys/sys/smp.h +++ b/sys/sys/smp.h @@ -76,6 +76,7 @@ extern int smp_cpus; extern volatile cpuset_t started_cpus; extern volatile cpuset_t stopped_cpus; extern volatile cpuset_t suspended_cpus; +extern volatile cpuset_t stopping_cpus; extern volatile cpuset_t hard_started_cpus; extern volatile cpuset_t hard_stopped_cpus; extern volatile cpuset_t hard_stopping_cpus;