1 // SPDX-License-Identifier: GPL-2.0-only
3 * Light-weight single-linked queue.
5 * Entries are enqueued to the head of an llist, with no blocking.
6 * This can happen in any context.
8 * Entries are dequeued using a spinlock to protect against multiple
9 * access. The llist is staged in reverse order, and refreshed
10 * from the llist when it exhausts.
12 * This is particularly suitable when work items are queued in BH or
13 * IRQ context, and where work items are handled one at a time by
16 #include <linux/rcupdate.h>
17 #include <linux/lwq.h>
19 struct llist_node
*__lwq_dequeue(struct lwq
*q
)
21 struct llist_node
*this;
27 if (!this && !llist_empty(&q
->new)) {
28 /* ensure queue doesn't appear transiently lwq_empty */
29 smp_store_release(&q
->ready
, (void *)1);
30 this = llist_reverse_order(llist_del_all(&q
->new));
35 q
->ready
= llist_next(this);
36 spin_unlock(&q
->lock
);
39 EXPORT_SYMBOL_GPL(__lwq_dequeue
);
42 * lwq_dequeue_all - dequeue all currently enqueued objects
43 * @q: the queue to dequeue from
45 * Remove and return a linked list of llist_nodes of all the objects that were
46 * in the queue. The first on the list will be the object that was least
49 struct llist_node
*lwq_dequeue_all(struct lwq
*q
)
51 struct llist_node
*r
, *t
, **ep
;
59 t
= llist_del_all(&q
->new);
60 spin_unlock(&q
->lock
);
64 *ep
= llist_reverse_order(t
);
67 EXPORT_SYMBOL_GPL(lwq_dequeue_all
);
69 #if IS_ENABLED(CONFIG_LWQ_TEST)
71 #include <linux/module.h>
72 #include <linux/slab.h>
73 #include <linux/wait_bit.h>
74 #include <linux/kthread.h>
75 #include <linux/delay.h>
82 static int lwq_exercise(void *qv
)
88 for (cnt
= 0; cnt
< 10000; cnt
++) {
89 wait_var_event(q
, (t
= lwq_dequeue(q
, struct tnode
, n
)) != NULL
);
91 if (lwq_enqueue(&t
->n
, q
))
94 while (!kthread_should_stop())
95 schedule_timeout_idle(1);
99 static int lwq_test(void)
103 struct llist_node
*l
, **t1
, *t2
;
105 struct task_struct
*threads
[8];
107 printk(KERN_INFO
"testing lwq....\n");
109 printk(KERN_INFO
" lwq: run some threads\n");
110 for (i
= 0; i
< ARRAY_SIZE(threads
); i
++)
111 threads
[i
] = kthread_run(lwq_exercise
, &q
, "lwq-test-%d", i
);
112 for (i
= 0; i
< 100; i
++) {
113 t
= kmalloc(sizeof(*t
), GFP_KERNEL
);
118 if (lwq_enqueue(&t
->n
, &q
))
121 /* wait for threads to exit */
122 for (i
= 0; i
< ARRAY_SIZE(threads
); i
++)
123 if (!IS_ERR_OR_NULL(threads
[i
]))
124 kthread_stop(threads
[i
]);
125 printk(KERN_INFO
" lwq: dequeue first 50:");
126 for (i
= 0; i
< 50 ; i
++) {
127 if (i
&& (i
% 10) == 0) {
128 printk(KERN_CONT
"\n");
129 printk(KERN_INFO
" lwq: ... ");
131 t
= lwq_dequeue(&q
, struct tnode
, n
);
133 printk(KERN_CONT
" %d(%d)", t
->i
, t
->c
);
136 printk(KERN_CONT
"\n");
137 l
= lwq_dequeue_all(&q
);
138 printk(KERN_INFO
" lwq: delete the multiples of 3 (test lwq_for_each_safe())\n");
139 lwq_for_each_safe(t
, t1
, t2
, &l
, n
) {
140 if ((t
->i
% 3) == 0) {
147 lwq_enqueue_batch(l
, &q
);
148 printk(KERN_INFO
" lwq: dequeue remaining:");
149 while ((t
= lwq_dequeue(&q
, struct tnode
, n
)) != NULL
) {
150 printk(KERN_CONT
" %d", t
->i
);
153 printk(KERN_CONT
"\n");
157 module_init(lwq_test
);
158 #endif /* CONFIG_LWQ_TEST*/