1 /* $OpenBSD: workqueue.h,v 1.12 2025/02/07 03:03:31 jsg Exp $ */
2 /*
3 * Copyright (c) 2015 Mark Kettenis
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #ifndef _LINUX_WORKQUEUE_H
19 #define _LINUX_WORKQUEUE_H
20
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/task.h>
24 #include <sys/timeout.h>
25 #include <linux/bitops.h>
26 #include <linux/atomic.h>
27 #include <linux/rcupdate.h>
28 #include <linux/lockdep.h>
29 #include <linux/timer.h>
30
31 struct workqueue_struct;
32
33 extern struct workqueue_struct *system_wq;
34 extern struct workqueue_struct *system_highpri_wq;
35 extern struct workqueue_struct *system_unbound_wq;
36 extern struct workqueue_struct *system_long_wq;
37
38 #define WQ_HIGHPRI (1 << 1)
39 #define WQ_FREEZABLE (1 << 2)
40 #define WQ_UNBOUND (1 << 3)
41 #define WQ_MEM_RECLAIM (1 << 4)
42
43 #define WQ_UNBOUND_MAX_ACTIVE 4 /* matches nthreads in drm_linux.c */
44
45 static inline struct workqueue_struct *
alloc_workqueue(const char * name,int flags,int max_active)46 alloc_workqueue(const char *name, int flags, int max_active)
47 {
48 struct taskq *tq = taskq_create(name, 1, IPL_TTY, 0);
49 return (struct workqueue_struct *)tq;
50 }
51
52 static inline struct workqueue_struct *
alloc_ordered_workqueue(const char * name,int flags,...)53 alloc_ordered_workqueue(const char *name, int flags, ...)
54 {
55 struct taskq *tq = taskq_create(name, 1, IPL_TTY, 0);
56 return (struct workqueue_struct *)tq;
57 }
58
59 static inline struct workqueue_struct *
create_singlethread_workqueue(const char * name)60 create_singlethread_workqueue(const char *name)
61 {
62 struct taskq *tq = taskq_create(name, 1, IPL_TTY, 0);
63 return (struct workqueue_struct *)tq;
64 }
65
66 static inline void
destroy_workqueue(struct workqueue_struct * wq)67 destroy_workqueue(struct workqueue_struct *wq)
68 {
69 taskq_destroy((struct taskq *)wq);
70 }
71
72 struct work_struct {
73 struct task task;
74 struct taskq *tq;
75 };
76
77 typedef void (*work_func_t)(struct work_struct *);
78
79 static inline void
INIT_WORK(struct work_struct * work,work_func_t func)80 INIT_WORK(struct work_struct *work, work_func_t func)
81 {
82 work->tq = NULL;
83 task_set(&work->task, (void (*)(void *))func, work);
84 }
85
86 #define INIT_WORK_ONSTACK(x, y) INIT_WORK((x), (y))
87
88 static inline bool
queue_work(struct workqueue_struct * wq,struct work_struct * work)89 queue_work(struct workqueue_struct *wq, struct work_struct *work)
90 {
91 work->tq = (struct taskq *)wq;
92 return task_add(work->tq, &work->task);
93 }
94
95 static inline bool
queue_work_node(int node,struct workqueue_struct * wq,struct work_struct * work)96 queue_work_node(int node, struct workqueue_struct *wq, struct work_struct *work)
97 {
98 return queue_work(wq, work);
99 }
100
101 static inline void
cancel_work(struct work_struct * work)102 cancel_work(struct work_struct *work)
103 {
104 if (work->tq != NULL)
105 task_del(work->tq, &work->task);
106 }
107
108 static inline bool
cancel_work_sync(struct work_struct * work)109 cancel_work_sync(struct work_struct *work)
110 {
111 if (work->tq != NULL)
112 return task_del(work->tq, &work->task);
113 return false;
114 }
115
116 #define work_pending(work) task_pending(&(work)->task)
117
118 struct delayed_work {
119 struct work_struct work;
120 struct timeout to;
121 struct taskq *tq;
122 };
123
124 #define system_power_efficient_wq ((struct workqueue_struct *)systq)
125
126 static inline struct delayed_work *
to_delayed_work(struct work_struct * work)127 to_delayed_work(struct work_struct *work)
128 {
129 return container_of(work, struct delayed_work, work);
130 }
131
132 static void
__delayed_work_tick(void * arg)133 __delayed_work_tick(void *arg)
134 {
135 struct delayed_work *dwork = arg;
136
137 task_add(dwork->tq, &dwork->work.task);
138 }
139
140 static inline void
INIT_DELAYED_WORK(struct delayed_work * dwork,work_func_t func)141 INIT_DELAYED_WORK(struct delayed_work *dwork, work_func_t func)
142 {
143 INIT_WORK(&dwork->work, func);
144 timeout_set(&dwork->to, __delayed_work_tick, &dwork->work);
145 }
146
147 static inline void
INIT_DELAYED_WORK_ONSTACK(struct delayed_work * dwork,work_func_t func)148 INIT_DELAYED_WORK_ONSTACK(struct delayed_work *dwork, work_func_t func)
149 {
150 INIT_WORK(&dwork->work, func);
151 timeout_set(&dwork->to, __delayed_work_tick, &dwork->work);
152 }
153
154 #define __DELAYED_WORK_INITIALIZER(dw, fn, flags) { \
155 .to = TIMEOUT_INITIALIZER(__delayed_work_tick, &(dw)), \
156 .tq = NULL, \
157 .work.tq = NULL, \
158 .work.task = TASK_INITIALIZER((void (*)(void *))(fn), &(dw).work) \
159 }
160
161 static inline bool
schedule_work(struct work_struct * work)162 schedule_work(struct work_struct *work)
163 {
164 work->tq = (struct taskq *)system_wq;
165 return task_add(work->tq, &work->task);
166 }
167
168 static inline bool
schedule_delayed_work(struct delayed_work * dwork,int jiffies)169 schedule_delayed_work(struct delayed_work *dwork, int jiffies)
170 {
171 dwork->tq = (struct taskq *)system_wq;
172 return timeout_add(&dwork->to, jiffies);
173 }
174
175 static inline bool
queue_delayed_work(struct workqueue_struct * wq,struct delayed_work * dwork,int jiffies)176 queue_delayed_work(struct workqueue_struct *wq,
177 struct delayed_work *dwork, int jiffies)
178 {
179 dwork->tq = (struct taskq *)wq;
180 return timeout_add(&dwork->to, jiffies);
181 }
182
183 static inline bool
mod_delayed_work(struct workqueue_struct * wq,struct delayed_work * dwork,int jiffies)184 mod_delayed_work(struct workqueue_struct *wq,
185 struct delayed_work *dwork, int jiffies)
186 {
187 dwork->tq = (struct taskq *)wq;
188 return (timeout_add(&dwork->to, jiffies) == 0);
189 }
190
191 static inline bool
cancel_delayed_work(struct delayed_work * dwork)192 cancel_delayed_work(struct delayed_work *dwork)
193 {
194 if (dwork->tq == NULL)
195 return false;
196 if (timeout_del(&dwork->to))
197 return true;
198 return task_del(dwork->tq, &dwork->work.task);
199 }
200
201 static inline bool
cancel_delayed_work_sync(struct delayed_work * dwork)202 cancel_delayed_work_sync(struct delayed_work *dwork)
203 {
204 if (dwork->tq == NULL)
205 return false;
206 if (timeout_del(&dwork->to))
207 return true;
208 return task_del(dwork->tq, &dwork->work.task);
209 }
210
211 static inline bool
delayed_work_pending(struct delayed_work * dwork)212 delayed_work_pending(struct delayed_work *dwork)
213 {
214 if (timeout_pending(&dwork->to))
215 return true;
216 return task_pending(&dwork->work.task);
217 }
218
219 void flush_workqueue(struct workqueue_struct *);
220 bool flush_work(struct work_struct *);
221 bool flush_delayed_work(struct delayed_work *);
222
223 static inline void
flush_scheduled_work(void)224 flush_scheduled_work(void)
225 {
226 flush_workqueue(system_wq);
227 }
228
229 static inline void
drain_workqueue(struct workqueue_struct * wq)230 drain_workqueue(struct workqueue_struct *wq)
231 {
232 flush_workqueue(wq);
233 }
234
235 static inline void
destroy_work_on_stack(struct work_struct * work)236 destroy_work_on_stack(struct work_struct *work)
237 {
238 if (work->tq)
239 task_del(work->tq, &work->task);
240 }
241
242 static inline void
destroy_delayed_work_on_stack(struct delayed_work * dwork)243 destroy_delayed_work_on_stack(struct delayed_work *dwork)
244 {
245 }
246
247 struct rcu_work {
248 struct work_struct work;
249 struct rcu_head rcu;
250 };
251
252 static inline void
INIT_RCU_WORK(struct rcu_work * work,work_func_t func)253 INIT_RCU_WORK(struct rcu_work *work, work_func_t func)
254 {
255 INIT_WORK(&work->work, func);
256 }
257
258 static inline bool
queue_rcu_work(struct workqueue_struct * wq,struct rcu_work * work)259 queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *work)
260 {
261 return queue_work(wq, &work->work);
262 }
263
264 #endif
265