Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 12 May 2011 09:24:50 +0000 (UTC)
From:      Andriy Gapon <avg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r221804 - user/avg/xcpu/sys/kern
Message-ID:  <201105120924.p4C9Oo4H028828@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avg
Date: Thu May 12 09:24:50 2011
New Revision: 221804
URL: http://svn.freebsd.org/changeset/base/221804

Log:
  (re-)add another rendezvous counter
  
  The problem was that if a master cpu calls rendezvous in rapid succession
  then the rendezvous object could be re-used while some slave cpus were
  still spinning on the dual-function teardown/exit counter if a teardown
  function was actually specified.
  To fix this problem use separate counters, one for teardown entry and the
  other for signaling full rendezvous completion.

Modified:
  user/avg/xcpu/sys/kern/subr_smp.c

Modified: user/avg/xcpu/sys/kern/subr_smp.c
==============================================================================
--- user/avg/xcpu/sys/kern/subr_smp.c	Thu May 12 07:44:41 2011	(r221803)
+++ user/avg/xcpu/sys/kern/subr_smp.c	Thu May 12 09:24:50 2011	(r221804)
@@ -118,7 +118,7 @@ struct smp_rendezvous_data {
 	void (*smp_rv_action_func)(void *arg);
 	void (*smp_rv_teardown_func)(void *arg);
 	void *smp_rv_func_arg;
-	volatile int smp_rv_waiters[2];
+	volatile int smp_rv_waiters[3];
 	int smp_rv_ncpus;
 };
 
@@ -439,17 +439,19 @@ smp_rendezvous_action_body(int cpu)
 	if (local_action_func != NULL)
 		local_action_func(local_func_arg);
 
-	atomic_add_int(&rv->smp_rv_waiters[1], 1);
-	if (local_teardown_func == smp_no_rendevous_barrier)
-                return;
+	if (local_teardown_func != smp_no_rendevous_barrier) {
+		/* spin on exit rendezvous */
+		atomic_add_int(&rv->smp_rv_waiters[1], 1);
+		while (rv->smp_rv_waiters[1] < ncpus)
+			cpu_spinwait();
 
-	/* spin on exit rendezvous */
-	while (rv->smp_rv_waiters[1] < ncpus)
-		cpu_spinwait();
+		atomic_add_int(&rv->smp_rv_waiters[2], 1);
 
-	/* teardown function */
-	if (local_teardown_func != NULL)
-		local_teardown_func(local_func_arg);
+		/* teardown function */
+		if (local_teardown_func != NULL)
+			local_teardown_func(local_func_arg);
+	} else
+		atomic_add_int(&rv->smp_rv_waiters[2], 1);
 }
 
 void
@@ -492,7 +494,7 @@ smp_rendezvous_wait(void)
 	rv = DPCPU_PTR(smp_rv_data);
 	ncpus = rv->smp_rv_ncpus;
 
-	while (atomic_load_acq_int(&rv->smp_rv_waiters[1]) < ncpus) {
+	while (atomic_load_acq_int(&rv->smp_rv_waiters[2]) < ncpus) {
 		/* check for incoming events */
 		if ((stopping_cpus & (1 << curcpu)) != 0)
 			cpustop_handler();
@@ -580,6 +582,7 @@ smp_rendezvous_cpus(cpumask_t map,
 	rv->smp_rv_teardown_func = teardown_func;
 	rv->smp_rv_func_arg = arg;
 	rv->smp_rv_waiters[1] = 0;
+	rv->smp_rv_waiters[2] = 0;
 	atomic_store_rel_int(&rv->smp_rv_waiters[0], 0);
 
 	/* signal other CPUs, which will enter the IPI with interrupts off */



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