diff options
author | Ingo Molnar <mingo@elte.hu> | 2006-06-27 05:54:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-27 20:32:46 -0400 |
commit | 77ba89c5cf28d5d98a3cae17f67a3e42b102cc25 (patch) | |
tree | d487b536522574ab183cc600b62008c60db85b59 | |
parent | 8eb94f80dd2da5977c35cd094f0802c1501a12cd (diff) |
[PATCH] pi-futex: add plist implementation
Add the priority-sorted list (plist) implementation.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | include/linux/plist.h | 247 | ||||
-rw-r--r-- | lib/Kconfig | 6 | ||||
-rw-r--r-- | lib/Makefile | 1 | ||||
-rw-r--r-- | lib/plist.c | 118 |
4 files changed, 372 insertions, 0 deletions
diff --git a/include/linux/plist.h b/include/linux/plist.h new file mode 100644 index 000000000000..3404faef542c --- /dev/null +++ b/include/linux/plist.h | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * Descending-priority-sorted double-linked list | ||
3 | * | ||
4 | * (C) 2002-2003 Intel Corp | ||
5 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>. | ||
6 | * | ||
7 | * 2001-2005 (c) MontaVista Software, Inc. | ||
8 | * Daniel Walker <dwalker@mvista.com> | ||
9 | * | ||
10 | * (C) 2005 Thomas Gleixner <tglx@linutronix.de> | ||
11 | * | ||
12 | * Simplifications of the original code by | ||
13 | * Oleg Nesterov <oleg@tv-sign.ru> | ||
14 | * | ||
15 | * Licensed under the FSF's GNU Public License v2 or later. | ||
16 | * | ||
17 | * Based on simple lists (include/linux/list.h). | ||
18 | * | ||
19 | * This is a priority-sorted list of nodes; each node has a | ||
20 | * priority from INT_MIN (highest) to INT_MAX (lowest). | ||
21 | * | ||
22 | * Addition is O(K), removal is O(1), change of priority of a node is | ||
23 | * O(K) and K is the number of RT priority levels used in the system. | ||
24 | * (1 <= K <= 99) | ||
25 | * | ||
26 | * This list is really a list of lists: | ||
27 | * | ||
28 | * - The tier 1 list is the prio_list, different priority nodes. | ||
29 | * | ||
30 | * - The tier 2 list is the node_list, serialized nodes. | ||
31 | * | ||
32 | * Simple ASCII art explanation: | ||
33 | * | ||
34 | * |HEAD | | ||
35 | * | | | ||
36 | * |prio_list.prev|<------------------------------------| | ||
37 | * |prio_list.next|<->|pl|<->|pl|<--------------->|pl|<-| | ||
38 | * |10 | |10| |21| |21| |21| |40| (prio) | ||
39 | * | | | | | | | | | | | | | ||
40 | * | | | | | | | | | | | | | ||
41 | * |node_list.next|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-| | ||
42 | * |node_list.prev|<------------------------------------| | ||
43 | * | ||
44 | * The nodes on the prio_list list are sorted by priority to simplify | ||
45 | * the insertion of new nodes. There are no nodes with duplicate | ||
46 | * priorites on the list. | ||
47 | * | ||
48 | * The nodes on the node_list is ordered by priority and can contain | ||
49 | * entries which have the same priority. Those entries are ordered | ||
50 | * FIFO | ||
51 | * | ||
52 | * Addition means: look for the prio_list node in the prio_list | ||
53 | * for the priority of the node and insert it before the node_list | ||
54 | * entry of the next prio_list node. If it is the first node of | ||
55 | * that priority, add it to the prio_list in the right position and | ||
56 | * insert it into the serialized node_list list | ||
57 | * | ||
58 | * Removal means remove it from the node_list and remove it from | ||
59 | * the prio_list if the node_list list_head is non empty. In case | ||
60 | * of removal from the prio_list it must be checked whether other | ||
61 | * entries of the same priority are on the list or not. If there | ||
62 | * is another entry of the same priority then this entry has to | ||
63 | * replace the removed entry on the prio_list. If the entry which | ||
64 | * is removed is the only entry of this priority then a simple | ||
65 | * remove from both list is sufficient. | ||
66 | * | ||
67 | * INT_MIN is the highest priority, 0 is the medium highest, INT_MAX | ||
68 | * is lowest priority. | ||
69 | * | ||
70 | * No locking is done, up to the caller. | ||
71 | * | ||
72 | */ | ||
73 | #ifndef _LINUX_PLIST_H_ | ||
74 | #define _LINUX_PLIST_H_ | ||
75 | |||
76 | #include <linux/list.h> | ||
77 | #include <linux/spinlock_types.h> | ||
78 | |||
79 | struct plist_head { | ||
80 | struct list_head prio_list; | ||
81 | struct list_head node_list; | ||
82 | #ifdef CONFIG_DEBUG_PI_LIST | ||
83 | spinlock_t *lock; | ||
84 | #endif | ||
85 | }; | ||
86 | |||
87 | struct plist_node { | ||
88 | int prio; | ||
89 | struct plist_head plist; | ||
90 | }; | ||
91 | |||
92 | #ifdef CONFIG_DEBUG_PI_LIST | ||
93 | # define PLIST_HEAD_LOCK_INIT(_lock) .lock = _lock | ||
94 | #else | ||
95 | # define PLIST_HEAD_LOCK_INIT(_lock) | ||
96 | #endif | ||
97 | |||
98 | /** | ||
99 | * #PLIST_HEAD_INIT - static struct plist_head initializer | ||
100 | * | ||
101 | * @head: struct plist_head variable name | ||
102 | */ | ||
103 | #define PLIST_HEAD_INIT(head, _lock) \ | ||
104 | { \ | ||
105 | .prio_list = LIST_HEAD_INIT((head).prio_list), \ | ||
106 | .node_list = LIST_HEAD_INIT((head).node_list), \ | ||
107 | PLIST_HEAD_LOCK_INIT(&(_lock)) \ | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * #PLIST_NODE_INIT - static struct plist_node initializer | ||
112 | * | ||
113 | * @node: struct plist_node variable name | ||
114 | * @__prio: initial node priority | ||
115 | */ | ||
116 | #define PLIST_NODE_INIT(node, __prio) \ | ||
117 | { \ | ||
118 | .prio = (__prio), \ | ||
119 | .plist = PLIST_HEAD_INIT((node).plist, NULL), \ | ||
120 | } | ||
121 | |||
122 | /** | ||
123 | * plist_head_init - dynamic struct plist_head initializer | ||
124 | * | ||
125 | * @head: &struct plist_head pointer | ||
126 | */ | ||
127 | static inline void | ||
128 | plist_head_init(struct plist_head *head, spinlock_t *lock) | ||
129 | { | ||
130 | INIT_LIST_HEAD(&head->prio_list); | ||
131 | INIT_LIST_HEAD(&head->node_list); | ||
132 | #ifdef CONFIG_DEBUG_PI_LIST | ||
133 | head->lock = lock; | ||
134 | #endif | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * plist_node_init - Dynamic struct plist_node initializer | ||
139 | * | ||
140 | * @node: &struct plist_node pointer | ||
141 | * @prio: initial node priority | ||
142 | */ | ||
143 | static inline void plist_node_init(struct plist_node *node, int prio) | ||
144 | { | ||
145 | node->prio = prio; | ||
146 | plist_head_init(&node->plist, NULL); | ||
147 | } | ||
148 | |||
149 | extern void plist_add(struct plist_node *node, struct plist_head *head); | ||
150 | extern void plist_del(struct plist_node *node, struct plist_head *head); | ||
151 | |||
152 | /** | ||
153 | * plist_for_each - iterate over the plist | ||
154 | * | ||
155 | * @pos1: the type * to use as a loop counter. | ||
156 | * @head: the head for your list. | ||
157 | */ | ||
158 | #define plist_for_each(pos, head) \ | ||
159 | list_for_each_entry(pos, &(head)->node_list, plist.node_list) | ||
160 | |||
161 | /** | ||
162 | * plist_for_each_entry_safe - iterate over a plist of given type safe | ||
163 | * against removal of list entry | ||
164 | * | ||
165 | * @pos1: the type * to use as a loop counter. | ||
166 | * @n1: another type * to use as temporary storage | ||
167 | * @head: the head for your list. | ||
168 | */ | ||
169 | #define plist_for_each_safe(pos, n, head) \ | ||
170 | list_for_each_entry_safe(pos, n, &(head)->node_list, plist.node_list) | ||
171 | |||
172 | /** | ||
173 | * plist_for_each_entry - iterate over list of given type | ||
174 | * | ||
175 | * @pos: the type * to use as a loop counter. | ||
176 | * @head: the head for your list. | ||
177 | * @member: the name of the list_struct within the struct. | ||
178 | */ | ||
179 | #define plist_for_each_entry(pos, head, mem) \ | ||
180 | list_for_each_entry(pos, &(head)->node_list, mem.plist.node_list) | ||
181 | |||
182 | /** | ||
183 | * plist_for_each_entry_safe - iterate over list of given type safe against | ||
184 | * removal of list entry | ||
185 | * | ||
186 | * @pos: the type * to use as a loop counter. | ||
187 | * @n: another type * to use as temporary storage | ||
188 | * @head: the head for your list. | ||
189 | * @m: the name of the list_struct within the struct. | ||
190 | */ | ||
191 | #define plist_for_each_entry_safe(pos, n, head, m) \ | ||
192 | list_for_each_entry_safe(pos, n, &(head)->node_list, m.plist.node_list) | ||
193 | |||
194 | /** | ||
195 | * plist_head_empty - return !0 if a plist_head is empty | ||
196 | * | ||
197 | * @head: &struct plist_head pointer | ||
198 | */ | ||
199 | static inline int plist_head_empty(const struct plist_head *head) | ||
200 | { | ||
201 | return list_empty(&head->node_list); | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * plist_node_empty - return !0 if plist_node is not on a list | ||
206 | * | ||
207 | * @node: &struct plist_node pointer | ||
208 | */ | ||
209 | static inline int plist_node_empty(const struct plist_node *node) | ||
210 | { | ||
211 | return plist_head_empty(&node->plist); | ||
212 | } | ||
213 | |||
214 | /* All functions below assume the plist_head is not empty. */ | ||
215 | |||
216 | /** | ||
217 | * plist_first_entry - get the struct for the first entry | ||
218 | * | ||
219 | * @ptr: the &struct plist_head pointer. | ||
220 | * @type: the type of the struct this is embedded in. | ||
221 | * @member: the name of the list_struct within the struct. | ||
222 | */ | ||
223 | #ifdef CONFIG_DEBUG_PI_LIST | ||
224 | # define plist_first_entry(head, type, member) \ | ||
225 | ({ \ | ||
226 | WARN_ON(plist_head_empty(head)); \ | ||
227 | container_of(plist_first(head), type, member); \ | ||
228 | }) | ||
229 | #else | ||
230 | # define plist_first_entry(head, type, member) \ | ||
231 | container_of(plist_first(head), type, member) | ||
232 | #endif | ||
233 | |||
234 | /** | ||
235 | * plist_first - return the first node (and thus, highest priority) | ||
236 | * | ||
237 | * @head: the &struct plist_head pointer | ||
238 | * | ||
239 | * Assumes the plist is _not_ empty. | ||
240 | */ | ||
241 | static inline struct plist_node* plist_first(const struct plist_head *head) | ||
242 | { | ||
243 | return list_entry(head->node_list.next, | ||
244 | struct plist_node, plist.node_list); | ||
245 | } | ||
246 | |||
247 | #endif | ||
diff --git a/lib/Kconfig b/lib/Kconfig index 3de93357f5ab..f6299342b882 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
@@ -86,4 +86,10 @@ config TEXTSEARCH_BM | |||
86 | config TEXTSEARCH_FSM | 86 | config TEXTSEARCH_FSM |
87 | tristate | 87 | tristate |
88 | 88 | ||
89 | # | ||
90 | # plist support is select#ed if needed | ||
91 | # | ||
92 | config PLIST | ||
93 | boolean | ||
94 | |||
89 | endmenu | 95 | endmenu |
diff --git a/lib/Makefile b/lib/Makefile index 79358ad1f113..10c13c9d7824 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
@@ -25,6 +25,7 @@ lib-$(CONFIG_SEMAPHORE_SLEEPERS) += semaphore-sleepers.o | |||
25 | lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o | 25 | lib-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o |
26 | lib-$(CONFIG_GENERIC_HWEIGHT) += hweight.o | 26 | lib-$(CONFIG_GENERIC_HWEIGHT) += hweight.o |
27 | obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o | 27 | obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o |
28 | obj-$(CONFIG_PLIST) += plist.o | ||
28 | obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o | 29 | obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o |
29 | 30 | ||
30 | ifneq ($(CONFIG_HAVE_DEC_LOCK),y) | 31 | ifneq ($(CONFIG_HAVE_DEC_LOCK),y) |
diff --git a/lib/plist.c b/lib/plist.c new file mode 100644 index 000000000000..3074a02272f3 --- /dev/null +++ b/lib/plist.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * lib/plist.c | ||
3 | * | ||
4 | * Descending-priority-sorted double-linked list | ||
5 | * | ||
6 | * (C) 2002-2003 Intel Corp | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>. | ||
8 | * | ||
9 | * 2001-2005 (c) MontaVista Software, Inc. | ||
10 | * Daniel Walker <dwalker@mvista.com> | ||
11 | * | ||
12 | * (C) 2005 Thomas Gleixner <tglx@linutronix.de> | ||
13 | * | ||
14 | * Simplifications of the original code by | ||
15 | * Oleg Nesterov <oleg@tv-sign.ru> | ||
16 | * | ||
17 | * Licensed under the FSF's GNU Public License v2 or later. | ||
18 | * | ||
19 | * Based on simple lists (include/linux/list.h). | ||
20 | * | ||
21 | * This file contains the add / del functions which are considered to | ||
22 | * be too large to inline. See include/linux/plist.h for further | ||
23 | * information. | ||
24 | */ | ||
25 | |||
26 | #include <linux/plist.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | |||
29 | #ifdef CONFIG_DEBUG_PI_LIST | ||
30 | |||
31 | static void plist_check_prev_next(struct list_head *t, struct list_head *p, | ||
32 | struct list_head *n) | ||
33 | { | ||
34 | if (n->prev != p || p->next != n) { | ||
35 | printk("top: %p, n: %p, p: %p\n", t, t->next, t->prev); | ||
36 | printk("prev: %p, n: %p, p: %p\n", p, p->next, p->prev); | ||
37 | printk("next: %p, n: %p, p: %p\n", n, n->next, n->prev); | ||
38 | WARN_ON(1); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | static void plist_check_list(struct list_head *top) | ||
43 | { | ||
44 | struct list_head *prev = top, *next = top->next; | ||
45 | |||
46 | plist_check_prev_next(top, prev, next); | ||
47 | while (next != top) { | ||
48 | prev = next; | ||
49 | next = prev->next; | ||
50 | plist_check_prev_next(top, prev, next); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | static void plist_check_head(struct plist_head *head) | ||
55 | { | ||
56 | WARN_ON(!head->lock); | ||
57 | if (head->lock) | ||
58 | WARN_ON_SMP(!spin_is_locked(head->lock)); | ||
59 | plist_check_list(&head->prio_list); | ||
60 | plist_check_list(&head->node_list); | ||
61 | } | ||
62 | |||
63 | #else | ||
64 | # define plist_check_head(h) do { } while (0) | ||
65 | #endif | ||
66 | |||
67 | /** | ||
68 | * plist_add - add @node to @head | ||
69 | * | ||
70 | * @node: &struct plist_node pointer | ||
71 | * @head: &struct plist_head pointer | ||
72 | */ | ||
73 | void plist_add(struct plist_node *node, struct plist_head *head) | ||
74 | { | ||
75 | struct plist_node *iter; | ||
76 | |||
77 | plist_check_head(head); | ||
78 | WARN_ON(!plist_node_empty(node)); | ||
79 | |||
80 | list_for_each_entry(iter, &head->prio_list, plist.prio_list) { | ||
81 | if (node->prio < iter->prio) | ||
82 | goto lt_prio; | ||
83 | else if (node->prio == iter->prio) { | ||
84 | iter = list_entry(iter->plist.prio_list.next, | ||
85 | struct plist_node, plist.prio_list); | ||
86 | goto eq_prio; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | lt_prio: | ||
91 | list_add_tail(&node->plist.prio_list, &iter->plist.prio_list); | ||
92 | eq_prio: | ||
93 | list_add_tail(&node->plist.node_list, &iter->plist.node_list); | ||
94 | |||
95 | plist_check_head(head); | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * plist_del - Remove a @node from plist. | ||
100 | * | ||
101 | * @node: &struct plist_node pointer - entry to be removed | ||
102 | * @head: &struct plist_head pointer - list head | ||
103 | */ | ||
104 | void plist_del(struct plist_node *node, struct plist_head *head) | ||
105 | { | ||
106 | plist_check_head(head); | ||
107 | |||
108 | if (!list_empty(&node->plist.prio_list)) { | ||
109 | struct plist_node *next = plist_first(&node->plist); | ||
110 | |||
111 | list_move_tail(&next->plist.prio_list, &node->plist.prio_list); | ||
112 | list_del_init(&node->plist.prio_list); | ||
113 | } | ||
114 | |||
115 | list_del_init(&node->plist.node_list); | ||
116 | |||
117 | plist_check_head(head); | ||
118 | } | ||