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>