| #ifndef INTERNAL_IO_SLIST_H |
| #define INTERNAL_IO_SLIST_H |
| |
| #include <linux/io_uring_types.h> |
| |
| #define wq_list_for_each(pos, prv, head) \ |
| for (pos = (head)->first, prv = NULL; pos; prv = pos, pos = (pos)->next) |
| |
| #define wq_list_for_each_resume(pos, prv) \ |
| for (; pos; prv = pos, pos = (pos)->next) |
| |
| #define wq_list_empty(list) (READ_ONCE((list)->first) == NULL) |
| |
| #define INIT_WQ_LIST(list) do { \ |
| (list)->first = NULL; \ |
| } while (0) |
| |
| static inline void wq_list_add_after(struct io_wq_work_node *node, |
| struct io_wq_work_node *pos, |
| struct io_wq_work_list *list) |
| { |
| struct io_wq_work_node *next = pos->next; |
| |
| pos->next = node; |
| node->next = next; |
| if (!next) |
| list->last = node; |
| } |
| |
| /** |
| * wq_list_merge - merge the second list to the first one. |
| * @list0: the first list |
| * @list1: the second list |
| * Return the first node after mergence. |
| */ |
| static inline struct io_wq_work_node *wq_list_merge(struct io_wq_work_list *list0, |
| struct io_wq_work_list *list1) |
| { |
| struct io_wq_work_node *ret; |
| |
| if (!list0->first) { |
| ret = list1->first; |
| } else { |
| ret = list0->first; |
| list0->last->next = list1->first; |
| } |
| INIT_WQ_LIST(list0); |
| INIT_WQ_LIST(list1); |
| return ret; |
| } |
| |
| static inline void wq_list_add_tail(struct io_wq_work_node *node, |
| struct io_wq_work_list *list) |
| { |
| node->next = NULL; |
| if (!list->first) { |
| list->last = node; |
| WRITE_ONCE(list->first, node); |
| } else { |
| list->last->next = node; |
| list->last = node; |
| } |
| } |
| |
| static inline void wq_list_add_head(struct io_wq_work_node *node, |
| struct io_wq_work_list *list) |
| { |
| node->next = list->first; |
| if (!node->next) |
| list->last = node; |
| WRITE_ONCE(list->first, node); |
| } |
| |
| static inline void wq_list_cut(struct io_wq_work_list *list, |
| struct io_wq_work_node *last, |
| struct io_wq_work_node *prev) |
| { |
| /* first in the list, if prev==NULL */ |
| if (!prev) |
| WRITE_ONCE(list->first, last->next); |
| else |
| prev->next = last->next; |
| |
| if (last == list->last) |
| list->last = prev; |
| last->next = NULL; |
| } |
| |
| static inline void __wq_list_splice(struct io_wq_work_list *list, |
| struct io_wq_work_node *to) |
| { |
| list->last->next = to->next; |
| to->next = list->first; |
| INIT_WQ_LIST(list); |
| } |
| |
| static inline bool wq_list_splice(struct io_wq_work_list *list, |
| struct io_wq_work_node *to) |
| { |
| if (!wq_list_empty(list)) { |
| __wq_list_splice(list, to); |
| return true; |
| } |
| return false; |
| } |
| |
| static inline void wq_stack_add_head(struct io_wq_work_node *node, |
| struct io_wq_work_node *stack) |
| { |
| node->next = stack->next; |
| stack->next = node; |
| } |
| |
| static inline void wq_list_del(struct io_wq_work_list *list, |
| struct io_wq_work_node *node, |
| struct io_wq_work_node *prev) |
| { |
| wq_list_cut(list, node, prev); |
| } |
| |
| static inline |
| struct io_wq_work_node *wq_stack_extract(struct io_wq_work_node *stack) |
| { |
| struct io_wq_work_node *node = stack->next; |
| |
| stack->next = node->next; |
| return node; |
| } |
| |
| static inline struct io_wq_work *wq_next_work(struct io_wq_work *work) |
| { |
| if (!work->list.next) |
| return NULL; |
| |
| return container_of(work->list.next, struct io_wq_work, list); |
| } |
| |
| #endif // INTERNAL_IO_SLIST_H |