]>
Commit | Line | Data |
---|---|---|
cb323159 A |
1 | /* |
2 | * Copyright (c) 2019 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | #ifndef _KERN_CIRCLE_QUEUE_H_ | |
30 | #define _KERN_CIRCLE_QUEUE_H_ | |
31 | ||
32 | #include <kern/queue.h> | |
33 | #include <kern/assert.h> | |
34 | ||
35 | __BEGIN_DECLS | |
36 | ||
37 | /* | |
38 | * Circle Queue Management APIs | |
39 | * | |
40 | * These are similar to the queues from queue.h, | |
41 | * but the circle queue head is a single pointer to the first element | |
42 | * of the queue. | |
43 | */ | |
44 | ||
45 | typedef struct circle_queue_head { | |
46 | queue_entry_t head; | |
47 | } circle_queue_head_t, *circle_queue_t; | |
48 | ||
49 | static inline bool | |
50 | circle_queue_empty(circle_queue_t cq) | |
51 | { | |
52 | return cq->head == NULL; | |
53 | } | |
54 | ||
55 | static inline queue_entry_t | |
56 | circle_queue_first(circle_queue_t cq) | |
57 | { | |
58 | return cq->head; | |
59 | } | |
60 | ||
61 | static inline queue_entry_t | |
62 | circle_queue_last(circle_queue_t cq) | |
63 | { | |
64 | queue_entry_t elt = circle_queue_first(cq); | |
65 | if (elt) { | |
66 | __builtin_assume(elt->prev != NULL); | |
67 | return elt->prev; | |
68 | } | |
69 | return NULL; | |
70 | } | |
71 | ||
72 | static inline queue_entry_t | |
73 | circle_queue_next(circle_queue_t cq, queue_entry_t elt) | |
74 | { | |
75 | return elt->next == cq->head ? NULL : elt->next; | |
76 | } | |
77 | ||
78 | static inline size_t | |
79 | circle_queue_length(circle_queue_t cq) | |
80 | { | |
81 | queue_entry_t elt = circle_queue_first(cq); | |
82 | size_t n = 0; | |
83 | ||
84 | for (; elt; elt = circle_queue_next(cq, elt)) { | |
85 | n++; | |
86 | } | |
87 | return n; | |
88 | } | |
89 | ||
90 | static inline void | |
91 | circle_enqueue_tail(circle_queue_t cq, queue_entry_t elt) | |
92 | { | |
93 | queue_entry_t head = circle_queue_first(cq); | |
94 | queue_entry_t tail = circle_queue_last(cq); | |
95 | ||
96 | if (head == NULL) { | |
97 | cq->head = elt->next = elt->prev = elt; | |
98 | } else { | |
99 | elt->next = head; | |
100 | elt->prev = tail; | |
101 | tail->next = elt; | |
102 | head->prev = elt; | |
103 | } | |
104 | } | |
105 | ||
106 | static inline void | |
107 | circle_enqueue_head(circle_queue_t cq, queue_entry_t elt) | |
108 | { | |
109 | circle_enqueue_tail(cq, elt); | |
110 | cq->head = elt; | |
111 | } | |
112 | ||
113 | static inline void | |
114 | circle_dequeue(circle_queue_t cq, queue_entry_t elt) | |
115 | { | |
116 | queue_entry_t elt_prev = elt->prev; | |
117 | queue_entry_t elt_next = elt->next; | |
118 | ||
119 | if (elt == elt_next) { | |
120 | assert(cq->head == elt); | |
121 | cq->head = NULL; | |
122 | } else { | |
123 | elt_prev->next = elt_next; | |
124 | elt_next->prev = elt_prev; | |
125 | if (cq->head == elt) { | |
126 | cq->head = elt_next; | |
127 | } | |
128 | } | |
129 | __DEQUEUE_ELT_CLEANUP(elt); | |
130 | } | |
131 | ||
132 | static inline queue_entry_t | |
133 | circle_dequeue_head(circle_queue_t cq) | |
134 | { | |
135 | queue_entry_t elt = circle_queue_first(cq); | |
136 | if (elt) { | |
137 | circle_dequeue(cq, elt); | |
138 | } | |
139 | return elt; | |
140 | } | |
141 | ||
142 | static inline queue_entry_t | |
143 | circle_dequeue_tail(circle_queue_t cq) | |
144 | { | |
145 | queue_entry_t elt = circle_queue_last(cq); | |
146 | if (elt) { | |
147 | circle_dequeue(cq, elt); | |
148 | } | |
149 | return elt; | |
150 | } | |
151 | ||
ea3f0419 A |
152 | static inline void |
153 | circle_queue_rotate_head_forward(circle_queue_t cq) | |
154 | { | |
155 | queue_entry_t first = circle_queue_first(cq); | |
156 | if (first != NULL) { | |
157 | cq->head = first->next; | |
158 | } | |
159 | } | |
160 | ||
161 | static inline void | |
162 | circle_queue_rotate_head_backward(circle_queue_t cq) | |
163 | { | |
164 | queue_entry_t last = circle_queue_last(cq); | |
165 | if (last != NULL) { | |
166 | cq->head = last; | |
167 | } | |
168 | } | |
169 | ||
cb323159 A |
170 | /* |
171 | * Macro: cqe_element | |
172 | * Function: | |
173 | * Convert a cirle_queue_entry_t pointer to a queue element pointer. | |
174 | * Get a pointer to the user-defined element containing | |
175 | * a given cirle_queue_entry_t | |
176 | * Header: | |
177 | * <type> * cqe_element(cirle_queue_entry_t qe, <type>, field) | |
178 | * qe - queue entry to convert | |
179 | * <type> - what's in the queue (e.g., struct some_data) | |
180 | * <field> - is the chain field in <type> | |
181 | * Note: | |
182 | * Do not use pointer types for <type> | |
183 | */ | |
184 | #define cqe_element(qe, type, field) __container_of(qe, type, field) | |
185 | ||
186 | /* | |
187 | * Macro: cqe_foreach | |
188 | * Function: | |
189 | * Iterate over each queue_entry_t structure. | |
190 | * Generates a 'for' loop, setting 'qe' to | |
191 | * each queue_entry_t in the queue. | |
192 | * Header: | |
193 | * cqe_foreach(queue_entry_t qe, queue_t head) | |
194 | * qe - iteration variable | |
195 | * head - pointer to queue_head_t (head of queue) | |
196 | * Note: | |
197 | * This should only be used with Method 1 queue iteration (linkage chains) | |
198 | */ | |
199 | #define cqe_foreach(qe, head) \ | |
200 | for (qe = circle_queue_first(head); qe; qe = circle_queue_next(head, qe)) | |
201 | ||
202 | /* | |
203 | * Macro: cqe_foreach_safe | |
204 | * Function: | |
205 | * Safely iterate over each queue_entry_t structure. | |
206 | * | |
207 | * Use this iterator macro if you plan to remove the | |
208 | * queue_entry_t, qe, from the queue during the | |
209 | * iteration. | |
210 | * Header: | |
211 | * cqe_foreach_safe(queue_entry_t qe, queue_t head) | |
212 | * qe - iteration variable | |
213 | * head - pointer to queue_head_t (head of queue) | |
214 | * Note: | |
215 | * This should only be used with Method 1 queue iteration (linkage chains) | |
216 | */ | |
217 | #define cqe_foreach_safe(qe, head) \ | |
218 | for (queue_entry_t _ne, _qe = circle_queue_first(head); \ | |
219 | (qe = _qe) && (_ne = circle_queue_next(head, _qe), 1); \ | |
220 | _qe = _ne) | |
221 | ||
222 | /* | |
223 | * Macro: cqe_foreach_element | |
224 | * Function: | |
225 | * Iterate over each _element_ in a queue | |
226 | * where each queue_entry_t points to another | |
227 | * queue_entry_t, i.e., managed by the [de|en]queue_head/ | |
228 | * [de|en]queue_tail / remqueue / etc. function. | |
229 | * Header: | |
230 | * cqe_foreach_element(<type> *elt, queue_t head, <field>) | |
231 | * elt - iteration variable | |
232 | * <type> - what's in the queue (e.g., struct some_data) | |
233 | * <field> - is the chain field in <type> | |
234 | * Note: | |
235 | * This should only be used with Method 1 queue iteration (linkage chains) | |
236 | */ | |
237 | #define cqe_foreach_element(elt, head, field) \ | |
238 | for (queue_entry_t _qe = circle_queue_first(head); \ | |
239 | _qe && (elt = cqe_element(_qe, typeof(*(elt)), field), 1); \ | |
240 | _qe = circle_queue_next(head, _qe)) | |
241 | ||
242 | /* | |
243 | * Macro: cqe_foreach_element_safe | |
244 | * Function: | |
245 | * Safely iterate over each _element_ in a queue | |
246 | * where each queue_entry_t points to another | |
247 | * queue_entry_t, i.e., managed by the [de|en]queue_head/ | |
248 | * [de|en]queue_tail / remqueue / etc. function. | |
249 | * | |
250 | * Use this iterator macro if you plan to remove the | |
251 | * element, elt, from the queue during the iteration. | |
252 | * Header: | |
253 | * cqe_foreach_element_safe(<type> *elt, queue_t head, <field>) | |
254 | * elt - iteration variable | |
255 | * <type> - what's in the queue (e.g., struct some_data) | |
256 | * <field> - is the chain field in <type> | |
257 | * Note: | |
258 | * This should only be used with Method 1 queue iteration (linkage chains) | |
259 | */ | |
260 | #define cqe_foreach_element_safe(elt, head, field) \ | |
261 | for (queue_entry_t _ne, _qe = circle_queue_first(head); \ | |
262 | _qe && (elt = cqe_element(_qe, typeof(*(elt)), field), \ | |
263 | _ne = circle_queue_next(head, _qe), 1); \ | |
264 | _qe = _ne) | |
265 | ||
266 | /* Dequeue an element from head, or return NULL if the queue is empty */ | |
267 | #define cqe_dequeue_head(head, type, field) ({ \ | |
268 | queue_entry_t _tmp_entry = circle_dequeue_head((head)); \ | |
269 | type *_tmp_element = (type*) NULL; \ | |
270 | if (_tmp_entry != (queue_entry_t) NULL) \ | |
271 | _tmp_element = cqe_element(_tmp_entry, type, field); \ | |
272 | _tmp_element; \ | |
273 | }) | |
274 | ||
275 | /* Dequeue an element from tail, or return NULL if the queue is empty */ | |
276 | #define cqe_dequeue_tail(head, type, field) ({ \ | |
277 | queue_entry_t _tmp_entry = circle_dequeue_tail((head)); \ | |
278 | type *_tmp_element = (type*) NULL; \ | |
279 | if (_tmp_entry != (queue_entry_t) NULL) \ | |
280 | _tmp_element = cqe_element(_tmp_entry, type, field); \ | |
281 | _tmp_element; \ | |
282 | }) | |
283 | ||
284 | /* Peek at the first element, or return NULL if the queue is empty */ | |
285 | #define cqe_queue_first(head, type, field) ({ \ | |
286 | queue_entry_t _tmp_entry = circle_queue_first((head)); \ | |
287 | type *_tmp_element = (type*) NULL; \ | |
288 | if (_tmp_entry != (queue_entry_t) NULL) \ | |
289 | _tmp_element = cqe_element(_tmp_entry, type, field); \ | |
290 | _tmp_element; \ | |
291 | }) | |
292 | ||
293 | /* Peek at the next element, or return NULL if it is last */ | |
294 | #define cqe_queue_next(elt, head, type, field) ({ \ | |
295 | queue_entry_t _tmp_entry = circle_queue_next((head), (elt)); \ | |
296 | type *_tmp_element = (type*) NULL; \ | |
297 | if (_tmp_entry != (queue_entry_t) NULL) \ | |
298 | _tmp_element = cqe_element(_tmp_entry, type, field); \ | |
299 | _tmp_element; \ | |
300 | }) | |
301 | ||
302 | /* Peek at the tail element, or return NULL if the queue is empty */ | |
303 | #define cqe_queue_last(head, type, field) ({ \ | |
304 | queue_entry_t _tmp_entry = circle_queue_last((head)); \ | |
305 | type *_tmp_element = (type*) NULL; \ | |
306 | if (_tmp_entry != (queue_entry_t) NULL) \ | |
307 | _tmp_element = cqe_element(_tmp_entry, type, field); \ | |
308 | _tmp_element; \ | |
309 | }) | |
310 | ||
311 | /* | |
312 | * Macro: circle_queue_init | |
313 | * Function: | |
314 | * Initialize the given circle queue. | |
315 | * Header: | |
316 | * void circle_queue_init(q) | |
317 | * circle_queue_t q; \* MODIFIED *\ | |
318 | */ | |
319 | #define circle_queue_init(q) \ | |
320 | MACRO_BEGIN \ | |
321 | (q)->head = NULL; \ | |
322 | MACRO_END | |
323 | ||
324 | __END_DECLS | |
325 | ||
326 | #endif /* _KERN_QUEUE_H_ */ |