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 * 361f5a2479SJohn Stultz * Adds the timer node to the timerqueue, sorted by the 371f5a2479SJohn Stultz * node's expires value. 381f5a2479SJohn Stultz */ 39c320642eSThomas Gleixner bool timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node) 401f5a2479SJohn Stultz { 411f5a2479SJohn Stultz struct rb_node **p = &head->head.rb_node; 421f5a2479SJohn Stultz struct rb_node *parent = NULL; 431f5a2479SJohn Stultz struct timerqueue_node *ptr; 441f5a2479SJohn Stultz 451f5a2479SJohn Stultz /* Make sure we don't add nodes that are already added */ 461f5a2479SJohn Stultz WARN_ON_ONCE(!RB_EMPTY_NODE(&node->node)); 471f5a2479SJohn Stultz 481f5a2479SJohn Stultz while (*p) { 491f5a2479SJohn Stultz parent = *p; 501f5a2479SJohn Stultz ptr = rb_entry(parent, struct timerqueue_node, node); 51*2456e855SThomas Gleixner if (node->expires < ptr->expires) 521f5a2479SJohn Stultz p = &(*p)->rb_left; 531f5a2479SJohn Stultz else 541f5a2479SJohn Stultz p = &(*p)->rb_right; 551f5a2479SJohn Stultz } 561f5a2479SJohn Stultz rb_link_node(&node->node, parent, p); 571f5a2479SJohn Stultz rb_insert_color(&node->node, &head->head); 581f5a2479SJohn Stultz 59*2456e855SThomas Gleixner if (!head->next || node->expires < head->next->expires) { 601f5a2479SJohn Stultz head->next = node; 61c320642eSThomas Gleixner return true; 62c320642eSThomas Gleixner } 63c320642eSThomas Gleixner return false; 641f5a2479SJohn Stultz } 659bb99b14SJohn Stultz EXPORT_SYMBOL_GPL(timerqueue_add); 661f5a2479SJohn Stultz 671f5a2479SJohn Stultz /** 681f5a2479SJohn Stultz * timerqueue_del - Removes a timer from the timerqueue. 691f5a2479SJohn Stultz * 701f5a2479SJohn Stultz * @head: head of timerqueue 711f5a2479SJohn Stultz * @node: timer node to be removed 721f5a2479SJohn Stultz * 731f5a2479SJohn Stultz * Removes the timer node from the timerqueue. 741f5a2479SJohn Stultz */ 75c320642eSThomas Gleixner bool timerqueue_del(struct timerqueue_head *head, struct timerqueue_node *node) 761f5a2479SJohn Stultz { 771f5a2479SJohn Stultz WARN_ON_ONCE(RB_EMPTY_NODE(&node->node)); 781f5a2479SJohn Stultz 791f5a2479SJohn Stultz /* update next pointer */ 801f5a2479SJohn Stultz if (head->next == node) { 811f5a2479SJohn Stultz struct rb_node *rbn = rb_next(&node->node); 821f5a2479SJohn Stultz 831f5a2479SJohn Stultz head->next = rbn ? 841f5a2479SJohn Stultz rb_entry(rbn, struct timerqueue_node, node) : NULL; 851f5a2479SJohn Stultz } 861f5a2479SJohn Stultz rb_erase(&node->node, &head->head); 871f5a2479SJohn Stultz RB_CLEAR_NODE(&node->node); 88c320642eSThomas Gleixner return head->next != NULL; 891f5a2479SJohn Stultz } 909bb99b14SJohn Stultz EXPORT_SYMBOL_GPL(timerqueue_del); 911f5a2479SJohn Stultz 921f5a2479SJohn Stultz /** 931f5a2479SJohn Stultz * timerqueue_iterate_next - Returns the timer after the provided timer 941f5a2479SJohn Stultz * 951f5a2479SJohn Stultz * @node: Pointer to a timer. 961f5a2479SJohn Stultz * 971f5a2479SJohn Stultz * Provides the timer that is after the given node. This is used, when 981f5a2479SJohn Stultz * necessary, to iterate through the list of timers in a timer list 991f5a2479SJohn Stultz * without modifying the list. 1001f5a2479SJohn Stultz */ 1011f5a2479SJohn Stultz struct timerqueue_node *timerqueue_iterate_next(struct timerqueue_node *node) 1021f5a2479SJohn Stultz { 1031f5a2479SJohn Stultz struct rb_node *next; 1041f5a2479SJohn Stultz 1051f5a2479SJohn Stultz if (!node) 1061f5a2479SJohn Stultz return NULL; 1071f5a2479SJohn Stultz next = rb_next(&node->node); 1081f5a2479SJohn Stultz if (!next) 1091f5a2479SJohn Stultz return NULL; 1101f5a2479SJohn Stultz return container_of(next, struct timerqueue_node, node); 1111f5a2479SJohn Stultz } 1129bb99b14SJohn Stultz EXPORT_SYMBOL_GPL(timerqueue_iterate_next); 113