Issue: Two threads: - A, executing rte_eal_alarm_cancel, - B, executing eal_alarm_callback.
Such case can cause starvation of thread B. Please see that there is a small time window between lock and unlock in thread A, so thread B must be switched to within a very small time window, so that it can obtain the lock. Solution to this problem is use sched_yield(), which puts current thread (A) at the end of thread execution priority queue and allows thread B to execute. The issue can be observed e.g. on hot-pluggable device detach path. On such path, rte_alarm can used to check if DPDK has completed the detachment. Waiting for completion, rte_eal_alarm_cancel is called, while another thread periodically calls eal_alarm_callback causing the issue to occur. Signed-off-by: Wojciech Panfil <wojciech.pan...@intel.com> --- lib/eal/freebsd/eal_alarm.c | 5 +++++ lib/eal/linux/eal_alarm.c | 5 +++++ lib/eal/windows/eal_alarm.c | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/lib/eal/freebsd/eal_alarm.c b/lib/eal/freebsd/eal_alarm.c index 94cae5f4b6..8425b4f5a2 100644 --- a/lib/eal/freebsd/eal_alarm.c +++ b/lib/eal/freebsd/eal_alarm.c @@ -318,7 +318,12 @@ rte_eal_alarm_cancel(rte_eal_alarm_callback cb_fn, void *cb_arg) } ap_prev = ap; } + rte_spinlock_unlock(&alarm_list_lk); + + /* Yield control to a second thread executing eal_alarm_callback to avoid its starvation, + * as it is waiting for the lock we have just released. */ + sched_yield(); } while (executing != 0); if (count == 0 && err == 0) diff --git a/lib/eal/linux/eal_alarm.c b/lib/eal/linux/eal_alarm.c index eeb096213b..5326b1895f 100644 --- a/lib/eal/linux/eal_alarm.c +++ b/lib/eal/linux/eal_alarm.c @@ -248,7 +248,12 @@ rte_eal_alarm_cancel(rte_eal_alarm_callback cb_fn, void *cb_arg) } ap_prev = ap; } + rte_spinlock_unlock(&alarm_list_lk); + + /* Yield control to a second thread executing eal_alarm_callback to avoid its starvation, + * as it is waiting for the lock we have just released. */ + sched_yield(); } while (executing != 0); if (count == 0 && err == 0) diff --git a/lib/eal/windows/eal_alarm.c b/lib/eal/windows/eal_alarm.c index 052af4b21b..43e8d7881f 100644 --- a/lib/eal/windows/eal_alarm.c +++ b/lib/eal/windows/eal_alarm.c @@ -211,6 +211,10 @@ rte_eal_alarm_cancel(rte_eal_alarm_callback cb_fn, void *cb_arg) } rte_spinlock_unlock(&alarm_lock); + + /* Yield control to a second thread executing eal_alarm_callback to avoid its starvation, + * as it is waiting for the lock we have just released. */ + SwitchToThread(); } while (executing); rte_eal_trace_alarm_cancel(cb_fn, cb_arg, removed); -- 2.46.0