summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_smp.c
diff options
context:
space:
mode:
authorups <ups@FreeBSD.org>2007-11-08 14:47:55 +0000
committerups <ups@FreeBSD.org>2007-11-08 14:47:55 +0000
commit9c75ede409d60f494cbb4b5c953e103ca672a0df (patch)
treee657852bc96f8f77553f7abb0596889a6b8d5e00 /sys/kern/subr_smp.c
parent6d7755ffed75007fcc52c6aa8ee3347a280b4706 (diff)
downloadFreeBSD-src-9c75ede409d60f494cbb4b5c953e103ca672a0df.zip
FreeBSD-src-9c75ede409d60f494cbb4b5c953e103ca672a0df.tar.gz
Initial checkin for rmlock (read mostly lock) a multi reader single writer
lock optimized for almost exclusive reader access. (see also rmlock.9) TODO: Convert to per cpu variables linkerset as soon as it is available. Optimize UP (single processor) case.
Diffstat (limited to 'sys/kern/subr_smp.c')
-rw-r--r--sys/kern/subr_smp.c53
1 files changed, 37 insertions, 16 deletions
diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c
index a884288..bc30b2a 100644
--- a/sys/kern/subr_smp.c
+++ b/sys/kern/subr_smp.c
@@ -104,10 +104,10 @@ SYSCTL_INT(_kern_smp, OID_AUTO, forward_roundrobin_enabled, CTLFLAG_RW,
"Forwarding of roundrobin to all other CPUs");
/* Variables needed for SMP rendezvous. */
-static void (*smp_rv_setup_func)(void *arg);
-static void (*smp_rv_action_func)(void *arg);
-static void (*smp_rv_teardown_func)(void *arg);
-static void *smp_rv_func_arg;
+static void (*volatile smp_rv_setup_func)(void *arg);
+static void (*volatile smp_rv_action_func)(void *arg);
+static void (* volatile smp_rv_teardown_func)(void *arg);
+static void * volatile smp_rv_func_arg;
static volatile int smp_rv_waiters[3];
/*
@@ -286,6 +286,13 @@ restart_cpus(cpumask_t map)
return 1;
}
+void smp_no_rendevous_barrier(void *dummy)
+{
+#ifdef SMP
+ KASSERT((!smp_started),("smp_no_rendevous called and smp is started"));
+#endif
+}
+
/*
* All-CPU rendezvous. CPUs are signalled, all execute the setup function
* (if specified), rendezvous, execute the action function (if specified),
@@ -298,33 +305,41 @@ restart_cpus(cpumask_t map)
void
smp_rendezvous_action(void)
{
-
+ void* local_func_arg = smp_rv_func_arg;
+ void (*local_setup_func)(void*) = smp_rv_setup_func;
+ void (*local_action_func)(void*) = smp_rv_action_func;
+ void (*local_teardown_func)(void*) = smp_rv_teardown_func;
+
/* Ensure we have up-to-date values. */
atomic_add_acq_int(&smp_rv_waiters[0], 1);
while (smp_rv_waiters[0] < mp_ncpus)
cpu_spinwait();
/* setup function */
- if (smp_rv_setup_func != NULL)
- smp_rv_setup_func(smp_rv_func_arg);
+ if (local_setup_func != smp_no_rendevous_barrier) {
+ if (smp_rv_setup_func != NULL)
+ smp_rv_setup_func(smp_rv_func_arg);
+ /* spin on entry rendezvous */
+ atomic_add_int(&smp_rv_waiters[1], 1);
+ while (smp_rv_waiters[1] < mp_ncpus)
+ cpu_spinwait();
+ }
- /* spin on entry rendezvous */
- atomic_add_int(&smp_rv_waiters[1], 1);
- while (smp_rv_waiters[1] < mp_ncpus)
- cpu_spinwait();
/* action function */
- if (smp_rv_action_func != NULL)
- smp_rv_action_func(smp_rv_func_arg);
+ if (local_action_func != NULL)
+ local_action_func(local_func_arg);
+
/* spin on exit rendezvous */
atomic_add_int(&smp_rv_waiters[2], 1);
+ if (local_teardown_func == smp_no_rendevous_barrier)
+ return;
while (smp_rv_waiters[2] < mp_ncpus)
cpu_spinwait();
-
/* teardown function */
- if (smp_rv_teardown_func != NULL)
- smp_rv_teardown_func(smp_rv_func_arg);
+ if (local_teardown_func != NULL)
+ local_teardown_func(local_func_arg);
}
void
@@ -356,12 +371,18 @@ smp_rendezvous(void (* setup_func)(void *),
smp_rv_waiters[2] = 0;
atomic_store_rel_int(&smp_rv_waiters[0], 0);
+
+
/* signal other processors, which will enter the IPI with interrupts off */
ipi_all_but_self(IPI_RENDEZVOUS);
/* call executor function */
smp_rendezvous_action();
+ if (teardown_func == smp_no_rendevous_barrier) {
+ while (atomic_load_acq_int(&smp_rv_waiters[2]) < mp_ncpus)
+ cpu_spinwait();
+ }
/* release lock */
mtx_unlock_spin(&smp_ipi_mtx);
}
OpenPOWER on IntegriCloud