The code for rte_eal_alarm_cancel was using two loops and duplicate code to handle cancel at the start of the list. Introduce the LIST_FOREACH_SAFE() macro from FreeBsd which makes writing the loop cleaner and simpler.
Signed-off-by: Stephen Hemminger <step...@networkplumber.org> --- lib/eal/linux/eal_alarm.c | 51 +++++++++++++++------------------------ 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/lib/eal/linux/eal_alarm.c b/lib/eal/linux/eal_alarm.c index eeb096213b..3f3b722421 100644 --- a/lib/eal/linux/eal_alarm.c +++ b/lib/eal/linux/eal_alarm.c @@ -53,6 +53,13 @@ static struct rte_intr_handle *intr_handle; static int handler_registered = 0; static void eal_alarm_callback(void *arg); +#ifndef LIST_FOREACH_SAFE +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) +#endif + void rte_eal_alarm_cleanup(void) { @@ -194,7 +201,7 @@ rte_eal_alarm_set(uint64_t us, rte_eal_alarm_callback cb_fn, void *cb_arg) int rte_eal_alarm_cancel(rte_eal_alarm_callback cb_fn, void *cb_arg) { - struct alarm_entry *ap, *ap_prev; + struct alarm_entry *ap, *tmp; int count = 0; int err = 0; int executing; @@ -207,46 +214,26 @@ rte_eal_alarm_cancel(rte_eal_alarm_callback cb_fn, void *cb_arg) do { executing = 0; rte_spinlock_lock(&alarm_list_lk); - /* remove any matches at the start of the list */ - while ((ap = LIST_FIRST(&alarm_list)) != NULL && - cb_fn == ap->cb_fn && - (cb_arg == (void *)-1 || cb_arg == ap->cb_arg)) { - - if (ap->executing == 0) { - LIST_REMOVE(ap, next); - free(ap); - count++; - } else { - /* If calling from other context, mark that alarm is executing - * so loop can spin till it finish. Otherwise we are trying to - * cancel our self - mark it by EINPROGRESS */ - if (pthread_equal(ap->executing_id, pthread_self()) == 0) - executing++; - else - err = EINPROGRESS; - - break; - } - } - ap_prev = ap; - /* now go through list, removing entries not at start */ - LIST_FOREACH(ap, &alarm_list, next) { + LIST_FOREACH_SAFE(ap, &alarm_list, next, tmp) { /* this won't be true first time through */ if (cb_fn == ap->cb_fn && (cb_arg == (void *)-1 || cb_arg == ap->cb_arg)) { - if (ap->executing == 0) { LIST_REMOVE(ap, next); free(ap); count++; - ap = ap_prev; - } else if (pthread_equal(ap->executing_id, pthread_self()) == 0) - executing++; - else - err = EINPROGRESS; + } else { + /* If calling from other context, mark that alarm is executing + * so loop can spin till it finish. Otherwise we are trying to + * cancel our self - mark it by EINPROGRESS + */ + if (pthread_equal(ap->executing_id, pthread_self()) == 0) + executing++; + else + err = EINPROGRESS; + } } - ap_prev = ap; } rte_spinlock_unlock(&alarm_list_lk); } while (executing != 0); -- 2.43.0