Added API to run a function in multiple CPUs, and wait for completion
authorDavide Libenzi <dlibenzi@google.com>
Mon, 16 Nov 2015 19:14:52 +0000 (11:14 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 24 Nov 2015 20:38:22 +0000 (15:38 -0500)
Added API to run a function in multiple CPUs, and wait for completion.

Signed-off-by: Davide Libenzi <dlibenzi@google.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/smp.h
kern/src/smp.c

index d4a4940..3d4fe95 100644 (file)
@@ -17,6 +17,7 @@
 #include <syscall.h>
 #include <alarm.h>
 #include <trace.h>
+#include <core_set.h>
 
 #define CPU_STATE_IRQ                  0
 #define CPU_STATE_KERNEL               1
@@ -154,6 +155,9 @@ struct pcpu_trace_event {
 
 #endif /* CONFIG_TRACE_LOCKS */
 
+void smp_do_in_cores(const struct core_set *cset, void (*func)(void *),
+                                        void *opaque);
+
 /* Run the handlers for all events in a pcpui ring.  Can run on all cores, or
  * just one core.  'type' selects which event type is handled (0 for all). */
 void pcpui_tr_foreach(int coreid, int type);
index aedd7ea..e30a7f4 100644 (file)
 #include <trace.h>
 #include <kdebug.h>
 #include <kmalloc.h>
+#include <core_set.h>
+#include <completion.h>
+
+struct all_cpu_work {
+       struct completion comp;
+       void (*func)(void *);
+       void *opaque;
+};
 
 struct per_cpu_info per_cpu_info[MAX_NUM_CORES];
 
@@ -239,3 +247,34 @@ void pcpui_tr_reset_and_clear_all(void)
        for (int i = 0; i < num_cores; i++)
                trace_ring_reset_and_clear(&per_cpu_info[i].traces);
 }
+
+static void smp_do_core_work(uint32_t srcid, long a0, long a1, long a2)
+{
+       struct all_cpu_work *acw = (struct all_cpu_work *) a0;
+
+       acw->func(acw->opaque);
+       completion_complete(&acw->comp, 1);
+}
+
+void smp_do_in_cores(const struct core_set *cset, void (*func)(void *),
+                                        void *opaque)
+{
+       int cpu = core_id();
+       struct all_cpu_work acw;
+
+       memset(&acw, 0, sizeof(acw));
+       completion_init(&acw.comp, core_set_remote_count(cset));
+       acw.func = func;
+       acw.opaque = opaque;
+
+       for (int i = 0; i < num_cores; i++) {
+               if (core_set_getcpu(cset, i)) {
+                       if (i == cpu)
+                               func(opaque);
+                       else
+                               send_kernel_message(i, smp_do_core_work, (long) &acw, 0, 0,
+                                                                       KMSG_ROUTINE);
+               }
+       }
+       completion_wait(&acw.comp);
+}