xref: /linux/io_uring/slist.h (revision bf80eef2212a1e8451df13b52533f4bc31bb4f8e)
1 #ifndef INTERNAL_IO_SLIST_H
2 #define INTERNAL_IO_SLIST_H
3 
4 #include <linux/io_uring_types.h>
5 
6 #define wq_list_for_each(pos, prv, head)			\
7 	for (pos = (head)->first, prv = NULL; pos; prv = pos, pos = (pos)->next)
8 
9 #define wq_list_for_each_resume(pos, prv)			\
10 	for (; pos; prv = pos, pos = (pos)->next)
11 
12 #define wq_list_empty(list)	(READ_ONCE((list)->first) == NULL)
13 
14 #define INIT_WQ_LIST(list)	do {				\
15 	(list)->first = NULL;					\
16 } while (0)
17 
18 static inline void wq_list_add_after(struct io_wq_work_node *node,
19 				     struct io_wq_work_node *pos,
20 				     struct io_wq_work_list *list)
21 {
22 	struct io_wq_work_node *next = pos->next;
23 
24 	pos->next = node;
25 	node->next = next;
26 	if (!next)
27 		list->last = node;
28 }
29 
30 /**
31  * wq_list_merge - merge the second list to the first one.
32  * @list0: the first list
33  * @list1: the second list
34  * Return the first node after mergence.
35  */
36 static inline struct io_wq_work_node *wq_list_merge(struct io_wq_work_list *list0,
37 						    struct io_wq_work_list *list1)
38 {
39 	struct io_wq_work_node *ret;
40 
41 	if (!list0->first) {
42 		ret = list1->first;
43 	} else {
44 		ret = list0->first;
45 		list0->last->next = list1->first;
46 	}
47 	INIT_WQ_LIST(list0);
48 	INIT_WQ_LIST(list1);
49 	return ret;
50 }
51 
52 static inline void wq_list_add_tail(struct io_wq_work_node *node,
53 				    struct io_wq_work_list *list)
54 {
55 	node->next = NULL;
56 	if (!list->first) {
57 		list->last = node;
58 		WRITE_ONCE(list->first, node);
59 	} else {
60 		list->last->next = node;
61 		list->last = node;
62 	}
63 }
64 
65 static inline void wq_list_add_head(struct io_wq_work_node *node,
66 				    struct io_wq_work_list *list)
67 {
68 	node->next = list->first;
69 	if (!node->next)
70 		list->last = node;
71 	WRITE_ONCE(list->first, node);
72 }
73 
74 static inline void wq_list_cut(struct io_wq_work_list *list,
75 			       struct io_wq_work_node *last,
76 			       struct io_wq_work_node *prev)
77 {
78 	/* first in the list, if prev==NULL */
79 	if (!prev)
80 		WRITE_ONCE(list->first, last->next);
81 	else
82 		prev->next = last->next;
83 
84 	if (last == list->last)
85 		list->last = prev;
86 	last->next = NULL;
87 }
88 
89 static inline void __wq_list_splice(struct io_wq_work_list *list,
90 				    struct io_wq_work_node *to)
91 {
92 	list->last->next = to->next;
93 	to->next = list->first;
94 	INIT_WQ_LIST(list);
95 }
96 
97 static inline bool wq_list_splice(struct io_wq_work_list *list,
98 				  struct io_wq_work_node *to)
99 {
100 	if (!wq_list_empty(list)) {
101 		__wq_list_splice(list, to);
102 		return true;
103 	}
104 	return false;
105 }
106 
107 static inline void wq_stack_add_head(struct io_wq_work_node *node,
108 				     struct io_wq_work_node *stack)
109 {
110 	node->next = stack->next;
111 	stack->next = node;
112 }
113 
114 static inline void wq_list_del(struct io_wq_work_list *list,
115 			       struct io_wq_work_node *node,
116 			       struct io_wq_work_node *prev)
117 {
118 	wq_list_cut(list, node, prev);
119 }
120 
121 static inline
122 struct io_wq_work_node *wq_stack_extract(struct io_wq_work_node *stack)
123 {
124 	struct io_wq_work_node *node = stack->next;
125 
126 	stack->next = node->next;
127 	return node;
128 }
129 
130 static inline struct io_wq_work *wq_next_work(struct io_wq_work *work)
131 {
132 	if (!work->list.next)
133 		return NULL;
134 
135 	return container_of(work->list.next, struct io_wq_work, list);
136 }
137 
138 #endif // INTERNAL_IO_SLIST_H