1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <string.h> 6 #include <stdio.h> 7 #include <stdint.h> 8 #include <stdbool.h> 9 #include <inttypes.h> 10 #include <assert.h> 11 #include <sys/queue.h> 12 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> 20 #include <rte_eal.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> 29 30 #include "rte_timer.h" 31 32 /** 33 * Per-lcore info for timers. 34 */ 35 struct priv_timer { 36 struct rte_timer pending_head; /**< dummy timer instance to head up list */ 37 rte_spinlock_t list_lock; /**< lock to protect list access */ 38 39 /** per-core variable that true if a timer was updated on this 40 * core since last reset of the variable */ 41 int updated; 42 43 /** track the current depth of the skiplist */ 44 unsigned curr_skiplist_depth; 45 46 unsigned prev_lcore; /**< used for lcore round robin */ 47 48 /** running timer on this lcore now */ 49 struct rte_timer *running_tim; 50 51 #ifdef RTE_LIBRTE_TIMER_DEBUG 52 /** per-lcore statistics */ 53 struct rte_timer_debug_stats stats; 54 #endif 55 } __rte_cache_aligned; 56 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; 61 }; 62 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; 69 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); \ 76 } while(0) 77 #else 78 #define __TIMER_STAT_ADD(priv_timer, name, n) do {} while (0) 79 #endif 80 81 static inline int 82 timer_data_valid(uint32_t id) 83 { 84 return rte_timer_data_arr && 85 (rte_timer_data_arr[id].internal_flags & FL_ALLOCATED); 86 } 87 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)) \ 91 return retval; \ 92 timer_data = &rte_timer_data_arr[id]; \ 93 } while (0) 94 95 int 96 rte_timer_data_alloc(uint32_t *id_ptr) 97 { 98 int i; 99 struct rte_timer_data *data; 100 101 if (!rte_timer_subsystem_initialized) 102 return -ENOMEM; 103 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; 108 109 if (id_ptr) 110 *id_ptr = i; 111 112 return 0; 113 } 114 } 115 116 return -ENOSPC; 117 } 118 119 int 120 rte_timer_data_dealloc(uint32_t id) 121 { 122 struct rte_timer_data *timer_data; 123 TIMER_DATA_VALID_GET_OR_ERR_RET(id, timer_data, -EINVAL); 124 125 timer_data->internal_flags &= ~(FL_ALLOCATED); 126 127 return 0; 128 } 129 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. 135 */ 136 int 137 rte_timer_subsystem_init(void) 138 { 139 const struct rte_memzone *mz; 140 struct rte_timer_data *data; 141 int i, lcore_id; 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; 147 148 if (rte_timer_subsystem_initialized) 149 return -EALREADY; 150 151 rte_mcfg_timer_lock(); 152 153 mz = rte_memzone_lookup(mz_name); 154 if (mz == NULL) { 155 mz = rte_memzone_reserve_aligned(mz_name, mem_size, 156 SOCKET_ID_ANY, 0, RTE_CACHE_LINE_SIZE); 157 if (mz == NULL) { 158 rte_mcfg_timer_unlock(); 159 return -ENOMEM; 160 } 161 do_full_init = true; 162 } else 163 do_full_init = false; 164 165 rte_timer_data_mz = mz; 166 rte_timer_data_arr = mz->addr; 167 rte_timer_mz_refcnt = (void *)((char *)mz->addr + data_arr_size); 168 169 if (do_full_init) { 170 for (i = 0; i < RTE_MAX_DATA_ELS; i++) { 171 data = &rte_timer_data_arr[i]; 172 173 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; 174 lcore_id++) { 175 rte_spinlock_init( 176 &data->priv_timer[lcore_id].list_lock); 177 data->priv_timer[lcore_id].prev_lcore = 178 lcore_id; 179 } 180 } 181 } 182 183 rte_timer_data_arr[default_data_id].internal_flags |= FL_ALLOCATED; 184 (*rte_timer_mz_refcnt)++; 185 186 rte_mcfg_timer_unlock(); 187 188 rte_timer_subsystem_initialized = 1; 189 190 return 0; 191 } 192 193 void 194 rte_timer_subsystem_finalize(void) 195 { 196 if (!rte_timer_subsystem_initialized) 197 return; 198 199 rte_mcfg_timer_lock(); 200 201 if (--(*rte_timer_mz_refcnt) == 0) 202 rte_memzone_free(rte_timer_data_mz); 203 204 rte_mcfg_timer_unlock(); 205 206 rte_timer_subsystem_initialized = 0; 207 } 208 209 /* Initialize the timer handle tim for use */ 210 void 211 rte_timer_init(struct rte_timer *tim) 212 { 213 union rte_timer_status status; 214 215 status.state = RTE_TIMER_STOP; 216 status.owner = RTE_TIMER_NO_OWNER; 217 tim->status.u32 = status.u32; 218 } 219 220 /* 221 * if timer is pending or stopped (or running on the same core than 222 * us), mark timer as configuring, and on success return the previous 223 * status of the timer 224 */ 225 static int 226 timer_set_config_state(struct rte_timer *tim, 227 union rte_timer_status *ret_prev_status, 228 struct priv_timer *priv_timer) 229 { 230 union rte_timer_status prev_status, status; 231 int success = 0; 232 unsigned lcore_id; 233 234 lcore_id = rte_lcore_id(); 235 236 /* wait that the timer is in correct status before update, 237 * and mark it as being configured */ 238 while (success == 0) { 239 prev_status.u32 = tim->status.u32; 240 241 /* timer is running on another core 242 * or ready to run on local core, exit 243 */ 244 if (prev_status.state == RTE_TIMER_RUNNING && 245 (prev_status.owner != (uint16_t)lcore_id || 246 tim != priv_timer[lcore_id].running_tim)) 247 return -1; 248 249 /* timer is being configured on another core */ 250 if (prev_status.state == RTE_TIMER_CONFIG) 251 return -1; 252 253 /* here, we know that timer is stopped or pending, 254 * mark it atomically as being configured */ 255 status.state = RTE_TIMER_CONFIG; 256 status.owner = (int16_t)lcore_id; 257 success = rte_atomic32_cmpset(&tim->status.u32, 258 prev_status.u32, 259 status.u32); 260 } 261 262 ret_prev_status->u32 = prev_status.u32; 263 return 0; 264 } 265 266 /* 267 * if timer is pending, mark timer as running 268 */ 269 static int 270 timer_set_running_state(struct rte_timer *tim) 271 { 272 union rte_timer_status prev_status, status; 273 unsigned lcore_id = rte_lcore_id(); 274 int success = 0; 275 276 /* wait that the timer is in correct status before update, 277 * and mark it as running */ 278 while (success == 0) { 279 prev_status.u32 = tim->status.u32; 280 281 /* timer is not pending anymore */ 282 if (prev_status.state != RTE_TIMER_PENDING) 283 return -1; 284 285 /* here, we know that timer is stopped or pending, 286 * mark it atomically as being configured */ 287 status.state = RTE_TIMER_RUNNING; 288 status.owner = (int16_t)lcore_id; 289 success = rte_atomic32_cmpset(&tim->status.u32, 290 prev_status.u32, 291 status.u32); 292 } 293 294 return 0; 295 } 296 297 /* 298 * Return a skiplist level for a new entry. 299 * This probabilistically gives a level with p=1/4 that an entry at level n 300 * will also appear at level n+1. 301 */ 302 static uint32_t 303 timer_get_skiplist_level(unsigned curr_depth) 304 { 305 #ifdef RTE_LIBRTE_TIMER_DEBUG 306 static uint32_t i, count = 0; 307 static uint32_t levels[MAX_SKIPLIST_DEPTH] = {0}; 308 #endif 309 310 /* probability value is 1/4, i.e. all at level 0, 1 in 4 is at level 1, 311 * 1 in 16 at level 2, 1 in 64 at level 3, etc. Calculated using lowest 312 * bit position of a (pseudo)random number. 313 */ 314 uint32_t rand = rte_rand() & (UINT32_MAX - 1); 315 uint32_t level = rand == 0 ? MAX_SKIPLIST_DEPTH : (rte_bsf32(rand)-1) / 2; 316 317 /* limit the levels used to one above our current level, so we don't, 318 * for instance, have a level 0 and a level 7 without anything between 319 */ 320 if (level > curr_depth) 321 level = curr_depth; 322 if (level >= MAX_SKIPLIST_DEPTH) 323 level = MAX_SKIPLIST_DEPTH-1; 324 #ifdef RTE_LIBRTE_TIMER_DEBUG 325 count ++; 326 levels[level]++; 327 if (count % 10000 == 0) 328 for (i = 0; i < MAX_SKIPLIST_DEPTH; i++) 329 printf("Level %u: %u\n", (unsigned)i, (unsigned)levels[i]); 330 #endif 331 return level; 332 } 333 334 /* 335 * For a given time value, get the entries at each level which 336 * are <= that time value. 337 */ 338 static void 339 timer_get_prev_entries(uint64_t time_val, unsigned tim_lcore, 340 struct rte_timer **prev, struct priv_timer *priv_timer) 341 { 342 unsigned lvl = priv_timer[tim_lcore].curr_skiplist_depth; 343 prev[lvl] = &priv_timer[tim_lcore].pending_head; 344 while(lvl != 0) { 345 lvl--; 346 prev[lvl] = prev[lvl+1]; 347 while (prev[lvl]->sl_next[lvl] && 348 prev[lvl]->sl_next[lvl]->expire <= time_val) 349 prev[lvl] = prev[lvl]->sl_next[lvl]; 350 } 351 } 352 353 /* 354 * Given a timer node in the skiplist, find the previous entries for it at 355 * all skiplist levels. 356 */ 357 static void 358 timer_get_prev_entries_for_node(struct rte_timer *tim, unsigned tim_lcore, 359 struct rte_timer **prev, 360 struct priv_timer *priv_timer) 361 { 362 int i; 363 364 /* to get a specific entry in the list, look for just lower than the time 365 * values, and then increment on each level individually if necessary 366 */ 367 timer_get_prev_entries(tim->expire - 1, tim_lcore, prev, priv_timer); 368 for (i = priv_timer[tim_lcore].curr_skiplist_depth - 1; i >= 0; i--) { 369 while (prev[i]->sl_next[i] != NULL && 370 prev[i]->sl_next[i] != tim && 371 prev[i]->sl_next[i]->expire <= tim->expire) 372 prev[i] = prev[i]->sl_next[i]; 373 } 374 } 375 376 /* call with lock held as necessary 377 * add in list 378 * timer must be in config state 379 * timer must not be in a list 380 */ 381 static void 382 timer_add(struct rte_timer *tim, unsigned int tim_lcore, 383 struct priv_timer *priv_timer) 384 { 385 unsigned lvl; 386 struct rte_timer *prev[MAX_SKIPLIST_DEPTH+1]; 387 388 /* find where exactly this element goes in the list of elements 389 * for each depth. */ 390 timer_get_prev_entries(tim->expire, tim_lcore, prev, priv_timer); 391 392 /* now assign it a new level and add at that level */ 393 const unsigned tim_level = timer_get_skiplist_level( 394 priv_timer[tim_lcore].curr_skiplist_depth); 395 if (tim_level == priv_timer[tim_lcore].curr_skiplist_depth) 396 priv_timer[tim_lcore].curr_skiplist_depth++; 397 398 lvl = tim_level; 399 while (lvl > 0) { 400 tim->sl_next[lvl] = prev[lvl]->sl_next[lvl]; 401 prev[lvl]->sl_next[lvl] = tim; 402 lvl--; 403 } 404 tim->sl_next[0] = prev[0]->sl_next[0]; 405 prev[0]->sl_next[0] = tim; 406 407 /* save the lowest list entry into the expire field of the dummy hdr 408 * NOTE: this is not atomic on 32-bit*/ 409 priv_timer[tim_lcore].pending_head.expire = priv_timer[tim_lcore].\ 410 pending_head.sl_next[0]->expire; 411 } 412 413 /* 414 * del from list, lock if needed 415 * timer must be in config state 416 * timer must be in a list 417 */ 418 static void 419 timer_del(struct rte_timer *tim, union rte_timer_status prev_status, 420 int local_is_locked, struct priv_timer *priv_timer) 421 { 422 unsigned lcore_id = rte_lcore_id(); 423 unsigned prev_owner = prev_status.owner; 424 int i; 425 struct rte_timer *prev[MAX_SKIPLIST_DEPTH+1]; 426 427 /* if timer needs is pending another core, we need to lock the 428 * list; if it is on local core, we need to lock if we are not 429 * called from rte_timer_manage() */ 430 if (prev_owner != lcore_id || !local_is_locked) 431 rte_spinlock_lock(&priv_timer[prev_owner].list_lock); 432 433 /* save the lowest list entry into the expire field of the dummy hdr. 434 * NOTE: this is not atomic on 32-bit */ 435 if (tim == priv_timer[prev_owner].pending_head.sl_next[0]) 436 priv_timer[prev_owner].pending_head.expire = 437 ((tim->sl_next[0] == NULL) ? 0 : tim->sl_next[0]->expire); 438 439 /* adjust pointers from previous entries to point past this */ 440 timer_get_prev_entries_for_node(tim, prev_owner, prev, priv_timer); 441 for (i = priv_timer[prev_owner].curr_skiplist_depth - 1; i >= 0; i--) { 442 if (prev[i]->sl_next[i] == tim) 443 prev[i]->sl_next[i] = tim->sl_next[i]; 444 } 445 446 /* in case we deleted last entry at a level, adjust down max level */ 447 for (i = priv_timer[prev_owner].curr_skiplist_depth - 1; i >= 0; i--) 448 if (priv_timer[prev_owner].pending_head.sl_next[i] == NULL) 449 priv_timer[prev_owner].curr_skiplist_depth --; 450 else 451 break; 452 453 if (prev_owner != lcore_id || !local_is_locked) 454 rte_spinlock_unlock(&priv_timer[prev_owner].list_lock); 455 } 456 457 /* Reset and start the timer associated with the timer handle (private func) */ 458 static int 459 __rte_timer_reset(struct rte_timer *tim, uint64_t expire, 460 uint64_t period, unsigned tim_lcore, 461 rte_timer_cb_t fct, void *arg, 462 int local_is_locked, 463 struct rte_timer_data *timer_data) 464 { 465 union rte_timer_status prev_status, status; 466 int ret; 467 unsigned lcore_id = rte_lcore_id(); 468 struct priv_timer *priv_timer = timer_data->priv_timer; 469 470 /* round robin for tim_lcore */ 471 if (tim_lcore == (unsigned)LCORE_ID_ANY) { 472 if (lcore_id < RTE_MAX_LCORE) { 473 /* EAL thread with valid lcore_id */ 474 tim_lcore = rte_get_next_lcore( 475 priv_timer[lcore_id].prev_lcore, 476 0, 1); 477 priv_timer[lcore_id].prev_lcore = tim_lcore; 478 } else 479 /* non-EAL thread do not run rte_timer_manage(), 480 * so schedule the timer on the first enabled lcore. */ 481 tim_lcore = rte_get_next_lcore(LCORE_ID_ANY, 0, 1); 482 } 483 484 /* wait that the timer is in correct status before update, 485 * and mark it as being configured */ 486 ret = timer_set_config_state(tim, &prev_status, priv_timer); 487 if (ret < 0) 488 return -1; 489 490 __TIMER_STAT_ADD(priv_timer, reset, 1); 491 if (prev_status.state == RTE_TIMER_RUNNING && 492 lcore_id < RTE_MAX_LCORE) { 493 priv_timer[lcore_id].updated = 1; 494 } 495 496 /* remove it from list */ 497 if (prev_status.state == RTE_TIMER_PENDING) { 498 timer_del(tim, prev_status, local_is_locked, priv_timer); 499 __TIMER_STAT_ADD(priv_timer, pending, -1); 500 } 501 502 tim->period = period; 503 tim->expire = expire; 504 tim->f = fct; 505 tim->arg = arg; 506 507 /* if timer needs to be scheduled on another core, we need to 508 * lock the destination list; if it is on local core, we need to lock if 509 * we are not called from rte_timer_manage() 510 */ 511 if (tim_lcore != lcore_id || !local_is_locked) 512 rte_spinlock_lock(&priv_timer[tim_lcore].list_lock); 513 514 __TIMER_STAT_ADD(priv_timer, pending, 1); 515 timer_add(tim, tim_lcore, priv_timer); 516 517 /* update state: as we are in CONFIG state, only us can modify 518 * the state so we don't need to use cmpset() here */ 519 rte_wmb(); 520 status.state = RTE_TIMER_PENDING; 521 status.owner = (int16_t)tim_lcore; 522 tim->status.u32 = status.u32; 523 524 if (tim_lcore != lcore_id || !local_is_locked) 525 rte_spinlock_unlock(&priv_timer[tim_lcore].list_lock); 526 527 return 0; 528 } 529 530 /* Reset and start the timer associated with the timer handle tim */ 531 int 532 rte_timer_reset(struct rte_timer *tim, uint64_t ticks, 533 enum rte_timer_type type, unsigned int tim_lcore, 534 rte_timer_cb_t fct, void *arg) 535 { 536 return rte_timer_alt_reset(default_data_id, tim, ticks, type, 537 tim_lcore, fct, arg); 538 } 539 540 int 541 rte_timer_alt_reset(uint32_t timer_data_id, struct rte_timer *tim, 542 uint64_t ticks, enum rte_timer_type type, 543 unsigned int tim_lcore, rte_timer_cb_t fct, void *arg) 544 { 545 uint64_t cur_time = rte_get_timer_cycles(); 546 uint64_t period; 547 struct rte_timer_data *timer_data; 548 549 TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL); 550 551 if (type == PERIODICAL) 552 period = ticks; 553 else 554 period = 0; 555 556 return __rte_timer_reset(tim, cur_time + ticks, period, tim_lcore, 557 fct, arg, 0, timer_data); 558 } 559 560 /* loop until rte_timer_reset() succeed */ 561 void 562 rte_timer_reset_sync(struct rte_timer *tim, uint64_t ticks, 563 enum rte_timer_type type, unsigned tim_lcore, 564 rte_timer_cb_t fct, void *arg) 565 { 566 while (rte_timer_reset(tim, ticks, type, tim_lcore, 567 fct, arg) != 0) 568 rte_pause(); 569 } 570 571 static int 572 __rte_timer_stop(struct rte_timer *tim, int local_is_locked, 573 struct rte_timer_data *timer_data) 574 { 575 union rte_timer_status prev_status, status; 576 unsigned lcore_id = rte_lcore_id(); 577 int ret; 578 struct priv_timer *priv_timer = timer_data->priv_timer; 579 580 /* wait that the timer is in correct status before update, 581 * and mark it as being configured */ 582 ret = timer_set_config_state(tim, &prev_status, priv_timer); 583 if (ret < 0) 584 return -1; 585 586 __TIMER_STAT_ADD(priv_timer, stop, 1); 587 if (prev_status.state == RTE_TIMER_RUNNING && 588 lcore_id < RTE_MAX_LCORE) { 589 priv_timer[lcore_id].updated = 1; 590 } 591 592 /* remove it from list */ 593 if (prev_status.state == RTE_TIMER_PENDING) { 594 timer_del(tim, prev_status, local_is_locked, priv_timer); 595 __TIMER_STAT_ADD(priv_timer, pending, -1); 596 } 597 598 /* mark timer as stopped */ 599 rte_wmb(); 600 status.state = RTE_TIMER_STOP; 601 status.owner = RTE_TIMER_NO_OWNER; 602 tim->status.u32 = status.u32; 603 604 return 0; 605 } 606 607 /* Stop the timer associated with the timer handle tim */ 608 int 609 rte_timer_stop(struct rte_timer *tim) 610 { 611 return rte_timer_alt_stop(default_data_id, tim); 612 } 613 614 int 615 rte_timer_alt_stop(uint32_t timer_data_id, struct rte_timer *tim) 616 { 617 struct rte_timer_data *timer_data; 618 619 TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL); 620 621 return __rte_timer_stop(tim, 0, timer_data); 622 } 623 624 /* loop until rte_timer_stop() succeed */ 625 void 626 rte_timer_stop_sync(struct rte_timer *tim) 627 { 628 while (rte_timer_stop(tim) != 0) 629 rte_pause(); 630 } 631 632 /* Test the PENDING status of the timer handle tim */ 633 int 634 rte_timer_pending(struct rte_timer *tim) 635 { 636 return tim->status.state == RTE_TIMER_PENDING; 637 } 638 639 /* must be called periodically, run all timer that expired */ 640 static void 641 __rte_timer_manage(struct rte_timer_data *timer_data) 642 { 643 union rte_timer_status status; 644 struct rte_timer *tim, *next_tim; 645 struct rte_timer *run_first_tim, **pprev; 646 unsigned lcore_id = rte_lcore_id(); 647 struct rte_timer *prev[MAX_SKIPLIST_DEPTH + 1]; 648 uint64_t cur_time; 649 int i, ret; 650 struct priv_timer *priv_timer = timer_data->priv_timer; 651 652 /* timer manager only runs on EAL thread with valid lcore_id */ 653 assert(lcore_id < RTE_MAX_LCORE); 654 655 __TIMER_STAT_ADD(priv_timer, manage, 1); 656 /* optimize for the case where per-cpu list is empty */ 657 if (priv_timer[lcore_id].pending_head.sl_next[0] == NULL) 658 return; 659 cur_time = rte_get_timer_cycles(); 660 661 #ifdef RTE_ARCH_64 662 /* on 64-bit the value cached in the pending_head.expired will be 663 * updated atomically, so we can consult that for a quick check here 664 * outside the lock */ 665 if (likely(priv_timer[lcore_id].pending_head.expire > cur_time)) 666 return; 667 #endif 668 669 /* browse ordered list, add expired timers in 'expired' list */ 670 rte_spinlock_lock(&priv_timer[lcore_id].list_lock); 671 672 /* if nothing to do just unlock and return */ 673 if (priv_timer[lcore_id].pending_head.sl_next[0] == NULL || 674 priv_timer[lcore_id].pending_head.sl_next[0]->expire > cur_time) { 675 rte_spinlock_unlock(&priv_timer[lcore_id].list_lock); 676 return; 677 } 678 679 /* save start of list of expired timers */ 680 tim = priv_timer[lcore_id].pending_head.sl_next[0]; 681 682 /* break the existing list at current time point */ 683 timer_get_prev_entries(cur_time, lcore_id, prev, priv_timer); 684 for (i = priv_timer[lcore_id].curr_skiplist_depth -1; i >= 0; i--) { 685 if (prev[i] == &priv_timer[lcore_id].pending_head) 686 continue; 687 priv_timer[lcore_id].pending_head.sl_next[i] = 688 prev[i]->sl_next[i]; 689 if (prev[i]->sl_next[i] == NULL) 690 priv_timer[lcore_id].curr_skiplist_depth--; 691 prev[i] ->sl_next[i] = NULL; 692 } 693 694 /* transition run-list from PENDING to RUNNING */ 695 run_first_tim = tim; 696 pprev = &run_first_tim; 697 698 for ( ; tim != NULL; tim = next_tim) { 699 next_tim = tim->sl_next[0]; 700 701 ret = timer_set_running_state(tim); 702 if (likely(ret == 0)) { 703 pprev = &tim->sl_next[0]; 704 } else { 705 /* another core is trying to re-config this one, 706 * remove it from local expired list 707 */ 708 *pprev = next_tim; 709 } 710 } 711 712 /* update the next to expire timer value */ 713 priv_timer[lcore_id].pending_head.expire = 714 (priv_timer[lcore_id].pending_head.sl_next[0] == NULL) ? 0 : 715 priv_timer[lcore_id].pending_head.sl_next[0]->expire; 716 717 rte_spinlock_unlock(&priv_timer[lcore_id].list_lock); 718 719 /* now scan expired list and call callbacks */ 720 for (tim = run_first_tim; tim != NULL; tim = next_tim) { 721 next_tim = tim->sl_next[0]; 722 priv_timer[lcore_id].updated = 0; 723 priv_timer[lcore_id].running_tim = tim; 724 725 /* execute callback function with list unlocked */ 726 tim->f(tim, tim->arg); 727 728 __TIMER_STAT_ADD(priv_timer, pending, -1); 729 /* the timer was stopped or reloaded by the callback 730 * function, we have nothing to do here */ 731 if (priv_timer[lcore_id].updated == 1) 732 continue; 733 734 if (tim->period == 0) { 735 /* remove from done list and mark timer as stopped */ 736 status.state = RTE_TIMER_STOP; 737 status.owner = RTE_TIMER_NO_OWNER; 738 rte_wmb(); 739 tim->status.u32 = status.u32; 740 } 741 else { 742 /* keep it in list and mark timer as pending */ 743 rte_spinlock_lock(&priv_timer[lcore_id].list_lock); 744 status.state = RTE_TIMER_PENDING; 745 __TIMER_STAT_ADD(priv_timer, pending, 1); 746 status.owner = (int16_t)lcore_id; 747 rte_wmb(); 748 tim->status.u32 = status.u32; 749 __rte_timer_reset(tim, tim->expire + tim->period, 750 tim->period, lcore_id, tim->f, tim->arg, 1, 751 timer_data); 752 rte_spinlock_unlock(&priv_timer[lcore_id].list_lock); 753 } 754 } 755 priv_timer[lcore_id].running_tim = NULL; 756 } 757 758 int 759 rte_timer_manage(void) 760 { 761 struct rte_timer_data *timer_data; 762 763 TIMER_DATA_VALID_GET_OR_ERR_RET(default_data_id, timer_data, -EINVAL); 764 765 __rte_timer_manage(timer_data); 766 767 return 0; 768 } 769 770 int 771 rte_timer_alt_manage(uint32_t timer_data_id, 772 unsigned int *poll_lcores, 773 int nb_poll_lcores, 774 rte_timer_alt_manage_cb_t f) 775 { 776 unsigned int default_poll_lcores[] = {rte_lcore_id()}; 777 union rte_timer_status status; 778 struct rte_timer *tim, *next_tim, **pprev; 779 struct rte_timer *run_first_tims[RTE_MAX_LCORE]; 780 unsigned int this_lcore = rte_lcore_id(); 781 struct rte_timer *prev[MAX_SKIPLIST_DEPTH + 1]; 782 uint64_t cur_time; 783 int i, j, ret; 784 int nb_runlists = 0; 785 struct rte_timer_data *data; 786 struct priv_timer *privp; 787 uint32_t poll_lcore; 788 789 TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, data, -EINVAL); 790 791 /* timer manager only runs on EAL thread with valid lcore_id */ 792 assert(this_lcore < RTE_MAX_LCORE); 793 794 __TIMER_STAT_ADD(data->priv_timer, manage, 1); 795 796 if (poll_lcores == NULL) { 797 poll_lcores = default_poll_lcores; 798 nb_poll_lcores = RTE_DIM(default_poll_lcores); 799 } 800 801 for (i = 0; i < nb_poll_lcores; i++) { 802 poll_lcore = poll_lcores[i]; 803 privp = &data->priv_timer[poll_lcore]; 804 805 /* optimize for the case where per-cpu list is empty */ 806 if (privp->pending_head.sl_next[0] == NULL) 807 continue; 808 cur_time = rte_get_timer_cycles(); 809 810 #ifdef RTE_ARCH_64 811 /* on 64-bit the value cached in the pending_head.expired will 812 * be updated atomically, so we can consult that for a quick 813 * check here outside the lock 814 */ 815 if (likely(privp->pending_head.expire > cur_time)) 816 continue; 817 #endif 818 819 /* browse ordered list, add expired timers in 'expired' list */ 820 rte_spinlock_lock(&privp->list_lock); 821 822 /* if nothing to do just unlock and return */ 823 if (privp->pending_head.sl_next[0] == NULL || 824 privp->pending_head.sl_next[0]->expire > cur_time) { 825 rte_spinlock_unlock(&privp->list_lock); 826 continue; 827 } 828 829 /* save start of list of expired timers */ 830 tim = privp->pending_head.sl_next[0]; 831 832 /* break the existing list at current time point */ 833 timer_get_prev_entries(cur_time, poll_lcore, prev, 834 data->priv_timer); 835 for (j = privp->curr_skiplist_depth - 1; j >= 0; j--) { 836 if (prev[j] == &privp->pending_head) 837 continue; 838 privp->pending_head.sl_next[j] = 839 prev[j]->sl_next[j]; 840 if (prev[j]->sl_next[j] == NULL) 841 privp->curr_skiplist_depth--; 842 843 prev[j]->sl_next[j] = NULL; 844 } 845 846 /* transition run-list from PENDING to RUNNING */ 847 run_first_tims[nb_runlists] = tim; 848 pprev = &run_first_tims[nb_runlists]; 849 nb_runlists++; 850 851 for ( ; tim != NULL; tim = next_tim) { 852 next_tim = tim->sl_next[0]; 853 854 ret = timer_set_running_state(tim); 855 if (likely(ret == 0)) { 856 pprev = &tim->sl_next[0]; 857 } else { 858 /* another core is trying to re-config this one, 859 * remove it from local expired list 860 */ 861 *pprev = next_tim; 862 } 863 } 864 865 /* update the next to expire timer value */ 866 privp->pending_head.expire = 867 (privp->pending_head.sl_next[0] == NULL) ? 0 : 868 privp->pending_head.sl_next[0]->expire; 869 870 rte_spinlock_unlock(&privp->list_lock); 871 } 872 873 /* Now process the run lists */ 874 while (1) { 875 bool done = true; 876 uint64_t min_expire = UINT64_MAX; 877 int min_idx = 0; 878 879 /* Find the next oldest timer to process */ 880 for (i = 0; i < nb_runlists; i++) { 881 tim = run_first_tims[i]; 882 883 if (tim != NULL && tim->expire < min_expire) { 884 min_expire = tim->expire; 885 min_idx = i; 886 done = false; 887 } 888 } 889 890 if (done) 891 break; 892 893 tim = run_first_tims[min_idx]; 894 895 /* Move down the runlist from which we picked a timer to 896 * execute 897 */ 898 run_first_tims[min_idx] = run_first_tims[min_idx]->sl_next[0]; 899 900 data->priv_timer[this_lcore].updated = 0; 901 data->priv_timer[this_lcore].running_tim = tim; 902 903 /* Call the provided callback function */ 904 f(tim); 905 906 __TIMER_STAT_ADD(data->priv_timer, pending, -1); 907 908 /* the timer was stopped or reloaded by the callback 909 * function, we have nothing to do here 910 */ 911 if (data->priv_timer[this_lcore].updated == 1) 912 continue; 913 914 if (tim->period == 0) { 915 /* remove from done list and mark timer as stopped */ 916 status.state = RTE_TIMER_STOP; 917 status.owner = RTE_TIMER_NO_OWNER; 918 rte_wmb(); 919 tim->status.u32 = status.u32; 920 } else { 921 /* keep it in list and mark timer as pending */ 922 rte_spinlock_lock( 923 &data->priv_timer[this_lcore].list_lock); 924 status.state = RTE_TIMER_PENDING; 925 __TIMER_STAT_ADD(data->priv_timer, pending, 1); 926 status.owner = (int16_t)this_lcore; 927 rte_wmb(); 928 tim->status.u32 = status.u32; 929 __rte_timer_reset(tim, tim->expire + tim->period, 930 tim->period, this_lcore, tim->f, tim->arg, 1, 931 data); 932 rte_spinlock_unlock( 933 &data->priv_timer[this_lcore].list_lock); 934 } 935 936 data->priv_timer[this_lcore].running_tim = NULL; 937 } 938 939 return 0; 940 } 941 942 /* Walk pending lists, stopping timers and calling user-specified function */ 943 int 944 rte_timer_stop_all(uint32_t timer_data_id, unsigned int *walk_lcores, 945 int nb_walk_lcores, 946 rte_timer_stop_all_cb_t f, void *f_arg) 947 { 948 int i; 949 struct priv_timer *priv_timer; 950 uint32_t walk_lcore; 951 struct rte_timer *tim, *next_tim; 952 struct rte_timer_data *timer_data; 953 954 TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL); 955 956 for (i = 0; i < nb_walk_lcores; i++) { 957 walk_lcore = walk_lcores[i]; 958 priv_timer = &timer_data->priv_timer[walk_lcore]; 959 960 rte_spinlock_lock(&priv_timer->list_lock); 961 962 for (tim = priv_timer->pending_head.sl_next[0]; 963 tim != NULL; 964 tim = next_tim) { 965 next_tim = tim->sl_next[0]; 966 967 /* Call timer_stop with lock held */ 968 __rte_timer_stop(tim, 1, timer_data); 969 970 if (f) 971 f(tim, f_arg); 972 } 973 974 rte_spinlock_unlock(&priv_timer->list_lock); 975 } 976 977 return 0; 978 } 979 980 /* dump statistics about timers */ 981 static void 982 __rte_timer_dump_stats(struct rte_timer_data *timer_data __rte_unused, FILE *f) 983 { 984 #ifdef RTE_LIBRTE_TIMER_DEBUG 985 struct rte_timer_debug_stats sum; 986 unsigned lcore_id; 987 struct priv_timer *priv_timer = timer_data->priv_timer; 988 989 memset(&sum, 0, sizeof(sum)); 990 for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id++) { 991 sum.reset += priv_timer[lcore_id].stats.reset; 992 sum.stop += priv_timer[lcore_id].stats.stop; 993 sum.manage += priv_timer[lcore_id].stats.manage; 994 sum.pending += priv_timer[lcore_id].stats.pending; 995 } 996 fprintf(f, "Timer statistics:\n"); 997 fprintf(f, " reset = %"PRIu64"\n", sum.reset); 998 fprintf(f, " stop = %"PRIu64"\n", sum.stop); 999 fprintf(f, " manage = %"PRIu64"\n", sum.manage); 1000 fprintf(f, " pending = %"PRIu64"\n", sum.pending); 1001 #else 1002 fprintf(f, "No timer statistics, RTE_LIBRTE_TIMER_DEBUG is disabled\n"); 1003 #endif 1004 } 1005 1006 int 1007 rte_timer_dump_stats(FILE *f) 1008 { 1009 return rte_timer_alt_dump_stats(default_data_id, f); 1010 } 1011 1012 int 1013 rte_timer_alt_dump_stats(uint32_t timer_data_id __rte_unused, FILE *f) 1014 { 1015 struct rte_timer_data *timer_data; 1016 1017 TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL); 1018 1019 __rte_timer_dump_stats(timer_data, f); 1020 1021 return 0; 1022 } 1023