summaryrefslogtreecommitdiffstats
path: root/sys/i386/include/mptable.h
diff options
context:
space:
mode:
authormsmith <msmith@FreeBSD.org>1999-07-20 06:52:35 +0000
committermsmith <msmith@FreeBSD.org>1999-07-20 06:52:35 +0000
commit84c939ef118a545b74e42d1ab9013ea9ba8b1b3f (patch)
treef285b114a76c38187b7d9910bdede9788d00ae9e /sys/i386/include/mptable.h
parent905bcc118433dc6747bf9091a2bae04370334c34 (diff)
downloadFreeBSD-src-84c939ef118a545b74e42d1ab9013ea9ba8b1b3f.zip
FreeBSD-src-84c939ef118a545b74e42d1ab9013ea9ba8b1b3f.tar.gz
Implement an all-CPU shootdown-style rendezvous facility. This allows
the caller to specify a function to be guarded between an entry and exit barrier, as well as pre- and post-barrier functions. The primary use for this function is synchronised update of per-cpu private data. The implementation is almost (but not quite) MI; with a better mechanism for masking per-CPU interrupts it could probably be hoisted. Reviewed by: peter (partially)
Diffstat (limited to 'sys/i386/include/mptable.h')
-rw-r--r--sys/i386/include/mptable.h86
1 files changed, 85 insertions, 1 deletions
diff --git a/sys/i386/include/mptable.h b/sys/i386/include/mptable.h
index 9d8be53..e81efef 100644
--- a/sys/i386/include/mptable.h
+++ b/sys/i386/include/mptable.h
@@ -22,7 +22,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: mp_machdep.c,v 1.104 1999/06/23 21:47:22 luoqi Exp $
+ * $Id: mp_machdep.c,v 1.105 1999/06/23 23:02:38 msmith Exp $
*/
#include "opt_smp.h"
@@ -62,7 +62,10 @@
#include <machine/smp.h>
#include <machine/apic.h>
+#include <machine/atomic.h>
+#include <machine/cpufunc.h>
#include <machine/mpapic.h>
+#include <machine/psl.h>
#include <machine/segments.h>
#include <machine/smptests.h> /** TEST_DEFAULT_CONFIG, TEST_TEST1 */
#include <machine/tss.h>
@@ -591,6 +594,10 @@ mp_enable(u_int boot_addr)
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
#endif
+ /* install an inter-CPU IPI for all-CPU rendezvous */
+ setidt(XRENDEZVOUS_OFFSET, Xrendezvous,
+ SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
+
/* install an inter-CPU IPI for forcing an additional software trap */
setidt(XCPUAST_OFFSET, Xcpuast,
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
@@ -1698,6 +1705,9 @@ struct simplelock com_lock;
struct simplelock clock_lock;
#endif /* USE_CLOCKLOCK */
+/* lock around the MP rendezvous */
+static struct simplelock smp_rv_lock;
+
static void
init_locks(void)
{
@@ -1722,6 +1732,7 @@ init_locks(void)
s_lock_init((struct simplelock*)&intr_lock);
s_lock_init((struct simplelock*)&imen_lock);
s_lock_init((struct simplelock*)&cpl_lock);
+ s_lock_init(&smp_rv_lock);
#ifdef USE_COMLOCK
s_lock_init((struct simplelock*)&com_lock);
@@ -2604,3 +2615,76 @@ set_lapic_isrloc(int intr, int vector)
apic_isrbit_location[intr].bit = (1<<(vector & 31));
}
#endif
+
+/*
+ * All-CPU rendezvous. CPUs are signalled, all execute the setup function
+ * (if specified), rendezvous, execute the action function (if specified),
+ * rendezvous again, execute the teardown function (if specified), and then
+ * resume.
+ *
+ * Note that the supplied external functions _must_ be reentrant and aware
+ * that they are running in parallel and in an unknown lock context.
+ */
+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 volatile int smp_rv_waiters[2];
+
+void
+smp_rendezvous_action(void)
+{
+ /* setup function */
+ if (smp_rv_setup_func != NULL)
+ smp_rv_setup_func(smp_rv_func_arg);
+ /* spin on entry rendezvous */
+ atomic_add_int(&smp_rv_waiters[0], 1);
+ while (smp_rv_waiters[0] < mp_ncpus)
+ ;
+ /* action function */
+ if (smp_rv_action_func != NULL)
+ smp_rv_action_func(smp_rv_func_arg);
+ /* spin on exit rendezvous */
+ atomic_add_int(&smp_rv_waiters[1], 1);
+ while (smp_rv_waiters[1] < mp_ncpus)
+ ;
+ /* teardown function */
+ if (smp_rv_teardown_func != NULL)
+ smp_rv_teardown_func(smp_rv_func_arg);
+}
+
+void
+smp_rendezvous(void (* setup_func)(void *),
+ void (* action_func)(void *),
+ void (* teardown_func)(void *),
+ void *arg)
+{
+ u_int efl;
+
+ /* obtain rendezvous lock */
+ s_lock(&smp_rv_lock); /* XXX sleep here? NOWAIT flag? */
+
+ /* set static function pointers */
+ smp_rv_setup_func = setup_func;
+ smp_rv_action_func = action_func;
+ smp_rv_teardown_func = teardown_func;
+ smp_rv_func_arg = arg;
+ smp_rv_waiters[0] = 0;
+ smp_rv_waiters[1] = 0;
+
+ /* disable interrupts on this CPU, save interrupt status */
+ efl = read_eflags();
+ write_eflags(efl & ~PSL_I);
+
+ /* signal other processors, which will enter the IPI with interrupts off */
+ all_but_self_ipi(XRENDEZVOUS_OFFSET);
+
+ /* call executor function */
+ smp_rendezvous_action();
+
+ /* restore interrupt flag */
+ write_eflags(efl);
+
+ /* release lock */
+ s_unlock(&smp_rv_lock);
+}
OpenPOWER on IntegriCloud