tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: percpu_foreach() does not execute remotely
> On Jan 28, 2020, at 9:20 AM, Taylor R Campbell <campbell+netbsd-tech-kern%mumble.net@localhost> wrote:
>
> OK, that sounds reasonable. (I misunderstood your first message to
> mean that percpu_foreach_xcall would synchronize with _other activity_
> on each CPU, rather than that it would serialize the xcall with itself
> on different CPUs.)
Something like this. I haven't tested this yet, but I will shortly. Only high-pri xcalls are supported in this -- to make low-pri xcalls work, you'd need to change how percpu_cpu_swap() interlocks with percpu_foreach(). High-pri doesn't need to take the percpu_swap_lock because percpu_cpu_swap() protects its critical section with splhigh().
Index: kern/subr_percpu.c
===================================================================
RCS file: /cvsroot/src/sys/kern/subr_percpu.c,v
retrieving revision 1.20
diff -u -p -r1.20 subr_percpu.c
--- kern/subr_percpu.c 5 Dec 2019 03:21:08 -0000 1.20
+++ kern/subr_percpu.c 29 Jan 2020 02:50:48 -0000
@@ -350,7 +350,9 @@ percpu_getptr_remote(percpu_t *pc, struc
/*
* percpu_foreach: call the specified callback function for each cpus.
*
- * => called in thread context.
+ * => must be called from thread context.
+ * => callback executes on **current** CPU (or, really, arbitrary CPU,
+ * in case of preemption)
* => caller should not rely on the cpu iteration order.
* => the callback function should be minimum because it is executed with
* holding a global lock, which can block low-priority xcalls.
@@ -368,3 +370,71 @@ percpu_foreach(percpu_t *pc, percpu_call
}
percpu_traverse_exit();
}
+
+struct percpu_xcall_ctx {
+ percpu_t *ctx_pc;
+ percpu_callback_t ctx_cb;
+ void *ctx_arg;
+};
+
+static void
+percpu_xcfunc(void * const v1, void * const v2 __unused)
+{
+ struct percpu_xcall_ctx * const ctx = v1;
+ struct cpu_info * const ci = curcpu();
+
+ /*
+ * We are running at the ipl specified in the call to
+ * percpu_foreach_xcall(). The callback can raise ipl
+ * if needed to serialize with hard interrupts.
+ */
+ (*ctx->ctx_cb)(percpu_getptr_remote(ctx->ctx_pc, ci), ctx->ctx_arg, ci);
+}
+
+/*
+ * percpu_foreach_xcall: call the specified callback function for each
+ * cpu. This version uses an xcall to run the callback on each cpu.
+ *
+ * => must be called from thread context.
+ * => callback executes on **remote** CPU in soft-interrupt context
+ * (at the specified soft interrupt priority).
+ * => caller should not rely on the cpu iteration order.
+ * => the callback function should be minimum because it is executed
+ * in soft-interrupt context. eg. it's illegal for a callback
+ * function to sleep for memory allocation.
+ */
+void
+percpu_foreach_xcall(percpu_t *pc, int ipl, percpu_callback_t cb, void *arg)
+{
+ struct percpu_xcall_ctx ctx = {
+ .ctx_pc = pc,
+ .ctx_cb = cb,
+ .ctx_arg = arg,
+ };
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+ uint64_t ticket;
+
+ /* don't use a switch statement, because there might be duplicates. */
+ KASSERT(ipl == IPL_SOFTSERIAL || ipl == IPL_SOFTNET ||
+ ipl == IPL_SOFTBIO || ipl == IPL_SOFTCLOCK);
+
+ /*
+ * We iterate manually and xc_unicast rather than xc_broadcast in
+ * order to to serialize the access to the callback argument.
+ *
+ * We do not take the percpu_swap_lock because percpu_cpu_swap()
+ * goes to splhigh during the critical section, thus serializing
+ * against our xcall softint.
+ *
+ * XXX We could use xc_broadcast and serialize invoking the
+ * callback using a spin mutex, but that seems like it would
+ * hog the xcall mechanism. This way at least allows others
+ * to sneak in and make progress while we do our work.
+ */
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ ticket = xc_unicast(XC_HIGHPRI_IPL(ipl),
+ percpu_xcfunc, &ctx, NULL, ci);
+ xc_wait(ticket);
+ }
+}
Index: sys/percpu.h
===================================================================
RCS file: /cvsroot/src/sys/sys/percpu.h,v
retrieving revision 1.3
diff -u -p -r1.3 percpu.h
--- sys/percpu.h 9 Apr 2008 05:11:20 -0000 1.3
+++ sys/percpu.h 29 Jan 2020 02:50:48 -0000
@@ -40,6 +40,7 @@ void percpu_putref(percpu_t *);
typedef void (*percpu_callback_t)(void *, void *, struct cpu_info *);
void percpu_foreach(percpu_t *, percpu_callback_t, void *);
+void percpu_foreach_xcall(percpu_t *, int, percpu_callback_t, void *);
/* low-level api; don't use unless necessary */
void percpu_traverse_enter(void);
-- thorpej
Home |
Main Index |
Thread Index |
Old Index