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.
--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.