11f5a2479SJohn Stultz /* 21f5a2479SJohn Stultz * Generic Timer-queue 31f5a2479SJohn Stultz * 41f5a2479SJohn Stultz * Manages a simple queue of timers, ordered by expiration time. 51f5a2479SJohn Stultz * Uses rbtrees for quick list adds and expiration. 61f5a2479SJohn Stultz * 71f5a2479SJohn Stultz * NOTE: All of the following functions need to be serialized 825985edcSLucas De Marchi * to avoid races. No locking is done by this library code. 91f5a2479SJohn Stultz * 101f5a2479SJohn Stultz * This program is free software; you can redistribute it and/or modify 111f5a2479SJohn Stultz * it under the terms of the GNU General Public License as published by 121f5a2479SJohn Stultz * the Free Software Foundation; either version 2 of the License, or 131f5a2479SJohn Stultz * (at your option) any later version. 141f5a2479SJohn Stultz * 151f5a2479SJohn Stultz * This program is distributed in the hope that it will be useful, 161f5a2479SJohn Stultz * but WITHOUT ANY WARRANTY; without even the implied warranty of 171f5a2479SJohn Stultz * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 181f5a2479SJohn Stultz * GNU General Public License for more details. 191f5a2479SJohn Stultz * 201f5a2479SJohn Stultz * You should have received a copy of the GNU General Public License 211f5a2479SJohn Stultz * along with this program; if not, write to the Free Software 221f5a2479SJohn Stultz * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 231f5a2479SJohn Stultz */ 241f5a2479SJohn Stultz 2550af5eadSPaul Gortmaker #include <linux/bug.h> 261f5a2479SJohn Stultz #include <linux/timerqueue.h> 271f5a2479SJohn Stultz #include <linux/rbtree.h> 288bc3bcc9SPaul Gortmaker #include <linux/export.h> 291f5a2479SJohn Stultz 301f5a2479SJohn Stultz /** 311f5a2479SJohn Stultz * timerqueue_add - Adds timer to timerqueue. 321f5a2479SJohn Stultz * 331f5a2479SJohn Stultz * @head: head of timerqueue 341f5a2479SJohn Stultz * @node: timer node to be added 351f5a2479SJohn Stultz * 36*9f4533cdSThomas Gleixner * Adds the timer node to the timerqueue, sorted by the node's expires 37*9f4533cdSThomas Gleixner * value. Returns true if the newly added timer is the first expiring timer in 38*9f4533cdSThomas Gleixner * the queue. 391f5a2479SJohn Stultz */ 40c320642eSThomas Gleixner bool timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node) 411f5a2479SJohn Stultz { 421f5a2479SJohn Stultz struct rb_node **p = &head->head.rb_node; 431f5a2479SJohn Stultz struct rb_node *parent = NULL; 441f5a2479SJohn Stultz struct timerqueue_node *ptr; 451f5a2479SJohn Stultz 461f5a2479SJohn Stultz /* Make sure we don't add nodes that are already added */ 471f5a2479SJohn Stultz WARN_ON_ONCE(!RB_EMPTY_NODE(&node->node)); 481f5a2479SJohn Stultz 491f5a2479SJohn Stultz while (*p) { 501f5a2479SJohn Stultz parent = *p; 511f5a2479SJohn Stultz ptr = rb_entry(parent, struct timerqueue_node, node); 522456e855SThomas Gleixner if (node->expires < ptr->expires) 531f5a2479SJohn Stultz p = &(*p)->rb_left; 541f5a2479SJohn Stultz else 551f5a2479SJohn Stultz p = &(*p)->rb_right; 561f5a2479SJohn Stultz } 571f5a2479SJohn Stultz rb_link_node(&node->node, parent, p); 581f5a2479SJohn Stultz rb_insert_color(&node->node, &head->head); 591f5a2479SJohn Stultz 602456e855SThomas Gleixner if (!head->next || node->expires < head->next->expires) { 611f5a2479SJohn Stultz head->next = node; 62c320642eSThomas Gleixner return true; 63c320642eSThomas Gleixner } 64c320642eSThomas Gleixner return false; 651f5a2479SJohn Stultz } 669bb99b14SJohn Stultz EXPORT_SYMBOL_GPL(timerqueue_add); 671f5a2479SJohn Stultz 681f5a2479SJohn Stultz /** 691f5a2479SJohn Stultz * timerqueue_del - Removes a timer from the timerqueue. 701f5a2479SJohn Stultz * 711f5a2479SJohn Stultz * @head: head of timerqueue 721f5a2479SJohn Stultz * @node: timer node to be removed 731f5a2479SJohn Stultz * 74*9f4533cdSThomas Gleixner * Removes the timer node from the timerqueue. Returns true if the queue is 75*9f4533cdSThomas Gleixner * not empty after the remove. 761f5a2479SJohn Stultz */ 77c320642eSThomas Gleixner bool timerqueue_del(struct timerqueue_head *head, struct timerqueue_node *node) 781f5a2479SJohn Stultz { 791f5a2479SJohn Stultz WARN_ON_ONCE(RB_EMPTY_NODE(&node->node)); 801f5a2479SJohn Stultz 811f5a2479SJohn Stultz /* update next pointer */ 821f5a2479SJohn Stultz if (head->next == node) { 831f5a2479SJohn Stultz struct rb_node *rbn = rb_next(&node->node); 841f5a2479SJohn Stultz 85d852d394SGeliang Tang head->next = rb_entry_safe(rbn, struct timerqueue_node, node); 861f5a2479SJohn Stultz } 871f5a2479SJohn Stultz rb_erase(&node->node, &head->head); 881f5a2479SJohn Stultz RB_CLEAR_NODE(&node->node); 89c320642eSThomas Gleixner return head->next != NULL; 901f5a2479SJohn Stultz } 919bb99b14SJohn Stultz EXPORT_SYMBOL_GPL(timerqueue_del); 921f5a2479SJohn Stultz 931f5a2479SJohn Stultz /** 941f5a2479SJohn Stultz * timerqueue_iterate_next - Returns the timer after the provided timer 951f5a2479SJohn Stultz * 961f5a2479SJohn Stultz * @node: Pointer to a timer. 971f5a2479SJohn Stultz * 981f5a2479SJohn Stultz * Provides the timer that is after the given node. This is used, when 991f5a2479SJohn Stultz * necessary, to iterate through the list of timers in a timer list 1001f5a2479SJohn Stultz * without modifying the list. 1011f5a2479SJohn Stultz */ 1021f5a2479SJohn Stultz struct timerqueue_node *timerqueue_iterate_next(struct timerqueue_node *node) 1031f5a2479SJohn Stultz { 1041f5a2479SJohn Stultz struct rb_node *next; 1051f5a2479SJohn Stultz 1061f5a2479SJohn Stultz if (!node) 1071f5a2479SJohn Stultz return NULL; 1081f5a2479SJohn Stultz next = rb_next(&node->node); 1091f5a2479SJohn Stultz if (!next) 1101f5a2479SJohn Stultz return NULL; 1111f5a2479SJohn Stultz return container_of(next, struct timerqueue_node, node); 1121f5a2479SJohn Stultz } 1139bb99b14SJohn Stultz EXPORT_SYMBOL_GPL(timerqueue_iterate_next); 114