Blame view

lib/plist.c 4.91 KB
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  /*
   * 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>
   *
   * Licensed under the FSF's GNU Public License v2 or later.
   *
   * 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.
   */
  
  #include <linux/plist.h>
  #include <linux/spinlock.h>
  
  #ifdef CONFIG_DEBUG_PI_LIST
6d55da53d   Lai Jiangshan   plist: Add priori...
30
  static struct plist_head test_head;
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
31
32
33
  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/
34
35
36
37
38
39
40
41
42
43
  	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:...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  }
  
  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)
  {
6d55da53d   Lai Jiangshan   plist: Add priori...
60
  	WARN_ON(head != &test_head && !head->rawlock && !head->spinlock);
a26724591   Thomas Gleixner   plist: Make plist...
61
62
63
64
  	if (head->rawlock)
  		WARN_ON_SMP(!raw_spin_is_locked(head->rawlock));
  	if (head->spinlock)
  		WARN_ON_SMP(!spin_is_locked(head->spinlock));
bf6a9b833   Lai Jiangshan   plist: Shrink str...
65
66
  	if (!plist_head_empty(head))
  		plist_check_list(&plist_first(head)->prio_list);
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  	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...
82
83
  	struct plist_node *first, *iter, *prev = NULL;
  	struct list_head *node_next = &head->node_list;
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
84
85
86
  
  	plist_check_head(head);
  	WARN_ON(!plist_node_empty(node));
bf6a9b833   Lai Jiangshan   plist: Shrink str...
87
  	WARN_ON(!list_empty(&node->prio_list));
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
88

bf6a9b833   Lai Jiangshan   plist: Shrink str...
89
90
91
92
93
94
95
96
97
  	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:...
98
  		}
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
99

bf6a9b833   Lai Jiangshan   plist: Shrink str...
100
101
102
103
104
105
106
107
108
  		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:...
109
110
111
112
113
114
115
116
117
118
119
120
121
  
  	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...
122
123
124
125
126
127
  	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:...
128

bf6a9b833   Lai Jiangshan   plist: Shrink str...
129
130
131
132
133
  			/* 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:...
134
  	}
bf6a9b833   Lai Jiangshan   plist: Shrink str...
135
  	list_del_init(&node->node_list);
77ba89c5c   Ingo Molnar   [PATCH] pi-futex:...
136
137
138
  
  	plist_check_head(head);
  }
6d55da53d   Lai Jiangshan   plist: Add priori...
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
173
174
175
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
209
210
211
212
213
214
215
216
217
  
  #ifdef CONFIG_DEBUG_PI_LIST
  #include <linux/sched.h>
  #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);
  }
  
  static int  __init plist_test(void)
  {
  	int nr_expect = 0, i, loop;
  	unsigned int r = local_clock();
  
  	printk(KERN_INFO "start plist test
  ");
  	plist_head_init(&test_head, NULL);
  	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);
  	}
  
  	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);
  	}
  
  	printk(KERN_INFO "end plist test
  ");
  	return 0;
  }
  
  module_init(plist_test);
  
  #endif