1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Descending-priority-sorted double-linked list
7 * (C) 2002-2003 Intel Corp
8 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
10 * 2001-2005 (c) MontaVista Software, Inc.
11 * Daniel Walker <dwalker@mvista.com>
13 * (C) 2005 Thomas Gleixner <tglx@linutronix.de>
15 * Simplifications of the original code by
16 * Oleg Nesterov <oleg@tv-sign.ru>
18 * Based on simple lists (include/linux/list.h).
20 * This file contains the add / del functions which are considered to
21 * be too large to inline. See include/linux/plist.h for further
25 #include <linux/bug.h>
26 #include <linux/plist.h>
28 #ifdef CONFIG_DEBUG_PLIST
30 static struct plist_head test_head
;
32 static void plist_check_prev_next(struct list_head
*t
, struct list_head
*p
,
35 WARN(n
->prev
!= p
|| p
->next
!= n
,
36 "top: %p, n: %p, p: %p\n"
37 "prev: %p, n: %p, p: %p\n"
38 "next: %p, n: %p, p: %p\n",
44 static void plist_check_list(struct list_head
*top
)
46 struct list_head
*prev
= top
, *next
= top
->next
;
48 plist_check_prev_next(top
, prev
, next
);
50 WRITE_ONCE(prev
, next
);
51 WRITE_ONCE(next
, prev
->next
);
52 plist_check_prev_next(top
, prev
, next
);
56 static void plist_check_head(struct plist_head
*head
)
58 if (!plist_head_empty(head
))
59 plist_check_list(&plist_first(head
)->prio_list
);
60 plist_check_list(&head
->node_list
);
64 # define plist_check_head(h) do { } while (0)
68 * plist_add - add @node to @head
70 * @node: &struct plist_node pointer
71 * @head: &struct plist_head pointer
73 void plist_add(struct plist_node
*node
, struct plist_head
*head
)
75 struct plist_node
*first
, *iter
, *prev
= NULL
, *last
, *reverse_iter
;
76 struct list_head
*node_next
= &head
->node_list
;
78 plist_check_head(head
);
79 WARN_ON(!plist_node_empty(node
));
80 WARN_ON(!list_empty(&node
->prio_list
));
82 if (plist_head_empty(head
))
85 first
= iter
= plist_first(head
);
86 last
= reverse_iter
= list_entry(first
->prio_list
.prev
, struct plist_node
, prio_list
);
89 if (node
->prio
< iter
->prio
) {
90 node_next
= &iter
->node_list
;
92 } else if (node
->prio
>= reverse_iter
->prio
) {
94 iter
= list_entry(reverse_iter
->prio_list
.next
,
95 struct plist_node
, prio_list
);
96 if (likely(reverse_iter
!= last
))
97 node_next
= &iter
->node_list
;
102 iter
= list_entry(iter
->prio_list
.next
,
103 struct plist_node
, prio_list
);
104 reverse_iter
= list_entry(reverse_iter
->prio_list
.prev
,
105 struct plist_node
, prio_list
);
106 } while (iter
!= first
);
108 if (!prev
|| prev
->prio
!= node
->prio
)
109 list_add_tail(&node
->prio_list
, &iter
->prio_list
);
111 list_add_tail(&node
->node_list
, node_next
);
113 plist_check_head(head
);
117 * plist_del - Remove a @node from plist.
119 * @node: &struct plist_node pointer - entry to be removed
120 * @head: &struct plist_head pointer - list head
122 void plist_del(struct plist_node
*node
, struct plist_head
*head
)
124 plist_check_head(head
);
126 if (!list_empty(&node
->prio_list
)) {
127 if (node
->node_list
.next
!= &head
->node_list
) {
128 struct plist_node
*next
;
130 next
= list_entry(node
->node_list
.next
,
131 struct plist_node
, node_list
);
133 /* add the next plist_node into prio_list */
134 if (list_empty(&next
->prio_list
))
135 list_add(&next
->prio_list
, &node
->prio_list
);
137 list_del_init(&node
->prio_list
);
140 list_del_init(&node
->node_list
);
142 plist_check_head(head
);
146 * plist_requeue - Requeue @node at end of same-prio entries.
148 * This is essentially an optimized plist_del() followed by
149 * plist_add(). It moves an entry already in the plist to
150 * after any other same-priority entries.
152 * @node: &struct plist_node pointer - entry to be moved
153 * @head: &struct plist_head pointer - list head
155 void plist_requeue(struct plist_node
*node
, struct plist_head
*head
)
157 struct plist_node
*iter
;
158 struct list_head
*node_next
= &head
->node_list
;
160 plist_check_head(head
);
161 BUG_ON(plist_head_empty(head
));
162 BUG_ON(plist_node_empty(node
));
164 if (node
== plist_last(head
))
167 iter
= plist_next(node
);
169 if (node
->prio
!= iter
->prio
)
172 plist_del(node
, head
);
174 plist_for_each_continue(iter
, head
) {
175 if (node
->prio
!= iter
->prio
) {
176 node_next
= &iter
->node_list
;
180 list_add_tail(&node
->node_list
, node_next
);
182 plist_check_head(head
);
185 #ifdef CONFIG_DEBUG_PLIST
186 #include <linux/sched.h>
187 #include <linux/sched/clock.h>
188 #include <linux/module.h>
189 #include <linux/init.h>
191 static struct plist_node __initdata test_node
[241];
193 static void __init
plist_test_check(int nr_expect
)
195 struct plist_node
*first
, *prio_pos
, *node_pos
;
197 if (plist_head_empty(&test_head
)) {
198 BUG_ON(nr_expect
!= 0);
202 prio_pos
= first
= plist_first(&test_head
);
203 plist_for_each(node_pos
, &test_head
) {
206 if (node_pos
== first
)
208 if (node_pos
->prio
== prio_pos
->prio
) {
209 BUG_ON(!list_empty(&node_pos
->prio_list
));
213 BUG_ON(prio_pos
->prio
> node_pos
->prio
);
214 BUG_ON(prio_pos
->prio_list
.next
!= &node_pos
->prio_list
);
218 BUG_ON(nr_expect
!= 0);
219 BUG_ON(prio_pos
->prio_list
.next
!= &first
->prio_list
);
222 static void __init
plist_test_requeue(struct plist_node
*node
)
224 plist_requeue(node
, &test_head
);
226 if (node
!= plist_last(&test_head
))
227 BUG_ON(node
->prio
== plist_next(node
)->prio
);
230 static int __init
plist_test(void)
232 int nr_expect
= 0, i
, loop
;
233 unsigned int r
= local_clock();
235 printk(KERN_DEBUG
"start plist test\n");
236 plist_head_init(&test_head
);
237 for (i
= 0; i
< ARRAY_SIZE(test_node
); i
++)
238 plist_node_init(test_node
+ i
, 0);
240 for (loop
= 0; loop
< 1000; loop
++) {
241 r
= r
* 193939 % 47629;
242 i
= r
% ARRAY_SIZE(test_node
);
243 if (plist_node_empty(test_node
+ i
)) {
244 r
= r
* 193939 % 47629;
245 test_node
[i
].prio
= r
% 99;
246 plist_add(test_node
+ i
, &test_head
);
249 plist_del(test_node
+ i
, &test_head
);
252 plist_test_check(nr_expect
);
253 if (!plist_node_empty(test_node
+ i
)) {
254 plist_test_requeue(test_node
+ i
);
255 plist_test_check(nr_expect
);
259 for (i
= 0; i
< ARRAY_SIZE(test_node
); i
++) {
260 if (plist_node_empty(test_node
+ i
))
262 plist_del(test_node
+ i
, &test_head
);
264 plist_test_check(nr_expect
);
267 printk(KERN_DEBUG
"end plist test\n");
269 /* Worst case test for plist_add() */
270 unsigned int test_data
[241];
272 for (i
= 0; i
< ARRAY_SIZE(test_data
); i
++)
275 ktime_t start
, end
, time_elapsed
= 0;
277 plist_head_init(&test_head
);
279 for (i
= 0; i
< ARRAY_SIZE(test_node
); i
++) {
280 plist_node_init(test_node
+ i
, 0);
281 test_node
[i
].prio
= test_data
[i
];
284 for (i
= 0; i
< ARRAY_SIZE(test_node
); i
++) {
285 if (plist_node_empty(test_node
+ i
)) {
287 plist_add(test_node
+ i
, &test_head
);
289 time_elapsed
+= (end
- start
);
293 pr_debug("plist_add worst case test time elapsed %lld\n", time_elapsed
);
297 module_init(plist_test
);