Proposal using RCU for callbacks
Konstantin Ananyev
konstantin.v.ananyev at yandex.ru
Thu Oct 22 09:38:13 CEST 2026
> On Wed, 21 Oct 2026 12:51:11 +0100
> Konstantin Ananyev <konstantin.v.ananyev at yandex.ru> wrote:
>
>> In particular, regarding membarrier() - consider using it for BPF CBs
>> instead of smb_mb, but decided not to. The main reasons:
>> - with membarrier() - all threads in the process will be affected.
>> Also, AFAIK it is implemented via IPI - which is quite heavy.
>> - current smp_mb (at least on modern x86_64) is quite fast
>> (it uses lock-ed instruction on thread's stack, and last time I measured it,
>> takes ¬30-50 cycles). As we usually doing it for a bulk (32+) of packets,
>> the overhead is quite small: 1-1.5 cycle per packet.
>>
>> But again, if you have some smart ideas how to improve our RCU lib with
>> membarrier() -
>> would be really interested to hear.
> There is a version in current wireshark extcap patch series.
> The membarrier is expensive but only happens when capture is stopped.
> We can afford a system call there.
Probably I didn't explain my concern regarding membarrier() well enough.
Let me try again:
AFAIU, when you issue a membarrier() on one thread, all other threads in
that process
(in case of MP - on all processes) will be synchronized.
I.E: all of them (all CPUs they run on) will receive an IPI, that they
have to handle.
So, for each CB add/remove - all DP threads doing packet RX/TX will be
interrupted.
That probably not what user wants.
Once again - why do you think that current librcu mechanism is not fast
enough?
As I said before: one thread_fence(seq_cst) per burst doesn't look like
a huge slowdown to me.
>
> The read side (in callback) is:
>
> static inline void
> capture_rcu_enter(unsigned int slot)
> {
> struct capture_rcu_reader *r = &capture_rcu.reader[slot];
> uint64_t t;
>
> if (r->depth++ != 0)
> return;
>
> t = rte_atomic_load_explicit(&capture_rcu.token, rte_memory_order_relaxed);
> rte_atomic_store_explicit(&r->ctr, t, rte_memory_order_relaxed);
>
> /*
> * The loads that follow must not move above the store of ctr. The
> * writer forces that on every CPU with membarrier, so no fence is
> * needed here; capture is refused if membarrier does not work.
> */
> rte_compiler_barrier();
> }
>
> static inline void
> capture_rcu_exit(unsigned int slot)
> {
> struct capture_rcu_reader *r = &capture_rcu.reader[slot];
>
> if (--r->depth != 0)
> return;
>
> /* release: prior loads complete before the slot reads idle */
> rte_atomic_store_explicit(&r->ctr, 0, rte_memory_order_release);
> }
More information about the dev
mailing list