Add a function to the timer API that allows a caller to traverse a specified set of timer lists, stopping each timer in each list, and invoking a callback function.
Signed-off-by: Erik Gabriel Carrillo <erik.g.carri...@intel.com> --- lib/librte_timer/rte_timer.c | 81 +++++++++++++++++++++++++++------- lib/librte_timer/rte_timer.h | 32 ++++++++++++++ lib/librte_timer/rte_timer_version.map | 1 + 3 files changed, 97 insertions(+), 17 deletions(-) diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c index a76be8b..1eaf755 100644 --- a/lib/librte_timer/rte_timer.c +++ b/lib/librte_timer/rte_timer.c @@ -559,39 +559,30 @@ rte_timer_reset_sync(struct rte_timer *tim, uint64_t ticks, rte_pause(); } -/* Stop the timer associated with the timer handle tim */ -int -rte_timer_stop(struct rte_timer *tim) -{ - return rte_timer_alt_stop(default_data_id, tim); -} - -int __rte_experimental -rte_timer_alt_stop(uint32_t timer_data_id, struct rte_timer *tim) +static int +__rte_timer_stop(struct rte_timer *tim, int local_is_locked, + struct rte_timer_data *data) { union rte_timer_status prev_status, status; unsigned lcore_id = rte_lcore_id(); int ret; - struct rte_timer_data *timer_data; - - TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL); /* wait that the timer is in correct status before update, * and mark it as being configured */ - ret = timer_set_config_state(tim, &prev_status, timer_data); + ret = timer_set_config_state(tim, &prev_status, data); if (ret < 0) return -1; - __TIMER_STAT_ADD(timer_data, stop, 1); + __TIMER_STAT_ADD(data, stop, 1); if (prev_status.state == RTE_TIMER_RUNNING && lcore_id < RTE_MAX_LCORE) { - timer_data->priv_timer[lcore_id].updated = 1; + data->priv_timer[lcore_id].updated = 1; } /* remove it from list */ if (prev_status.state == RTE_TIMER_PENDING) { - timer_del(tim, prev_status, 0, timer_data); - __TIMER_STAT_ADD(timer_data, pending, -1); + timer_del(tim, prev_status, local_is_locked, data); + __TIMER_STAT_ADD(data, pending, -1); } /* mark timer as stopped */ @@ -603,6 +594,23 @@ rte_timer_alt_stop(uint32_t timer_data_id, struct rte_timer *tim) return 0; } +/* Stop the timer associated with the timer handle tim */ +int +rte_timer_stop(struct rte_timer *tim) +{ + return rte_timer_alt_stop(default_data_id, tim); +} + +int __rte_experimental +rte_timer_alt_stop(uint32_t timer_data_id, struct rte_timer *tim) +{ + struct rte_timer_data *timer_data; + + TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL); + + return __rte_timer_stop(tim, 0, timer_data); +} + /* loop until rte_timer_stop() succeed */ void rte_timer_stop_sync(struct rte_timer *tim) @@ -912,6 +920,45 @@ rte_timer_alt_manage(uint32_t timer_data_id, return 0; } +/* Walk pending lists, stopping timers and calling user-specified function */ +int __rte_experimental +rte_timer_stop_all(uint32_t timer_data_id, unsigned int *walk_lcores, + int nb_walk_lcores, + rte_timer_stop_all_cb_t f, void *f_arg) +{ + int i; + struct priv_timer *priv_timer; + uint32_t walk_lcore; + struct rte_timer *tim, *next_tim; + struct rte_timer_data *timer_data; + + TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL); + + for (i = 0, walk_lcore = walk_lcores[i]; + i < nb_walk_lcores; + walk_lcore = walk_lcores[++i]) { + priv_timer = &timer_data->priv_timer[walk_lcore]; + + rte_spinlock_lock(&priv_timer->list_lock); + + for (tim = priv_timer->pending_head.sl_next[0]; + tim != NULL; + tim = next_tim) { + next_tim = tim->sl_next[0]; + + /* Call timer_stop with lock held */ + __rte_timer_stop(tim, 1, timer_data); + + if (f) + f(tim, f_arg); + } + + rte_spinlock_unlock(&priv_timer->list_lock); + } + + return 0; +} + /* dump statistics about timers */ void rte_timer_dump_stats(FILE *f) { diff --git a/lib/librte_timer/rte_timer.h b/lib/librte_timer/rte_timer.h index 9daa334..27b1ebd 100644 --- a/lib/librte_timer/rte_timer.h +++ b/lib/librte_timer/rte_timer.h @@ -446,6 +446,38 @@ rte_timer_alt_manage(uint32_t timer_data_id, unsigned int *poll_lcores, int n_poll_lcores, rte_timer_alt_manage_cb_t f); /** + * Callback function type for rte_timer_stop_all(). + */ +typedef void (*rte_timer_stop_all_cb_t)(struct rte_timer *tim, void *arg); + +/** + * @warning + * @b EXPERIMENTAL: this API may change without prior notice + * + * Walk the pending timer lists for the specified lcore IDs, and for each timer + * that is encountered, stop it and call the specified callback function to + * process it further. + * + * @param timer_data_id + * An identifier indicating which instance of timer data should be used for + * this operation. + * @param walk_lcores + * An array of lcore ids identifying the timer lists that should be processed. + * @param nb_walk_lcores + * The size of the walk_lcores array. + * @param f + * The callback function which should be called for each timers. Can be NULL. + * @param f_arg + * An arbitrary argument that will be passed to f, if it is called. + * @return + * - 0: success + * - EINVAL: invalid timer_data_id + */ +int __rte_experimental +rte_timer_stop_all(uint32_t timer_data_id, unsigned int *walk_lcores, + int nb_walk_lcores, rte_timer_stop_all_cb_t f, void *f_arg); + +/** * @warning * @b EXPERIMENTAL: this API may change without prior notice * diff --git a/lib/librte_timer/rte_timer_version.map b/lib/librte_timer/rte_timer_version.map index 1e6b70d..0fab845 100644 --- a/lib/librte_timer/rte_timer_version.map +++ b/lib/librte_timer/rte_timer_version.map @@ -28,5 +28,6 @@ EXPERIMENTAL { rte_timer_alt_stop; rte_timer_data_alloc; rte_timer_data_dealloc; + rte_timer_stop_all; rte_timer_subsystem_finalize; }; -- 2.6.4