On 25/10/2026 10:50, Konstantin Ananyev wrote:
/* in use, busy wait till current RX/TX iteration is
finished */
if ((puse & BPF_ETH_CBI_INUSE) != 0) {
RTE_WAIT_UNTIL_MASKED((__rte_atomic uint32_t
*)(uintptr_t)&cbi->use,
UINT32_MAX, !=, puse,
rte_memory_order_acquire);
}
Here, we are waiting when 'puse' will become not equal to 'cbi->use'.
So, any value except current puse is good.
If you look a the sequence diagram, there is no way to arrive here
without the callback being removed and `cb` cleared in the DP
thread, no matter how you move the arrows around. So the DP thread
will increment `use` once to make it even, and then will never ever
reach the callback or increment anything again. We allow any value
except current puse, but there are never any values except the
current puse and the one after it. It's just these two values we can
possibly see.
DP can (and most likely will) call rx/tx_burst again.
Just to give you an example:
--- DP thread:
cbi->use = 1;
--- CP thread:
read cbi->use (1)
By this time the callback is removed and `cb` is cleared.
from CP thread perspective:
a) bc->cb is removed from ethdev callback list
b) bc->cb = NULL
But there is no guarantee that DP thread will see these changes till next
bpf_eth_cbi_inuse()->rte_atomic_thread_fence(rte_memory_order_seq_cst);
So it can still (at least once) invoke bpf callback and read and update
cbi->use.
Thinking about that once again - it seems that could happen only once
(i.e. in that example CP thread will see just one of {1,2,3,4} after
that point.
So I probably was too pessimistic about 'live-lock'.
But anyway, I don't see any point to change existing code to what you
propose (boolean value).
From my perspective it doesn't make it safer (or faster) in any way.
--DP thread:
cbi->use = 2;
...
next rx burst:
cbi->use = 3;
How did we reach hear if `cb` is NULL?
read cbi->use (3)
So CP sees an odd value (3), but it is ok to proceed, as previoud RX
iteration (quiscent period) had already finished,
and in new one rx_burst will not see removed call-back.