Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 15 Sep 2011 10:51:31 +0000 (UTC)
From:      Andriy Gapon <avg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r225580 - stable/8/sys/kern
Message-ID:  <201109151051.p8FApV79070329@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avg
Date: Thu Sep 15 10:51:31 2011
New Revision: 225580
URL: http://svn.freebsd.org/changeset/base/225580

Log:
  MFC r213736: generic_stop_cpus: prevent parallel execution
  
  Addendum to the original commit message:
  This is mostly useful to protect kdb_trap() from concurrent entry as it
  doesn't have any protection like e.g. panic(9) has.  Even if kdb_trap()
  had that protection there would still be a need for protection
  between concurrect panic() and kdb_trap() entries.  That protection
  could be implemented externally, but doing it in generic_stop_cpus()
  seems to be OK as well (stopping CPUs on panic is in the works).

Modified:
  stable/8/sys/kern/subr_smp.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/kern/subr_smp.c
==============================================================================
--- stable/8/sys/kern/subr_smp.c	Thu Sep 15 10:42:55 2011	(r225579)
+++ stable/8/sys/kern/subr_smp.c	Thu Sep 15 10:51:31 2011	(r225580)
@@ -198,22 +198,32 @@ forward_signal(struct thread *td)
  *   0: NA
  *   1: ok
  *
- * XXX FIXME: this is not MP-safe, needs a lock to prevent multiple CPUs
- *            from executing at same time.
  */
 static int
 generic_stop_cpus(cpumask_t map, u_int type)
 {
+	static volatile u_int stopping_cpu = NOCPU;
 	int i;
 
-	KASSERT(type == IPI_STOP || type == IPI_STOP_HARD,
+	KASSERT(
+#if defined(__amd64__)
+	    type == IPI_STOP || type == IPI_STOP_HARD || type == IPI_SUSPEND,
+#else
+	    type == IPI_STOP || type == IPI_STOP_HARD,
+#endif
 	    ("%s: invalid stop type", __func__));
 
 	if (!smp_started)
-		return 0;
+		return (0);
 
 	CTR2(KTR_SMP, "stop_cpus(%x) with %u type", 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 */
+
 	/* send the stop IPI to all CPUs in map */
 	ipi_selected(map, type);
 
@@ -230,7 +240,8 @@ generic_stop_cpus(cpumask_t map, u_int t
 #endif
 	}
 
-	return 1;
+	stopping_cpu = NOCPU;
+	return (1);
 }
 
 int
@@ -248,50 +259,11 @@ stop_cpus_hard(cpumask_t map)
 }
 
 #if defined(__amd64__)
-/*
- * When called the executing CPU will send an IPI to all other CPUs
- *  requesting that they halt execution.
- *
- * Usually (but not necessarily) called with 'other_cpus' as its arg.
- *
- *  - Signals all CPUs in map to suspend.
- *  - Waits for each to suspend.
- *
- * Returns:
- *  -1: error
- *   0: NA
- *   1: ok
- *
- * XXX FIXME: this is not MP-safe, needs a lock to prevent multiple CPUs
- *            from executing at same time.
- */
 int
 suspend_cpus(cpumask_t map)
 {
-	int i;
 
-	if (!smp_started)
-		return (0);
-
-	CTR1(KTR_SMP, "suspend_cpus(%x)", map);
-
-	/* send the suspend IPI to all CPUs in map */
-	ipi_selected(map, IPI_SUSPEND);
-
-	i = 0;
-	while ((stopped_cpus & map) != map) {
-		/* spin */
-		cpu_spinwait();
-		i++;
-#ifdef DIAGNOSTIC
-		if (i == 100000) {
-			printf("timeout suspending cpus\n");
-			break;
-		}
-#endif
-	}
-
-	return (1);
+	return (generic_stop_cpus(map, IPI_SUSPEND));
 }
 #endif
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201109151051.p8FApV79070329>