1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
11 #include <sys/queue.h>
13 #include <rte_atomic.h>
14 #include <rte_common.h>
15 #include <rte_cycles.h>
16 #include <rte_eal_memconfig.h>
17 #include <rte_per_lcore.h>
18 #include <rte_memory.h>
19 #include <rte_launch.h>
21 #include <rte_lcore.h>
22 #include <rte_branch_prediction.h>
23 #include <rte_spinlock.h>
24 #include <rte_random.h>
25 #include <rte_pause.h>
26 #include <rte_memzone.h>
27 #include <rte_malloc.h>
28 #include <rte_errno.h>
30 #include "rte_timer.h"
33 * Per-lcore info for timers.
36 struct rte_timer pending_head; /**< dummy timer instance to head up list */
37 rte_spinlock_t list_lock; /**< lock to protect list access */
39 /** per-core variable that true if a timer was updated on this
40 * core since last reset of the variable */
43 /** track the current depth of the skiplist */
44 unsigned curr_skiplist_depth;
46 unsigned prev_lcore; /**< used for lcore round robin */
48 /** running timer on this lcore now */
49 struct rte_timer *running_tim;
51 #ifdef RTE_LIBRTE_TIMER_DEBUG
52 /** per-lcore statistics */
53 struct rte_timer_debug_stats stats;
55 } __rte_cache_aligned;
57 #define FL_ALLOCATED (1 << 0)
58 struct rte_timer_data {
59 struct priv_timer priv_timer[RTE_MAX_LCORE];
60 uint8_t internal_flags;
63 #define RTE_MAX_DATA_ELS 64
64 static const struct rte_memzone *rte_timer_data_mz;
65 static int *volatile rte_timer_mz_refcnt;
66 static struct rte_timer_data *rte_timer_data_arr;
67 static const uint32_t default_data_id;
68 static uint32_t rte_timer_subsystem_initialized;
70 /* when debug is enabled, store some statistics */
71 #ifdef RTE_LIBRTE_TIMER_DEBUG
72 #define __TIMER_STAT_ADD(priv_timer, name, n) do { \
73 unsigned __lcore_id = rte_lcore_id(); \
74 if (__lcore_id < RTE_MAX_LCORE) \
75 priv_timer[__lcore_id].stats.name += (n); \
78 #define __TIMER_STAT_ADD(priv_timer, name, n) do {} while (0)
82 timer_data_valid(uint32_t id)
84 return rte_timer_data_arr &&
85 (rte_timer_data_arr[id].internal_flags & FL_ALLOCATED);
88 /* validate ID and retrieve timer data pointer, or return error value */
89 #define TIMER_DATA_VALID_GET_OR_ERR_RET(id, timer_data, retval) do { \
90 if (id >= RTE_MAX_DATA_ELS || !timer_data_valid(id)) \
92 timer_data = &rte_timer_data_arr[id]; \
96 rte_timer_data_alloc(uint32_t *id_ptr)
99 struct rte_timer_data *data;
101 if (!rte_timer_subsystem_initialized)
104 for (i = 0; i < RTE_MAX_DATA_ELS; i++) {
105 data = &rte_timer_data_arr[i];
106 if (!(data->internal_flags & FL_ALLOCATED)) {
107 data->internal_flags |= FL_ALLOCATED;
120 rte_timer_data_dealloc(uint32_t id)
122 struct rte_timer_data *timer_data;
123 TIMER_DATA_VALID_GET_OR_ERR_RET(id, timer_data, -EINVAL);
125 timer_data->internal_flags &= ~(FL_ALLOCATED);
130 /* Init the timer library. Allocate an array of timer data structs in shared
131 * memory, and allocate the zeroth entry for use with original timer
132 * APIs. Since the intersection of the sets of lcore ids in primary and
133 * secondary processes should be empty, the zeroth entry can be shared by
134 * multiple processes.
137 rte_timer_subsystem_init(void)
139 const struct rte_memzone *mz;
140 struct rte_timer_data *data;
142 static const char *mz_name = "rte_timer_mz";
143 const size_t data_arr_size =
144 RTE_MAX_DATA_ELS * sizeof(*rte_timer_data_arr);
145 const size_t mem_size = data_arr_size + sizeof(*rte_timer_mz_refcnt);
146 bool do_full_init = true;
148 rte_mcfg_timer_lock();
150 if (rte_timer_subsystem_initialized) {
151 rte_mcfg_timer_unlock();
155 mz = rte_memzone_lookup(mz_name);
157 mz = rte_memzone_reserve_aligned(mz_name, mem_size,
158 SOCKET_ID_ANY, 0, RTE_CACHE_LINE_SIZE);
160 rte_mcfg_timer_unlock();
165 do_full_init = false;
167 rte_timer_data_mz = mz;
168 rte_timer_data_arr = mz->addr;
169 rte_timer_mz_refcnt = (void *)((char *)mz->addr + data_arr_size);
172 for (i = 0; i < RTE_MAX_DATA_ELS; i++) {
173 data = &rte_timer_data_arr[i];
175 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE;
178 &data->priv_timer[lcore_id].list_lock);
179 data->priv_timer[lcore_id].prev_lcore =
185 rte_timer_data_arr[default_data_id].internal_flags |= FL_ALLOCATED;
186 (*rte_timer_mz_refcnt)++;
188 rte_timer_subsystem_initialized = 1;
190 rte_mcfg_timer_unlock();
196 rte_timer_subsystem_finalize(void)
198 rte_mcfg_timer_lock();
200 if (!rte_timer_subsystem_initialized) {
201 rte_mcfg_timer_unlock();
205 if (--(*rte_timer_mz_refcnt) == 0)
206 rte_memzone_free(rte_timer_data_mz);
208 rte_timer_subsystem_initialized = 0;
210 rte_mcfg_timer_unlock();
213 /* Initialize the timer handle tim for use */
215 rte_timer_init(struct rte_timer *tim)
217 union rte_timer_status status;
219 status.state = RTE_TIMER_STOP;
220 status.owner = RTE_TIMER_NO_OWNER;
221 tim->status.u32 = status.u32;
225 * if timer is pending or stopped (or running on the same core than
226 * us), mark timer as configuring, and on success return the previous
227 * status of the timer
230 timer_set_config_state(struct rte_timer *tim,
231 union rte_timer_status *ret_prev_status,
232 struct priv_timer *priv_timer)
234 union rte_timer_status prev_status, status;
238 lcore_id = rte_lcore_id();
240 /* wait that the timer is in correct status before update,
241 * and mark it as being configured */
242 while (success == 0) {
243 prev_status.u32 = tim->status.u32;
245 /* timer is running on another core
246 * or ready to run on local core, exit
248 if (prev_status.state == RTE_TIMER_RUNNING &&
249 (prev_status.owner != (uint16_t)lcore_id ||
250 tim != priv_timer[lcore_id].running_tim))
253 /* timer is being configured on another core */
254 if (prev_status.state == RTE_TIMER_CONFIG)
257 /* here, we know that timer is stopped or pending,
258 * mark it atomically as being configured */
259 status.state = RTE_TIMER_CONFIG;
260 status.owner = (int16_t)lcore_id;
261 success = rte_atomic32_cmpset(&tim->status.u32,
266 ret_prev_status->u32 = prev_status.u32;
271 * if timer is pending, mark timer as running
274 timer_set_running_state(struct rte_timer *tim)
276 union rte_timer_status prev_status, status;
277 unsigned lcore_id = rte_lcore_id();
280 /* wait that the timer is in correct status before update,
281 * and mark it as running */
282 while (success == 0) {
283 prev_status.u32 = tim->status.u32;
285 /* timer is not pending anymore */
286 if (prev_status.state != RTE_TIMER_PENDING)
289 /* here, we know that timer is stopped or pending,
290 * mark it atomically as being configured */
291 status.state = RTE_TIMER_RUNNING;
292 status.owner = (int16_t)lcore_id;
293 success = rte_atomic32_cmpset(&tim->status.u32,
302 * Return a skiplist level for a new entry.
303 * This probabilistically gives a level with p=1/4 that an entry at level n
304 * will also appear at level n+1.
307 timer_get_skiplist_level(unsigned curr_depth)
309 #ifdef RTE_LIBRTE_TIMER_DEBUG
310 static uint32_t i, count = 0;
311 static uint32_t levels[MAX_SKIPLIST_DEPTH] = {0};
314 /* probability value is 1/4, i.e. all at level 0, 1 in 4 is at level 1,
315 * 1 in 16 at level 2, 1 in 64 at level 3, etc. Calculated using lowest
316 * bit position of a (pseudo)random number.
318 uint32_t rand = rte_rand() & (UINT32_MAX - 1);
319 uint32_t level = rand == 0 ? MAX_SKIPLIST_DEPTH : (rte_bsf32(rand)-1) / 2;
321 /* limit the levels used to one above our current level, so we don't,
322 * for instance, have a level 0 and a level 7 without anything between
324 if (level > curr_depth)
326 if (level >= MAX_SKIPLIST_DEPTH)
327 level = MAX_SKIPLIST_DEPTH-1;
328 #ifdef RTE_LIBRTE_TIMER_DEBUG
331 if (count % 10000 == 0)
332 for (i = 0; i < MAX_SKIPLIST_DEPTH; i++)
333 printf("Level %u: %u\n", (unsigned)i, (unsigned)levels[i]);
339 * For a given time value, get the entries at each level which
340 * are <= that time value.
343 timer_get_prev_entries(uint64_t time_val, unsigned tim_lcore,
344 struct rte_timer **prev, struct priv_timer *priv_timer)
346 unsigned lvl = priv_timer[tim_lcore].curr_skiplist_depth;
347 prev[lvl] = &priv_timer[tim_lcore].pending_head;
350 prev[lvl] = prev[lvl+1];
351 while (prev[lvl]->sl_next[lvl] &&
352 prev[lvl]->sl_next[lvl]->expire <= time_val)
353 prev[lvl] = prev[lvl]->sl_next[lvl];
358 * Given a timer node in the skiplist, find the previous entries for it at
359 * all skiplist levels.
362 timer_get_prev_entries_for_node(struct rte_timer *tim, unsigned tim_lcore,
363 struct rte_timer **prev,
364 struct priv_timer *priv_timer)
368 /* to get a specific entry in the list, look for just lower than the time
369 * values, and then increment on each level individually if necessary
371 timer_get_prev_entries(tim->expire - 1, tim_lcore, prev, priv_timer);
372 for (i = priv_timer[tim_lcore].curr_skiplist_depth - 1; i >= 0; i--) {
373 while (prev[i]->sl_next[i] != NULL &&
374 prev[i]->sl_next[i] != tim &&
375 prev[i]->sl_next[i]->expire <= tim->expire)
376 prev[i] = prev[i]->sl_next[i];
380 /* call with lock held as necessary
382 * timer must be in config state
383 * timer must not be in a list
386 timer_add(struct rte_timer *tim, unsigned int tim_lcore,
387 struct priv_timer *priv_timer)
390 struct rte_timer *prev[MAX_SKIPLIST_DEPTH+1];
392 /* find where exactly this element goes in the list of elements
394 timer_get_prev_entries(tim->expire, tim_lcore, prev, priv_timer);
396 /* now assign it a new level and add at that level */
397 const unsigned tim_level = timer_get_skiplist_level(
398 priv_timer[tim_lcore].curr_skiplist_depth);
399 if (tim_level == priv_timer[tim_lcore].curr_skiplist_depth)
400 priv_timer[tim_lcore].curr_skiplist_depth++;
404 tim->sl_next[lvl] = prev[lvl]->sl_next[lvl];
405 prev[lvl]->sl_next[lvl] = tim;
408 tim->sl_next[0] = prev[0]->sl_next[0];
409 prev[0]->sl_next[0] = tim;
411 /* save the lowest list entry into the expire field of the dummy hdr
412 * NOTE: this is not atomic on 32-bit*/
413 priv_timer[tim_lcore].pending_head.expire = priv_timer[tim_lcore].\
414 pending_head.sl_next[0]->expire;
418 * del from list, lock if needed
419 * timer must be in config state
420 * timer must be in a list
423 timer_del(struct rte_timer *tim, union rte_timer_status prev_status,
424 int local_is_locked, struct priv_timer *priv_timer)
426 unsigned lcore_id = rte_lcore_id();
427 unsigned prev_owner = prev_status.owner;
429 struct rte_timer *prev[MAX_SKIPLIST_DEPTH+1];
431 /* if timer needs is pending another core, we need to lock the
432 * list; if it is on local core, we need to lock if we are not
433 * called from rte_timer_manage() */
434 if (prev_owner != lcore_id || !local_is_locked)
435 rte_spinlock_lock(&priv_timer[prev_owner].list_lock);
437 /* save the lowest list entry into the expire field of the dummy hdr.
438 * NOTE: this is not atomic on 32-bit */
439 if (tim == priv_timer[prev_owner].pending_head.sl_next[0])
440 priv_timer[prev_owner].pending_head.expire =
441 ((tim->sl_next[0] == NULL) ? 0 : tim->sl_next[0]->expire);
443 /* adjust pointers from previous entries to point past this */
444 timer_get_prev_entries_for_node(tim, prev_owner, prev, priv_timer);
445 for (i = priv_timer[prev_owner].curr_skiplist_depth - 1; i >= 0; i--) {
446 if (prev[i]->sl_next[i] == tim)
447 prev[i]->sl_next[i] = tim->sl_next[i];
450 /* in case we deleted last entry at a level, adjust down max level */
451 for (i = priv_timer[prev_owner].curr_skiplist_depth - 1; i >= 0; i--)
452 if (priv_timer[prev_owner].pending_head.sl_next[i] == NULL)
453 priv_timer[prev_owner].curr_skiplist_depth --;
457 if (prev_owner != lcore_id || !local_is_locked)
458 rte_spinlock_unlock(&priv_timer[prev_owner].list_lock);
461 /* Reset and start the timer associated with the timer handle (private func) */
463 __rte_timer_reset(struct rte_timer *tim, uint64_t expire,
464 uint64_t period, unsigned tim_lcore,
465 rte_timer_cb_t fct, void *arg,
467 struct rte_timer_data *timer_data)
469 union rte_timer_status prev_status, status;
471 unsigned lcore_id = rte_lcore_id();
472 struct priv_timer *priv_timer = timer_data->priv_timer;
474 /* round robin for tim_lcore */
475 if (tim_lcore == (unsigned)LCORE_ID_ANY) {
476 if (lcore_id < RTE_MAX_LCORE) {
477 /* EAL thread with valid lcore_id */
478 tim_lcore = rte_get_next_lcore(
479 priv_timer[lcore_id].prev_lcore,
481 priv_timer[lcore_id].prev_lcore = tim_lcore;
483 /* non-EAL thread do not run rte_timer_manage(),
484 * so schedule the timer on the first enabled lcore. */
485 tim_lcore = rte_get_next_lcore(LCORE_ID_ANY, 0, 1);
488 /* wait that the timer is in correct status before update,
489 * and mark it as being configured */
490 ret = timer_set_config_state(tim, &prev_status, priv_timer);
494 __TIMER_STAT_ADD(priv_timer, reset, 1);
495 if (prev_status.state == RTE_TIMER_RUNNING &&
496 lcore_id < RTE_MAX_LCORE) {
497 priv_timer[lcore_id].updated = 1;
500 /* remove it from list */
501 if (prev_status.state == RTE_TIMER_PENDING) {
502 timer_del(tim, prev_status, local_is_locked, priv_timer);
503 __TIMER_STAT_ADD(priv_timer, pending, -1);
506 tim->period = period;
507 tim->expire = expire;
511 /* if timer needs to be scheduled on another core, we need to
512 * lock the destination list; if it is on local core, we need to lock if
513 * we are not called from rte_timer_manage()
515 if (tim_lcore != lcore_id || !local_is_locked)
516 rte_spinlock_lock(&priv_timer[tim_lcore].list_lock);
518 __TIMER_STAT_ADD(priv_timer, pending, 1);
519 timer_add(tim, tim_lcore, priv_timer);
521 /* update state: as we are in CONFIG state, only us can modify
522 * the state so we don't need to use cmpset() here */
524 status.state = RTE_TIMER_PENDING;
525 status.owner = (int16_t)tim_lcore;
526 tim->status.u32 = status.u32;
528 if (tim_lcore != lcore_id || !local_is_locked)
529 rte_spinlock_unlock(&priv_timer[tim_lcore].list_lock);
534 /* Reset and start the timer associated with the timer handle tim */
536 rte_timer_reset(struct rte_timer *tim, uint64_t ticks,
537 enum rte_timer_type type, unsigned int tim_lcore,
538 rte_timer_cb_t fct, void *arg)
540 return rte_timer_alt_reset(default_data_id, tim, ticks, type,
541 tim_lcore, fct, arg);
545 rte_timer_alt_reset(uint32_t timer_data_id, struct rte_timer *tim,
546 uint64_t ticks, enum rte_timer_type type,
547 unsigned int tim_lcore, rte_timer_cb_t fct, void *arg)
549 uint64_t cur_time = rte_get_timer_cycles();
551 struct rte_timer_data *timer_data;
553 TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
555 if (type == PERIODICAL)
560 return __rte_timer_reset(tim, cur_time + ticks, period, tim_lcore,
561 fct, arg, 0, timer_data);
564 /* loop until rte_timer_reset() succeed */
566 rte_timer_reset_sync(struct rte_timer *tim, uint64_t ticks,
567 enum rte_timer_type type, unsigned tim_lcore,
568 rte_timer_cb_t fct, void *arg)
570 while (rte_timer_reset(tim, ticks, type, tim_lcore,
576 __rte_timer_stop(struct rte_timer *tim, int local_is_locked,
577 struct rte_timer_data *timer_data)
579 union rte_timer_status prev_status, status;
580 unsigned lcore_id = rte_lcore_id();
582 struct priv_timer *priv_timer = timer_data->priv_timer;
584 /* wait that the timer is in correct status before update,
585 * and mark it as being configured */
586 ret = timer_set_config_state(tim, &prev_status, priv_timer);
590 __TIMER_STAT_ADD(priv_timer, stop, 1);
591 if (prev_status.state == RTE_TIMER_RUNNING &&
592 lcore_id < RTE_MAX_LCORE) {
593 priv_timer[lcore_id].updated = 1;
596 /* remove it from list */
597 if (prev_status.state == RTE_TIMER_PENDING) {
598 timer_del(tim, prev_status, local_is_locked, priv_timer);
599 __TIMER_STAT_ADD(priv_timer, pending, -1);
602 /* mark timer as stopped */
604 status.state = RTE_TIMER_STOP;
605 status.owner = RTE_TIMER_NO_OWNER;
606 tim->status.u32 = status.u32;
611 /* Stop the timer associated with the timer handle tim */
613 rte_timer_stop(struct rte_timer *tim)
615 return rte_timer_alt_stop(default_data_id, tim);
619 rte_timer_alt_stop(uint32_t timer_data_id, struct rte_timer *tim)
621 struct rte_timer_data *timer_data;
623 TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
625 return __rte_timer_stop(tim, 0, timer_data);
628 /* loop until rte_timer_stop() succeed */
630 rte_timer_stop_sync(struct rte_timer *tim)
632 while (rte_timer_stop(tim) != 0)
636 /* Test the PENDING status of the timer handle tim */
638 rte_timer_pending(struct rte_timer *tim)
640 return tim->status.state == RTE_TIMER_PENDING;
643 /* must be called periodically, run all timer that expired */
645 __rte_timer_manage(struct rte_timer_data *timer_data)
647 union rte_timer_status status;
648 struct rte_timer *tim, *next_tim;
649 struct rte_timer *run_first_tim, **pprev;
650 unsigned lcore_id = rte_lcore_id();
651 struct rte_timer *prev[MAX_SKIPLIST_DEPTH + 1];
654 struct priv_timer *priv_timer = timer_data->priv_timer;
656 /* timer manager only runs on EAL thread with valid lcore_id */
657 assert(lcore_id < RTE_MAX_LCORE);
659 __TIMER_STAT_ADD(priv_timer, manage, 1);
660 /* optimize for the case where per-cpu list is empty */
661 if (priv_timer[lcore_id].pending_head.sl_next[0] == NULL)
663 cur_time = rte_get_timer_cycles();
666 /* on 64-bit the value cached in the pending_head.expired will be
667 * updated atomically, so we can consult that for a quick check here
668 * outside the lock */
669 if (likely(priv_timer[lcore_id].pending_head.expire > cur_time))
673 /* browse ordered list, add expired timers in 'expired' list */
674 rte_spinlock_lock(&priv_timer[lcore_id].list_lock);
676 /* if nothing to do just unlock and return */
677 if (priv_timer[lcore_id].pending_head.sl_next[0] == NULL ||
678 priv_timer[lcore_id].pending_head.sl_next[0]->expire > cur_time) {
679 rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
683 /* save start of list of expired timers */
684 tim = priv_timer[lcore_id].pending_head.sl_next[0];
686 /* break the existing list at current time point */
687 timer_get_prev_entries(cur_time, lcore_id, prev, priv_timer);
688 for (i = priv_timer[lcore_id].curr_skiplist_depth -1; i >= 0; i--) {
689 if (prev[i] == &priv_timer[lcore_id].pending_head)
691 priv_timer[lcore_id].pending_head.sl_next[i] =
693 if (prev[i]->sl_next[i] == NULL)
694 priv_timer[lcore_id].curr_skiplist_depth--;
695 prev[i] ->sl_next[i] = NULL;
698 /* transition run-list from PENDING to RUNNING */
700 pprev = &run_first_tim;
702 for ( ; tim != NULL; tim = next_tim) {
703 next_tim = tim->sl_next[0];
705 ret = timer_set_running_state(tim);
706 if (likely(ret == 0)) {
707 pprev = &tim->sl_next[0];
709 /* another core is trying to re-config this one,
710 * remove it from local expired list
716 /* update the next to expire timer value */
717 priv_timer[lcore_id].pending_head.expire =
718 (priv_timer[lcore_id].pending_head.sl_next[0] == NULL) ? 0 :
719 priv_timer[lcore_id].pending_head.sl_next[0]->expire;
721 rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
723 /* now scan expired list and call callbacks */
724 for (tim = run_first_tim; tim != NULL; tim = next_tim) {
725 next_tim = tim->sl_next[0];
726 priv_timer[lcore_id].updated = 0;
727 priv_timer[lcore_id].running_tim = tim;
729 /* execute callback function with list unlocked */
730 tim->f(tim, tim->arg);
732 __TIMER_STAT_ADD(priv_timer, pending, -1);
733 /* the timer was stopped or reloaded by the callback
734 * function, we have nothing to do here */
735 if (priv_timer[lcore_id].updated == 1)
738 if (tim->period == 0) {
739 /* remove from done list and mark timer as stopped */
740 status.state = RTE_TIMER_STOP;
741 status.owner = RTE_TIMER_NO_OWNER;
743 tim->status.u32 = status.u32;
746 /* keep it in list and mark timer as pending */
747 rte_spinlock_lock(&priv_timer[lcore_id].list_lock);
748 status.state = RTE_TIMER_PENDING;
749 __TIMER_STAT_ADD(priv_timer, pending, 1);
750 status.owner = (int16_t)lcore_id;
752 tim->status.u32 = status.u32;
753 __rte_timer_reset(tim, tim->expire + tim->period,
754 tim->period, lcore_id, tim->f, tim->arg, 1,
756 rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
759 priv_timer[lcore_id].running_tim = NULL;
763 rte_timer_manage(void)
765 struct rte_timer_data *timer_data;
767 TIMER_DATA_VALID_GET_OR_ERR_RET(default_data_id, timer_data, -EINVAL);
769 __rte_timer_manage(timer_data);
775 rte_timer_alt_manage(uint32_t timer_data_id,
776 unsigned int *poll_lcores,
778 rte_timer_alt_manage_cb_t f)
780 unsigned int default_poll_lcores[] = {rte_lcore_id()};
781 union rte_timer_status status;
782 struct rte_timer *tim, *next_tim, **pprev;
783 struct rte_timer *run_first_tims[RTE_MAX_LCORE];
784 unsigned int this_lcore = rte_lcore_id();
785 struct rte_timer *prev[MAX_SKIPLIST_DEPTH + 1];
789 struct rte_timer_data *data;
790 struct priv_timer *privp;
793 TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, data, -EINVAL);
795 /* timer manager only runs on EAL thread with valid lcore_id */
796 assert(this_lcore < RTE_MAX_LCORE);
798 __TIMER_STAT_ADD(data->priv_timer, manage, 1);
800 if (poll_lcores == NULL) {
801 poll_lcores = default_poll_lcores;
802 nb_poll_lcores = RTE_DIM(default_poll_lcores);
805 for (i = 0; i < nb_poll_lcores; i++) {
806 poll_lcore = poll_lcores[i];
807 privp = &data->priv_timer[poll_lcore];
809 /* optimize for the case where per-cpu list is empty */
810 if (privp->pending_head.sl_next[0] == NULL)
812 cur_time = rte_get_timer_cycles();
815 /* on 64-bit the value cached in the pending_head.expired will
816 * be updated atomically, so we can consult that for a quick
817 * check here outside the lock
819 if (likely(privp->pending_head.expire > cur_time))
823 /* browse ordered list, add expired timers in 'expired' list */
824 rte_spinlock_lock(&privp->list_lock);
826 /* if nothing to do just unlock and return */
827 if (privp->pending_head.sl_next[0] == NULL ||
828 privp->pending_head.sl_next[0]->expire > cur_time) {
829 rte_spinlock_unlock(&privp->list_lock);
833 /* save start of list of expired timers */
834 tim = privp->pending_head.sl_next[0];
836 /* break the existing list at current time point */
837 timer_get_prev_entries(cur_time, poll_lcore, prev,
839 for (j = privp->curr_skiplist_depth - 1; j >= 0; j--) {
840 if (prev[j] == &privp->pending_head)
842 privp->pending_head.sl_next[j] =
844 if (prev[j]->sl_next[j] == NULL)
845 privp->curr_skiplist_depth--;
847 prev[j]->sl_next[j] = NULL;
850 /* transition run-list from PENDING to RUNNING */
851 run_first_tims[nb_runlists] = tim;
852 pprev = &run_first_tims[nb_runlists];
855 for ( ; tim != NULL; tim = next_tim) {
856 next_tim = tim->sl_next[0];
858 ret = timer_set_running_state(tim);
859 if (likely(ret == 0)) {
860 pprev = &tim->sl_next[0];
862 /* another core is trying to re-config this one,
863 * remove it from local expired list
869 /* update the next to expire timer value */
870 privp->pending_head.expire =
871 (privp->pending_head.sl_next[0] == NULL) ? 0 :
872 privp->pending_head.sl_next[0]->expire;
874 rte_spinlock_unlock(&privp->list_lock);
877 /* Now process the run lists */
880 uint64_t min_expire = UINT64_MAX;
883 /* Find the next oldest timer to process */
884 for (i = 0; i < nb_runlists; i++) {
885 tim = run_first_tims[i];
887 if (tim != NULL && tim->expire < min_expire) {
888 min_expire = tim->expire;
897 tim = run_first_tims[min_idx];
899 /* Move down the runlist from which we picked a timer to
902 run_first_tims[min_idx] = run_first_tims[min_idx]->sl_next[0];
904 data->priv_timer[this_lcore].updated = 0;
905 data->priv_timer[this_lcore].running_tim = tim;
907 /* Call the provided callback function */
910 __TIMER_STAT_ADD(data->priv_timer, pending, -1);
912 /* the timer was stopped or reloaded by the callback
913 * function, we have nothing to do here
915 if (data->priv_timer[this_lcore].updated == 1)
918 if (tim->period == 0) {
919 /* remove from done list and mark timer as stopped */
920 status.state = RTE_TIMER_STOP;
921 status.owner = RTE_TIMER_NO_OWNER;
923 tim->status.u32 = status.u32;
925 /* keep it in list and mark timer as pending */
927 &data->priv_timer[this_lcore].list_lock);
928 status.state = RTE_TIMER_PENDING;
929 __TIMER_STAT_ADD(data->priv_timer, pending, 1);
930 status.owner = (int16_t)this_lcore;
932 tim->status.u32 = status.u32;
933 __rte_timer_reset(tim, tim->expire + tim->period,
934 tim->period, this_lcore, tim->f, tim->arg, 1,
937 &data->priv_timer[this_lcore].list_lock);
940 data->priv_timer[this_lcore].running_tim = NULL;
946 /* Walk pending lists, stopping timers and calling user-specified function */
948 rte_timer_stop_all(uint32_t timer_data_id, unsigned int *walk_lcores,
950 rte_timer_stop_all_cb_t f, void *f_arg)
953 struct priv_timer *priv_timer;
955 struct rte_timer *tim, *next_tim;
956 struct rte_timer_data *timer_data;
958 TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
960 for (i = 0; i < nb_walk_lcores; i++) {
961 walk_lcore = walk_lcores[i];
962 priv_timer = &timer_data->priv_timer[walk_lcore];
964 rte_spinlock_lock(&priv_timer->list_lock);
966 for (tim = priv_timer->pending_head.sl_next[0];
969 next_tim = tim->sl_next[0];
971 /* Call timer_stop with lock held */
972 __rte_timer_stop(tim, 1, timer_data);
978 rte_spinlock_unlock(&priv_timer->list_lock);
985 rte_timer_next_ticks(void)
987 unsigned int lcore_id = rte_lcore_id();
988 struct rte_timer_data *timer_data;
989 struct priv_timer *priv_timer;
990 const struct rte_timer *tm;
992 int64_t left = -ENOENT;
994 TIMER_DATA_VALID_GET_OR_ERR_RET(default_data_id, timer_data, -EINVAL);
996 priv_timer = timer_data->priv_timer;
997 cur_time = rte_get_timer_cycles();
999 rte_spinlock_lock(&priv_timer[lcore_id].list_lock);
1000 tm = priv_timer[lcore_id].pending_head.sl_next[0];
1002 left = tm->expire - cur_time;
1006 rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
1011 /* dump statistics about timers */
1013 __rte_timer_dump_stats(struct rte_timer_data *timer_data __rte_unused, FILE *f)
1015 #ifdef RTE_LIBRTE_TIMER_DEBUG
1016 struct rte_timer_debug_stats sum;
1018 struct priv_timer *priv_timer = timer_data->priv_timer;
1020 memset(&sum, 0, sizeof(sum));
1021 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) {
1022 sum.reset += priv_timer[lcore_id].stats.reset;
1023 sum.stop += priv_timer[lcore_id].stats.stop;
1024 sum.manage += priv_timer[lcore_id].stats.manage;
1025 sum.pending += priv_timer[lcore_id].stats.pending;
1027 fprintf(f, "Timer statistics:\n");
1028 fprintf(f, " reset = %"PRIu64"\n", sum.reset);
1029 fprintf(f, " stop = %"PRIu64"\n", sum.stop);
1030 fprintf(f, " manage = %"PRIu64"\n", sum.manage);
1031 fprintf(f, " pending = %"PRIu64"\n", sum.pending);
1033 fprintf(f, "No timer statistics, RTE_LIBRTE_TIMER_DEBUG is disabled\n");
1038 rte_timer_dump_stats(FILE *f)
1040 return rte_timer_alt_dump_stats(default_data_id, f);
1044 rte_timer_alt_dump_stats(uint32_t timer_data_id __rte_unused, FILE *f)
1046 struct rte_timer_data *timer_data;
1048 TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
1050 __rte_timer_dump_stats(timer_data, f);