Blame view

lib/plist.c 5.9 KB
aded9cb87   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   * lib/plist.c
   *
   * Descending-priority-sorted double-linked list
   *
   * (C) 2002-2003 Intel Corp
   * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>.
   *
   * 2001-2005 (c) MontaVista Software, Inc.
   * Daniel Walker <dwalker@mvista.com>
   *
   * (C) 2005 Thomas Gleixner <tglx@linutronix.de>
   *
   * Simplifications of the original code by
   * Oleg Nesterov <oleg@tv-sign.ru>
   *
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
18
19
20
21
22
23
   * Based on simple lists (include/linux/list.h).
   *
   * This file contains the add / del functions which are considered to
   * be too large to inline. See include/linux/plist.h for further
   * information.
   */
50af5ead3   Paul Gortmaker   bug.h: add includ...
24
  #include <linux/bug.h>
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
25
  #include <linux/plist.h>
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
26

8e18faeac   Davidlohr Bueso   lib/plist: rename...
27
  #ifdef CONFIG_DEBUG_PLIST
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
28

6d55da53d   Lai Jiangshan   plist: Add priori...
29
  static struct plist_head test_head;
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
30
31
32
  static void plist_check_prev_next(struct list_head *t, struct list_head *p,
  				  struct list_head *n)
  {
5cd2b459d   Arjan van de Ven   Use WARN() in lib/
33
34
35
36
37
38
39
40
41
42
  	WARN(n->prev != p || p->next != n,
  			"top: %p, n: %p, p: %p
  "
  			"prev: %p, n: %p, p: %p
  "
  			"next: %p, n: %p, p: %p
  ",
  			 t, t->next, t->prev,
  			p, p->next, p->prev,
  			n, n->next, n->prev);
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  }
  
  static void plist_check_list(struct list_head *top)
  {
  	struct list_head *prev = top, *next = top->next;
  
  	plist_check_prev_next(top, prev, next);
  	while (next != top) {
  		prev = next;
  		next = prev->next;
  		plist_check_prev_next(top, prev, next);
  	}
  }
  
  static void plist_check_head(struct plist_head *head)
  {
bf6a9b833   Lai Jiangshan   plist: Shrink str...
59
60
  	if (!plist_head_empty(head))
  		plist_check_list(&plist_first(head)->prio_list);
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  	plist_check_list(&head->node_list);
  }
  
  #else
  # define plist_check_head(h)	do { } while (0)
  #endif
  
  /**
   * plist_add - add @node to @head
   *
   * @node:	&struct plist_node pointer
   * @head:	&struct plist_head pointer
   */
  void plist_add(struct plist_node *node, struct plist_head *head)
  {
bf6a9b833   Lai Jiangshan   plist: Shrink str...
76
77
  	struct plist_node *first, *iter, *prev = NULL;
  	struct list_head *node_next = &head->node_list;
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
78
79
80
  
  	plist_check_head(head);
  	WARN_ON(!plist_node_empty(node));
bf6a9b833   Lai Jiangshan   plist: Shrink str...
81
  	WARN_ON(!list_empty(&node->prio_list));
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
82

bf6a9b833   Lai Jiangshan   plist: Shrink str...
83
84
85
86
87
88
89
90
91
  	if (plist_head_empty(head))
  		goto ins_node;
  
  	first = iter = plist_first(head);
  
  	do {
  		if (node->prio < iter->prio) {
  			node_next = &iter->node_list;
  			break;
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
92
  		}
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
93

bf6a9b833   Lai Jiangshan   plist: Shrink str...
94
95
96
97
98
99
100
101
102
  		prev = iter;
  		iter = list_entry(iter->prio_list.next,
  				struct plist_node, prio_list);
  	} while (iter != first);
  
  	if (!prev || prev->prio != node->prio)
  		list_add_tail(&node->prio_list, &iter->prio_list);
  ins_node:
  	list_add_tail(&node->node_list, node_next);
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
103
104
105
106
107
108
109
110
111
112
113
114
115
  
  	plist_check_head(head);
  }
  
  /**
   * plist_del - Remove a @node from plist.
   *
   * @node:	&struct plist_node pointer - entry to be removed
   * @head:	&struct plist_head pointer - list head
   */
  void plist_del(struct plist_node *node, struct plist_head *head)
  {
  	plist_check_head(head);
bf6a9b833   Lai Jiangshan   plist: Shrink str...
116
117
118
119
120
121
  	if (!list_empty(&node->prio_list)) {
  		if (node->node_list.next != &head->node_list) {
  			struct plist_node *next;
  
  			next = list_entry(node->node_list.next,
  					struct plist_node, node_list);
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
122

bf6a9b833   Lai Jiangshan   plist: Shrink str...
123
124
125
126
127
  			/* add the next plist_node into prio_list */
  			if (list_empty(&next->prio_list))
  				list_add(&next->prio_list, &node->prio_list);
  		}
  		list_del_init(&node->prio_list);
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
128
  	}
bf6a9b833   Lai Jiangshan   plist: Shrink str...
129
  	list_del_init(&node->node_list);
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
130
131
132
  
  	plist_check_head(head);
  }
6d55da53d   Lai Jiangshan   plist: Add priori...
133

a75f232ce   Dan Streetman   lib/plist: add pl...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  /**
   * plist_requeue - Requeue @node at end of same-prio entries.
   *
   * This is essentially an optimized plist_del() followed by
   * plist_add().  It moves an entry already in the plist to
   * after any other same-priority entries.
   *
   * @node:	&struct plist_node pointer - entry to be moved
   * @head:	&struct plist_head pointer - list head
   */
  void plist_requeue(struct plist_node *node, struct plist_head *head)
  {
  	struct plist_node *iter;
  	struct list_head *node_next = &head->node_list;
  
  	plist_check_head(head);
  	BUG_ON(plist_head_empty(head));
  	BUG_ON(plist_node_empty(node));
  
  	if (node == plist_last(head))
  		return;
  
  	iter = plist_next(node);
  
  	if (node->prio != iter->prio)
  		return;
  
  	plist_del(node, head);
  
  	plist_for_each_continue(iter, head) {
  		if (node->prio != iter->prio) {
  			node_next = &iter->node_list;
  			break;
  		}
  	}
  	list_add_tail(&node->node_list, node_next);
  
  	plist_check_head(head);
  }
8e18faeac   Davidlohr Bueso   lib/plist: rename...
173
  #ifdef CONFIG_DEBUG_PLIST
6d55da53d   Lai Jiangshan   plist: Add priori...
174
  #include <linux/sched.h>
e60175710   Ingo Molnar   sched/headers: Pr...
175
  #include <linux/sched/clock.h>
6d55da53d   Lai Jiangshan   plist: Add priori...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  #include <linux/module.h>
  #include <linux/init.h>
  
  static struct plist_node __initdata test_node[241];
  
  static void __init plist_test_check(int nr_expect)
  {
  	struct plist_node *first, *prio_pos, *node_pos;
  
  	if (plist_head_empty(&test_head)) {
  		BUG_ON(nr_expect != 0);
  		return;
  	}
  
  	prio_pos = first = plist_first(&test_head);
  	plist_for_each(node_pos, &test_head) {
  		if (nr_expect-- < 0)
  			break;
  		if (node_pos == first)
  			continue;
  		if (node_pos->prio == prio_pos->prio) {
  			BUG_ON(!list_empty(&node_pos->prio_list));
  			continue;
  		}
  
  		BUG_ON(prio_pos->prio > node_pos->prio);
  		BUG_ON(prio_pos->prio_list.next != &node_pos->prio_list);
  		prio_pos = node_pos;
  	}
  
  	BUG_ON(nr_expect != 0);
  	BUG_ON(prio_pos->prio_list.next != &first->prio_list);
  }
a75f232ce   Dan Streetman   lib/plist: add pl...
209
210
211
212
213
214
215
  static void __init plist_test_requeue(struct plist_node *node)
  {
  	plist_requeue(node, &test_head);
  
  	if (node != plist_last(&test_head))
  		BUG_ON(node->prio == plist_next(node)->prio);
  }
6d55da53d   Lai Jiangshan   plist: Add priori...
216
217
218
219
  static int  __init plist_test(void)
  {
  	int nr_expect = 0, i, loop;
  	unsigned int r = local_clock();
181206279   Dan Streetman   lib/plist.c: repl...
220
221
  	printk(KERN_DEBUG "start plist test
  ");
732375c6a   Dima Zavin   plist: Remove the...
222
  	plist_head_init(&test_head);
6d55da53d   Lai Jiangshan   plist: Add priori...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  	for (i = 0; i < ARRAY_SIZE(test_node); i++)
  		plist_node_init(test_node + i, 0);
  
  	for (loop = 0; loop < 1000; loop++) {
  		r = r * 193939 % 47629;
  		i = r % ARRAY_SIZE(test_node);
  		if (plist_node_empty(test_node + i)) {
  			r = r * 193939 % 47629;
  			test_node[i].prio = r % 99;
  			plist_add(test_node + i, &test_head);
  			nr_expect++;
  		} else {
  			plist_del(test_node + i, &test_head);
  			nr_expect--;
  		}
  		plist_test_check(nr_expect);
a75f232ce   Dan Streetman   lib/plist: add pl...
239
240
241
242
  		if (!plist_node_empty(test_node + i)) {
  			plist_test_requeue(test_node + i);
  			plist_test_check(nr_expect);
  		}
6d55da53d   Lai Jiangshan   plist: Add priori...
243
244
245
246
247
248
249
250
251
  	}
  
  	for (i = 0; i < ARRAY_SIZE(test_node); i++) {
  		if (plist_node_empty(test_node + i))
  			continue;
  		plist_del(test_node + i, &test_head);
  		nr_expect--;
  		plist_test_check(nr_expect);
  	}
181206279   Dan Streetman   lib/plist.c: repl...
252
253
  	printk(KERN_DEBUG "end plist test
  ");
6d55da53d   Lai Jiangshan   plist: Add priori...
254
255
256
257
258
259
  	return 0;
  }
  
  module_init(plist_test);
  
  #endif