1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2006-03-16 Bernard the first version
9 * 2006-09-07 Bernard move the kservice APIs to rtthread.h
10 * 2007-06-27 Bernard fix the rt_list_remove bug
11 * 2012-03-22 Bernard rename kservice.h to rtservice.h
12 * 2017-11-15 JasonJia Modify rt_slist_foreach to rt_slist_for_each_entry.
13 * Make code cleanup.
14 * 2024-01-03 Shell add rt_slist_pop()
15 */
16
17 #ifndef __RT_SERVICE_H__
18 #define __RT_SERVICE_H__
19
20 #include <rtdef.h>
21
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25
26 /**
27 * @addtogroup group_kernel_service
28 */
29
30 /**@{*/
31
32 /**
33 * rt_container_of - return the start address of struct type, while ptr is the
34 * member of struct type.
35 */
36 #define rt_container_of(ptr, type, member) \
37 ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
38
39
40 /**
41 * @brief initialize a list object
42 */
43 #define RT_LIST_OBJECT_INIT(object) { &(object), &(object) }
44
45 /**
46 * @brief initialize a list
47 *
48 * @param l list to be initialized
49 */
rt_list_init(rt_list_t * l)50 rt_inline void rt_list_init(rt_list_t *l)
51 {
52 l->next = l->prev = l;
53 }
54
55 /**
56 * @brief insert a node after a list
57 *
58 * @param l list to insert it
59 * @param n new node to be inserted
60 */
rt_list_insert_after(rt_list_t * l,rt_list_t * n)61 rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n)
62 {
63 l->next->prev = n;
64 n->next = l->next;
65
66 l->next = n;
67 n->prev = l;
68 }
69
70 /**
71 * @brief insert a node before a list
72 *
73 * @param n new node to be inserted
74 * @param l list to insert it
75 */
rt_list_insert_before(rt_list_t * l,rt_list_t * n)76 rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n)
77 {
78 l->prev->next = n;
79 n->prev = l->prev;
80
81 l->prev = n;
82 n->next = l;
83 }
84
85 /**
86 * @brief remove node from list.
87 * @param n the node to remove from the list.
88 */
rt_list_remove(rt_list_t * n)89 rt_inline void rt_list_remove(rt_list_t *n)
90 {
91 n->next->prev = n->prev;
92 n->prev->next = n->next;
93
94 n->next = n->prev = n;
95 }
96
97 /**
98 * @brief tests whether a list is empty
99 * @param l the list to test.
100 */
rt_list_isempty(const rt_list_t * l)101 rt_inline int rt_list_isempty(const rt_list_t *l)
102 {
103 return l->next == l;
104 }
105
106 /**
107 * @brief get the list length
108 * @param l the list to get.
109 */
rt_list_len(const rt_list_t * l)110 rt_inline unsigned int rt_list_len(const rt_list_t *l)
111 {
112 unsigned int len = 0;
113 const rt_list_t *p = l;
114 while (p->next != l)
115 {
116 p = p->next;
117 len ++;
118 }
119
120 return len;
121 }
122
123 /**
124 * @brief get the struct for this entry
125 * @param node the entry point
126 * @param type the type of structure
127 * @param member the name of list in structure
128 */
129 #define rt_list_entry(node, type, member) \
130 rt_container_of(node, type, member)
131
132 /**
133 * rt_list_for_each - iterate over a list
134 * @param pos the rt_list_t * to use as a loop cursor.
135 * @param head the head for your list.
136 */
137 #define rt_list_for_each(pos, head) \
138 for (pos = (head)->next; pos != (head); pos = pos->next)
139
140 /**
141 * rt_list_for_each_safe - iterate over a list safe against removal of list entry
142 * @param pos the rt_list_t * to use as a loop cursor.
143 * @param n another rt_list_t * to use as temporary storage
144 * @param head the head for your list.
145 */
146 #define rt_list_for_each_safe(pos, n, head) \
147 for (pos = (head)->next, n = pos->next; pos != (head); \
148 pos = n, n = pos->next)
149
150 /**
151 * rt_list_for_each_entry - iterate over list of given type
152 * @param pos the type * to use as a loop cursor.
153 * @param head the head for your list.
154 * @param member the name of the list_struct within the struct.
155 */
156 #define rt_list_for_each_entry(pos, head, member) \
157 for (pos = rt_list_entry((head)->next, rt_typeof(*pos), member); \
158 &pos->member != (head); \
159 pos = rt_list_entry(pos->member.next, rt_typeof(*pos), member))
160
161 /**
162 * rt_list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
163 * @param pos the type * to use as a loop cursor.
164 * @param n another type * to use as temporary storage
165 * @param head the head for your list.
166 * @param member the name of the list_struct within the struct.
167 */
168 #define rt_list_for_each_entry_safe(pos, n, head, member) \
169 for (pos = rt_list_entry((head)->next, rt_typeof(*pos), member), \
170 n = rt_list_entry(pos->member.next, rt_typeof(*pos), member); \
171 &pos->member != (head); \
172 pos = n, n = rt_list_entry(n->member.next, rt_typeof(*n), member))
173
174 /**
175 * rt_list_first_entry - get the first element from a list
176 * @param ptr the list head to take the element from.
177 * @param type the type of the struct this is embedded in.
178 * @param member the name of the list_struct within the struct.
179 *
180 * Note, that list is expected to be not empty.
181 */
182 #define rt_list_first_entry(ptr, type, member) \
183 rt_list_entry((ptr)->next, type, member)
184
185 #define RT_SLIST_OBJECT_INIT(object) { RT_NULL }
186
187 /**
188 * @brief initialize a single list
189 *
190 * @param l the single list to be initialized
191 */
rt_slist_init(rt_slist_t * l)192 rt_inline void rt_slist_init(rt_slist_t *l)
193 {
194 l->next = RT_NULL;
195 }
196
rt_slist_append(rt_slist_t * l,rt_slist_t * n)197 rt_inline void rt_slist_append(rt_slist_t *l, rt_slist_t *n)
198 {
199 struct rt_slist_node *node;
200
201 node = l;
202 while (node->next) node = node->next;
203
204 /* append the node to the tail */
205 node->next = n;
206 n->next = RT_NULL;
207 }
208
rt_slist_insert(rt_slist_t * l,rt_slist_t * n)209 rt_inline void rt_slist_insert(rt_slist_t *l, rt_slist_t *n)
210 {
211 n->next = l->next;
212 l->next = n;
213 }
214
rt_slist_len(const rt_slist_t * l)215 rt_inline unsigned int rt_slist_len(const rt_slist_t *l)
216 {
217 unsigned int len = 0;
218 const rt_slist_t *list = l->next;
219 while (list != RT_NULL)
220 {
221 list = list->next;
222 len ++;
223 }
224
225 return len;
226 }
227
rt_slist_pop(rt_slist_t * l)228 rt_inline rt_slist_t *rt_slist_pop(rt_slist_t *l)
229 {
230 struct rt_slist_node *node = l;
231
232 /* remove node */
233 node = node->next;
234 if (node != (rt_slist_t *)0)
235 {
236 ((struct rt_slist_node *)l)->next = node->next;
237 node->next = RT_NULL;
238 }
239
240 return node;
241 }
242
rt_slist_remove(rt_slist_t * l,rt_slist_t * n)243 rt_inline rt_slist_t *rt_slist_remove(rt_slist_t *l, rt_slist_t *n)
244 {
245 /* remove slist head */
246 struct rt_slist_node *node = l;
247 while (node->next && node->next != n) node = node->next;
248
249 /* remove node */
250 if (node->next != (rt_slist_t *)0)
251 {
252 node->next = node->next->next;
253 n->next = RT_NULL;
254 }
255
256 return l;
257 }
258
rt_slist_first(rt_slist_t * l)259 rt_inline rt_slist_t *rt_slist_first(rt_slist_t *l)
260 {
261 return l->next;
262 }
263
rt_slist_tail(rt_slist_t * l)264 rt_inline rt_slist_t *rt_slist_tail(rt_slist_t *l)
265 {
266 while (l->next) l = l->next;
267
268 return l;
269 }
270
rt_slist_next(rt_slist_t * n)271 rt_inline rt_slist_t *rt_slist_next(rt_slist_t *n)
272 {
273 return n->next;
274 }
275
rt_slist_isempty(rt_slist_t * l)276 rt_inline int rt_slist_isempty(rt_slist_t *l)
277 {
278 return l->next == RT_NULL;
279 }
280
281 /**
282 * @brief get the struct for this single list node
283 * @param node the entry point
284 * @param type the type of structure
285 * @param member the name of list in structure
286 */
287 #define rt_slist_entry(node, type, member) \
288 rt_container_of(node, type, member)
289
290 /**
291 * rt_slist_for_each - iterate over a single list
292 * @param pos the rt_slist_t * to use as a loop cursor.
293 * @param head the head for your single list.
294 */
295 #define rt_slist_for_each(pos, head) \
296 for (pos = (head)->next; pos != RT_NULL; pos = pos->next)
297
298 /**
299 * rt_slist_for_each_entry - iterate over single list of given type
300 * @param pos the type * to use as a loop cursor.
301 * @param head the head for your single list.
302 * @param member the name of the list_struct within the struct.
303 */
304 #define rt_slist_for_each_entry(pos, head, member) \
305 for (pos = ((head)->next == (RT_NULL) ? (RT_NULL) : rt_slist_entry((head)->next, rt_typeof(*pos), member)); \
306 pos != (RT_NULL) && &pos->member != (RT_NULL); \
307 pos = (pos->member.next == (RT_NULL) ? (RT_NULL) : rt_slist_entry(pos->member.next, rt_typeof(*pos), member)))
308
309 /**
310 * rt_slist_first_entry - get the first element from a slist
311 * @param ptr the slist head to take the element from.
312 * @param type the type of the struct this is embedded in.
313 * @param member the name of the slist_struct within the struct.
314 *
315 * Note, that slist is expected to be not empty.
316 */
317 #define rt_slist_first_entry(ptr, type, member) \
318 rt_slist_entry((ptr)->next, type, member)
319
320 /**
321 * rt_slist_tail_entry - get the tail element from a slist
322 * @param ptr the slist head to take the element from.
323 * @param type the type of the struct this is embedded in.
324 * @param member the name of the slist_struct within the struct.
325 *
326 * Note, that slist is expected to be not empty.
327 */
328 #define rt_slist_tail_entry(ptr, type, member) \
329 rt_slist_entry(rt_slist_tail(ptr), type, member)
330
331 /**@}*/
332
333 #ifdef __cplusplus
334 }
335 #endif
336
337 #endif
338