162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * lib/plist.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Descending-priority-sorted double-linked list 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * (C) 2002-2003 Intel Corp 862306a36Sopenharmony_ci * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * 2001-2005 (c) MontaVista Software, Inc. 1162306a36Sopenharmony_ci * Daniel Walker <dwalker@mvista.com> 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * (C) 2005 Thomas Gleixner <tglx@linutronix.de> 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Simplifications of the original code by 1662306a36Sopenharmony_ci * Oleg Nesterov <oleg@tv-sign.ru> 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Based on simple lists (include/linux/list.h). 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * This file contains the add / del functions which are considered to 2162306a36Sopenharmony_ci * be too large to inline. See include/linux/plist.h for further 2262306a36Sopenharmony_ci * information. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <linux/bug.h> 2662306a36Sopenharmony_ci#include <linux/plist.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_PLIST 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic struct plist_head test_head; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic void plist_check_prev_next(struct list_head *t, struct list_head *p, 3362306a36Sopenharmony_ci struct list_head *n) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci WARN(n->prev != p || p->next != n, 3662306a36Sopenharmony_ci "top: %p, n: %p, p: %p\n" 3762306a36Sopenharmony_ci "prev: %p, n: %p, p: %p\n" 3862306a36Sopenharmony_ci "next: %p, n: %p, p: %p\n", 3962306a36Sopenharmony_ci t, t->next, t->prev, 4062306a36Sopenharmony_ci p, p->next, p->prev, 4162306a36Sopenharmony_ci n, n->next, n->prev); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic void plist_check_list(struct list_head *top) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct list_head *prev = top, *next = top->next; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci plist_check_prev_next(top, prev, next); 4962306a36Sopenharmony_ci while (next != top) { 5062306a36Sopenharmony_ci prev = next; 5162306a36Sopenharmony_ci next = prev->next; 5262306a36Sopenharmony_ci plist_check_prev_next(top, prev, next); 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void plist_check_head(struct plist_head *head) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci if (!plist_head_empty(head)) 5962306a36Sopenharmony_ci plist_check_list(&plist_first(head)->prio_list); 6062306a36Sopenharmony_ci plist_check_list(&head->node_list); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#else 6462306a36Sopenharmony_ci# define plist_check_head(h) do { } while (0) 6562306a36Sopenharmony_ci#endif 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/** 6862306a36Sopenharmony_ci * plist_add - add @node to @head 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * @node: &struct plist_node pointer 7162306a36Sopenharmony_ci * @head: &struct plist_head pointer 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_civoid plist_add(struct plist_node *node, struct plist_head *head) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct plist_node *first, *iter, *prev = NULL; 7662306a36Sopenharmony_ci struct list_head *node_next = &head->node_list; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci plist_check_head(head); 7962306a36Sopenharmony_ci WARN_ON(!plist_node_empty(node)); 8062306a36Sopenharmony_ci WARN_ON(!list_empty(&node->prio_list)); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (plist_head_empty(head)) 8362306a36Sopenharmony_ci goto ins_node; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci first = iter = plist_first(head); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci do { 8862306a36Sopenharmony_ci if (node->prio < iter->prio) { 8962306a36Sopenharmony_ci node_next = &iter->node_list; 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci prev = iter; 9462306a36Sopenharmony_ci iter = list_entry(iter->prio_list.next, 9562306a36Sopenharmony_ci struct plist_node, prio_list); 9662306a36Sopenharmony_ci } while (iter != first); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (!prev || prev->prio != node->prio) 9962306a36Sopenharmony_ci list_add_tail(&node->prio_list, &iter->prio_list); 10062306a36Sopenharmony_ciins_node: 10162306a36Sopenharmony_ci list_add_tail(&node->node_list, node_next); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci plist_check_head(head); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/** 10762306a36Sopenharmony_ci * plist_del - Remove a @node from plist. 10862306a36Sopenharmony_ci * 10962306a36Sopenharmony_ci * @node: &struct plist_node pointer - entry to be removed 11062306a36Sopenharmony_ci * @head: &struct plist_head pointer - list head 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_civoid plist_del(struct plist_node *node, struct plist_head *head) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci plist_check_head(head); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (!list_empty(&node->prio_list)) { 11762306a36Sopenharmony_ci if (node->node_list.next != &head->node_list) { 11862306a36Sopenharmony_ci struct plist_node *next; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci next = list_entry(node->node_list.next, 12162306a36Sopenharmony_ci struct plist_node, node_list); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* add the next plist_node into prio_list */ 12462306a36Sopenharmony_ci if (list_empty(&next->prio_list)) 12562306a36Sopenharmony_ci list_add(&next->prio_list, &node->prio_list); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci list_del_init(&node->prio_list); 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci list_del_init(&node->node_list); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci plist_check_head(head); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/** 13662306a36Sopenharmony_ci * plist_requeue - Requeue @node at end of same-prio entries. 13762306a36Sopenharmony_ci * 13862306a36Sopenharmony_ci * This is essentially an optimized plist_del() followed by 13962306a36Sopenharmony_ci * plist_add(). It moves an entry already in the plist to 14062306a36Sopenharmony_ci * after any other same-priority entries. 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * @node: &struct plist_node pointer - entry to be moved 14362306a36Sopenharmony_ci * @head: &struct plist_head pointer - list head 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_civoid plist_requeue(struct plist_node *node, struct plist_head *head) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct plist_node *iter; 14862306a36Sopenharmony_ci struct list_head *node_next = &head->node_list; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci plist_check_head(head); 15162306a36Sopenharmony_ci BUG_ON(plist_head_empty(head)); 15262306a36Sopenharmony_ci BUG_ON(plist_node_empty(node)); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (node == plist_last(head)) 15562306a36Sopenharmony_ci return; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci iter = plist_next(node); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (node->prio != iter->prio) 16062306a36Sopenharmony_ci return; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci plist_del(node, head); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci plist_for_each_continue(iter, head) { 16562306a36Sopenharmony_ci if (node->prio != iter->prio) { 16662306a36Sopenharmony_ci node_next = &iter->node_list; 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci list_add_tail(&node->node_list, node_next); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci plist_check_head(head); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_PLIST 17662306a36Sopenharmony_ci#include <linux/sched.h> 17762306a36Sopenharmony_ci#include <linux/sched/clock.h> 17862306a36Sopenharmony_ci#include <linux/module.h> 17962306a36Sopenharmony_ci#include <linux/init.h> 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic struct plist_node __initdata test_node[241]; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic void __init plist_test_check(int nr_expect) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct plist_node *first, *prio_pos, *node_pos; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (plist_head_empty(&test_head)) { 18862306a36Sopenharmony_ci BUG_ON(nr_expect != 0); 18962306a36Sopenharmony_ci return; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci prio_pos = first = plist_first(&test_head); 19362306a36Sopenharmony_ci plist_for_each(node_pos, &test_head) { 19462306a36Sopenharmony_ci if (nr_expect-- < 0) 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci if (node_pos == first) 19762306a36Sopenharmony_ci continue; 19862306a36Sopenharmony_ci if (node_pos->prio == prio_pos->prio) { 19962306a36Sopenharmony_ci BUG_ON(!list_empty(&node_pos->prio_list)); 20062306a36Sopenharmony_ci continue; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci BUG_ON(prio_pos->prio > node_pos->prio); 20462306a36Sopenharmony_ci BUG_ON(prio_pos->prio_list.next != &node_pos->prio_list); 20562306a36Sopenharmony_ci prio_pos = node_pos; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci BUG_ON(nr_expect != 0); 20962306a36Sopenharmony_ci BUG_ON(prio_pos->prio_list.next != &first->prio_list); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void __init plist_test_requeue(struct plist_node *node) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci plist_requeue(node, &test_head); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (node != plist_last(&test_head)) 21762306a36Sopenharmony_ci BUG_ON(node->prio == plist_next(node)->prio); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int __init plist_test(void) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci int nr_expect = 0, i, loop; 22362306a36Sopenharmony_ci unsigned int r = local_clock(); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci printk(KERN_DEBUG "start plist test\n"); 22662306a36Sopenharmony_ci plist_head_init(&test_head); 22762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(test_node); i++) 22862306a36Sopenharmony_ci plist_node_init(test_node + i, 0); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci for (loop = 0; loop < 1000; loop++) { 23162306a36Sopenharmony_ci r = r * 193939 % 47629; 23262306a36Sopenharmony_ci i = r % ARRAY_SIZE(test_node); 23362306a36Sopenharmony_ci if (plist_node_empty(test_node + i)) { 23462306a36Sopenharmony_ci r = r * 193939 % 47629; 23562306a36Sopenharmony_ci test_node[i].prio = r % 99; 23662306a36Sopenharmony_ci plist_add(test_node + i, &test_head); 23762306a36Sopenharmony_ci nr_expect++; 23862306a36Sopenharmony_ci } else { 23962306a36Sopenharmony_ci plist_del(test_node + i, &test_head); 24062306a36Sopenharmony_ci nr_expect--; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci plist_test_check(nr_expect); 24362306a36Sopenharmony_ci if (!plist_node_empty(test_node + i)) { 24462306a36Sopenharmony_ci plist_test_requeue(test_node + i); 24562306a36Sopenharmony_ci plist_test_check(nr_expect); 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(test_node); i++) { 25062306a36Sopenharmony_ci if (plist_node_empty(test_node + i)) 25162306a36Sopenharmony_ci continue; 25262306a36Sopenharmony_ci plist_del(test_node + i, &test_head); 25362306a36Sopenharmony_ci nr_expect--; 25462306a36Sopenharmony_ci plist_test_check(nr_expect); 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci printk(KERN_DEBUG "end plist test\n"); 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cimodule_init(plist_test); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci#endif 264