11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21f5a2479SJohn Stultz /* 31f5a2479SJohn Stultz * Generic Timer-queue 41f5a2479SJohn Stultz * 51f5a2479SJohn Stultz * Manages a simple queue of timers, ordered by expiration time. 61f5a2479SJohn Stultz * Uses rbtrees for quick list adds and expiration. 71f5a2479SJohn Stultz * 81f5a2479SJohn Stultz * NOTE: All of the following functions need to be serialized 925985edcSLucas De Marchi * to avoid races. No locking is done by this library code. 101f5a2479SJohn Stultz */ 111f5a2479SJohn Stultz 1250af5eadSPaul Gortmaker #include <linux/bug.h> 131f5a2479SJohn Stultz #include <linux/timerqueue.h> 141f5a2479SJohn Stultz #include <linux/rbtree.h> 158bc3bcc9SPaul Gortmaker #include <linux/export.h> 161f5a2479SJohn Stultz 171f5a2479SJohn Stultz /** 181f5a2479SJohn Stultz * timerqueue_add - Adds timer to timerqueue. 191f5a2479SJohn Stultz * 201f5a2479SJohn Stultz * @head: head of timerqueue 211f5a2479SJohn Stultz * @node: timer node to be added 221f5a2479SJohn Stultz * 239f4533cdSThomas Gleixner * Adds the timer node to the timerqueue, sorted by the node's expires 249f4533cdSThomas Gleixner * value. Returns true if the newly added timer is the first expiring timer in 259f4533cdSThomas Gleixner * the queue. 261f5a2479SJohn Stultz */ 27c320642eSThomas Gleixner bool timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node) 281f5a2479SJohn Stultz { 29*511885d7SDavidlohr Bueso struct rb_node **p = &head->rb_root.rb_root.rb_node; 301f5a2479SJohn Stultz struct rb_node *parent = NULL; 311f5a2479SJohn Stultz struct timerqueue_node *ptr; 32*511885d7SDavidlohr Bueso bool leftmost = true; 331f5a2479SJohn Stultz 341f5a2479SJohn Stultz /* Make sure we don't add nodes that are already added */ 351f5a2479SJohn Stultz WARN_ON_ONCE(!RB_EMPTY_NODE(&node->node)); 361f5a2479SJohn Stultz 371f5a2479SJohn Stultz while (*p) { 381f5a2479SJohn Stultz parent = *p; 391f5a2479SJohn Stultz ptr = rb_entry(parent, struct timerqueue_node, node); 40*511885d7SDavidlohr Bueso if (node->expires < ptr->expires) { 411f5a2479SJohn Stultz p = &(*p)->rb_left; 42*511885d7SDavidlohr Bueso } else { 431f5a2479SJohn Stultz p = &(*p)->rb_right; 44*511885d7SDavidlohr Bueso leftmost = false; 45*511885d7SDavidlohr Bueso } 461f5a2479SJohn Stultz } 471f5a2479SJohn Stultz rb_link_node(&node->node, parent, p); 48*511885d7SDavidlohr Bueso rb_insert_color_cached(&node->node, &head->rb_root, leftmost); 491f5a2479SJohn Stultz 50*511885d7SDavidlohr Bueso return leftmost; 511f5a2479SJohn Stultz } 529bb99b14SJohn Stultz EXPORT_SYMBOL_GPL(timerqueue_add); 531f5a2479SJohn Stultz 541f5a2479SJohn Stultz /** 551f5a2479SJohn Stultz * timerqueue_del - Removes a timer from the timerqueue. 561f5a2479SJohn Stultz * 571f5a2479SJohn Stultz * @head: head of timerqueue 581f5a2479SJohn Stultz * @node: timer node to be removed 591f5a2479SJohn Stultz * 609f4533cdSThomas Gleixner * Removes the timer node from the timerqueue. Returns true if the queue is 619f4533cdSThomas Gleixner * not empty after the remove. 621f5a2479SJohn Stultz */ 63c320642eSThomas Gleixner bool timerqueue_del(struct timerqueue_head *head, struct timerqueue_node *node) 641f5a2479SJohn Stultz { 651f5a2479SJohn Stultz WARN_ON_ONCE(RB_EMPTY_NODE(&node->node)); 661f5a2479SJohn Stultz 67*511885d7SDavidlohr Bueso rb_erase_cached(&node->node, &head->rb_root); 681f5a2479SJohn Stultz RB_CLEAR_NODE(&node->node); 69*511885d7SDavidlohr Bueso 70*511885d7SDavidlohr Bueso return !RB_EMPTY_ROOT(&head->rb_root.rb_root); 711f5a2479SJohn Stultz } 729bb99b14SJohn Stultz EXPORT_SYMBOL_GPL(timerqueue_del); 731f5a2479SJohn Stultz 741f5a2479SJohn Stultz /** 751f5a2479SJohn Stultz * timerqueue_iterate_next - Returns the timer after the provided timer 761f5a2479SJohn Stultz * 771f5a2479SJohn Stultz * @node: Pointer to a timer. 781f5a2479SJohn Stultz * 791f5a2479SJohn Stultz * Provides the timer that is after the given node. This is used, when 801f5a2479SJohn Stultz * necessary, to iterate through the list of timers in a timer list 811f5a2479SJohn Stultz * without modifying the list. 821f5a2479SJohn Stultz */ 831f5a2479SJohn Stultz struct timerqueue_node *timerqueue_iterate_next(struct timerqueue_node *node) 841f5a2479SJohn Stultz { 851f5a2479SJohn Stultz struct rb_node *next; 861f5a2479SJohn Stultz 871f5a2479SJohn Stultz if (!node) 881f5a2479SJohn Stultz return NULL; 891f5a2479SJohn Stultz next = rb_next(&node->node); 901f5a2479SJohn Stultz if (!next) 911f5a2479SJohn Stultz return NULL; 921f5a2479SJohn Stultz return container_of(next, struct timerqueue_node, node); 931f5a2479SJohn Stultz } 949bb99b14SJohn Stultz EXPORT_SYMBOL_GPL(timerqueue_iterate_next); 95