1*667382c7Skettenis /* $OpenBSD: workqueue.h,v 1.11 2024/01/06 09:33:08 kettenis Exp $ */
27f4dd379Sjsg /*
37f4dd379Sjsg * Copyright (c) 2015 Mark Kettenis
47f4dd379Sjsg *
57f4dd379Sjsg * Permission to use, copy, modify, and distribute this software for any
67f4dd379Sjsg * purpose with or without fee is hereby granted, provided that the above
77f4dd379Sjsg * copyright notice and this permission notice appear in all copies.
87f4dd379Sjsg *
97f4dd379Sjsg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
107f4dd379Sjsg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
117f4dd379Sjsg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
127f4dd379Sjsg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
137f4dd379Sjsg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
147f4dd379Sjsg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
157f4dd379Sjsg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
167f4dd379Sjsg */
177f4dd379Sjsg
187f4dd379Sjsg #ifndef _LINUX_WORKQUEUE_H
197f4dd379Sjsg #define _LINUX_WORKQUEUE_H
207f4dd379Sjsg
217f4dd379Sjsg #include <sys/param.h>
227f4dd379Sjsg #include <sys/systm.h>
237f4dd379Sjsg #include <sys/task.h>
247f4dd379Sjsg #include <sys/timeout.h>
257f4dd379Sjsg #include <linux/bitops.h>
267f4dd379Sjsg #include <linux/atomic.h>
277f4dd379Sjsg #include <linux/rcupdate.h>
287f4dd379Sjsg #include <linux/lockdep.h>
297f4dd379Sjsg #include <linux/timer.h>
307f4dd379Sjsg
317f4dd379Sjsg struct workqueue_struct;
327f4dd379Sjsg
337f4dd379Sjsg extern struct workqueue_struct *system_wq;
34c349dbc7Sjsg extern struct workqueue_struct *system_highpri_wq;
357f4dd379Sjsg extern struct workqueue_struct *system_unbound_wq;
367f4dd379Sjsg extern struct workqueue_struct *system_long_wq;
377f4dd379Sjsg
38*667382c7Skettenis #define WQ_HIGHPRI (1 << 1)
39*667382c7Skettenis #define WQ_FREEZABLE (1 << 2)
40*667382c7Skettenis #define WQ_UNBOUND (1 << 3)
41*667382c7Skettenis #define WQ_MEM_RECLAIM (1 << 4)
427f4dd379Sjsg
43c349dbc7Sjsg #define WQ_UNBOUND_MAX_ACTIVE 4 /* matches nthreads in drm_linux.c */
44c349dbc7Sjsg
457f4dd379Sjsg static inline struct workqueue_struct *
alloc_workqueue(const char * name,int flags,int max_active)467f4dd379Sjsg alloc_workqueue(const char *name, int flags, int max_active)
477f4dd379Sjsg {
487f4dd379Sjsg struct taskq *tq = taskq_create(name, 1, IPL_TTY, 0);
497f4dd379Sjsg return (struct workqueue_struct *)tq;
507f4dd379Sjsg }
517f4dd379Sjsg
527f4dd379Sjsg static inline struct workqueue_struct *
alloc_ordered_workqueue(const char * name,int flags,...)53*667382c7Skettenis alloc_ordered_workqueue(const char *name, int flags, ...)
547f4dd379Sjsg {
557f4dd379Sjsg struct taskq *tq = taskq_create(name, 1, IPL_TTY, 0);
567f4dd379Sjsg return (struct workqueue_struct *)tq;
577f4dd379Sjsg }
587f4dd379Sjsg
597f4dd379Sjsg static inline struct workqueue_struct *
create_singlethread_workqueue(const char * name)607f4dd379Sjsg create_singlethread_workqueue(const char *name)
617f4dd379Sjsg {
627f4dd379Sjsg struct taskq *tq = taskq_create(name, 1, IPL_TTY, 0);
637f4dd379Sjsg return (struct workqueue_struct *)tq;
647f4dd379Sjsg }
657f4dd379Sjsg
667f4dd379Sjsg static inline void
destroy_workqueue(struct workqueue_struct * wq)677f4dd379Sjsg destroy_workqueue(struct workqueue_struct *wq)
687f4dd379Sjsg {
697f4dd379Sjsg taskq_destroy((struct taskq *)wq);
707f4dd379Sjsg }
717f4dd379Sjsg
727f4dd379Sjsg struct work_struct {
737f4dd379Sjsg struct task task;
747f4dd379Sjsg struct taskq *tq;
757f4dd379Sjsg };
767f4dd379Sjsg
777f4dd379Sjsg typedef void (*work_func_t)(struct work_struct *);
787f4dd379Sjsg
797f4dd379Sjsg static inline void
INIT_WORK(struct work_struct * work,work_func_t func)807f4dd379Sjsg INIT_WORK(struct work_struct *work, work_func_t func)
817f4dd379Sjsg {
8215e28df9Sjsg work->tq = NULL;
837f4dd379Sjsg task_set(&work->task, (void (*)(void *))func, work);
847f4dd379Sjsg }
857f4dd379Sjsg
867f4dd379Sjsg #define INIT_WORK_ONSTACK(x, y) INIT_WORK((x), (y))
877f4dd379Sjsg
887f4dd379Sjsg static inline bool
queue_work(struct workqueue_struct * wq,struct work_struct * work)897f4dd379Sjsg queue_work(struct workqueue_struct *wq, struct work_struct *work)
907f4dd379Sjsg {
917f4dd379Sjsg work->tq = (struct taskq *)wq;
927f4dd379Sjsg return task_add(work->tq, &work->task);
937f4dd379Sjsg }
947f4dd379Sjsg
957f4dd379Sjsg static inline void
cancel_work(struct work_struct * work)961bb76ff1Sjsg cancel_work(struct work_struct *work)
971bb76ff1Sjsg {
981bb76ff1Sjsg if (work->tq != NULL)
991bb76ff1Sjsg task_del(work->tq, &work->task);
1001bb76ff1Sjsg }
1011bb76ff1Sjsg
1021bb76ff1Sjsg static inline void
cancel_work_sync(struct work_struct * work)1037f4dd379Sjsg cancel_work_sync(struct work_struct *work)
1047f4dd379Sjsg {
105eb5a2f7aSjsg if (work->tq != NULL)
1067f4dd379Sjsg task_del(work->tq, &work->task);
1077f4dd379Sjsg }
1087f4dd379Sjsg
1097f4dd379Sjsg #define work_pending(work) task_pending(&(work)->task)
1107f4dd379Sjsg
1117f4dd379Sjsg struct delayed_work {
1127f4dd379Sjsg struct work_struct work;
1137f4dd379Sjsg struct timeout to;
1147f4dd379Sjsg struct taskq *tq;
1157f4dd379Sjsg };
1167f4dd379Sjsg
1177f4dd379Sjsg #define system_power_efficient_wq ((struct workqueue_struct *)systq)
1187f4dd379Sjsg
1197f4dd379Sjsg static inline struct delayed_work *
to_delayed_work(struct work_struct * work)1207f4dd379Sjsg to_delayed_work(struct work_struct *work)
1217f4dd379Sjsg {
1227f4dd379Sjsg return container_of(work, struct delayed_work, work);
1237f4dd379Sjsg }
1247f4dd379Sjsg
1257f4dd379Sjsg static void
__delayed_work_tick(void * arg)1267f4dd379Sjsg __delayed_work_tick(void *arg)
1277f4dd379Sjsg {
1287f4dd379Sjsg struct delayed_work *dwork = arg;
1297f4dd379Sjsg
1307f4dd379Sjsg task_add(dwork->tq, &dwork->work.task);
1317f4dd379Sjsg }
1327f4dd379Sjsg
1337f4dd379Sjsg static inline void
INIT_DELAYED_WORK(struct delayed_work * dwork,work_func_t func)1347f4dd379Sjsg INIT_DELAYED_WORK(struct delayed_work *dwork, work_func_t func)
1357f4dd379Sjsg {
1367f4dd379Sjsg INIT_WORK(&dwork->work, func);
1377f4dd379Sjsg timeout_set(&dwork->to, __delayed_work_tick, &dwork->work);
1387f4dd379Sjsg }
1397f4dd379Sjsg
1407f4dd379Sjsg static inline void
INIT_DELAYED_WORK_ONSTACK(struct delayed_work * dwork,work_func_t func)1417f4dd379Sjsg INIT_DELAYED_WORK_ONSTACK(struct delayed_work *dwork, work_func_t func)
1427f4dd379Sjsg {
1437f4dd379Sjsg INIT_WORK(&dwork->work, func);
1447f4dd379Sjsg timeout_set(&dwork->to, __delayed_work_tick, &dwork->work);
1457f4dd379Sjsg }
1467f4dd379Sjsg
1475ca02815Sjsg #define __DELAYED_WORK_INITIALIZER(dw, fn, flags) { \
1485ca02815Sjsg .to = TIMEOUT_INITIALIZER(__delayed_work_tick, &(dw)), \
1495ca02815Sjsg .tq = NULL, \
1505ca02815Sjsg .work.tq = NULL, \
1515ca02815Sjsg .work.task = TASK_INITIALIZER((void (*)(void *))(fn), &(dw).work) \
1525ca02815Sjsg }
1535ca02815Sjsg
1547f4dd379Sjsg static inline bool
schedule_work(struct work_struct * work)1557f4dd379Sjsg schedule_work(struct work_struct *work)
1567f4dd379Sjsg {
15715e28df9Sjsg work->tq = (struct taskq *)system_wq;
1587f4dd379Sjsg return task_add(work->tq, &work->task);
1597f4dd379Sjsg }
1607f4dd379Sjsg
1617f4dd379Sjsg static inline bool
schedule_delayed_work(struct delayed_work * dwork,int jiffies)1627f4dd379Sjsg schedule_delayed_work(struct delayed_work *dwork, int jiffies)
1637f4dd379Sjsg {
1647f4dd379Sjsg dwork->tq = (struct taskq *)system_wq;
1657f4dd379Sjsg return timeout_add(&dwork->to, jiffies);
1667f4dd379Sjsg }
1677f4dd379Sjsg
1687f4dd379Sjsg static inline bool
queue_delayed_work(struct workqueue_struct * wq,struct delayed_work * dwork,int jiffies)1697f4dd379Sjsg queue_delayed_work(struct workqueue_struct *wq,
1707f4dd379Sjsg struct delayed_work *dwork, int jiffies)
1717f4dd379Sjsg {
1727f4dd379Sjsg dwork->tq = (struct taskq *)wq;
1737f4dd379Sjsg return timeout_add(&dwork->to, jiffies);
1747f4dd379Sjsg }
1757f4dd379Sjsg
1767f4dd379Sjsg static inline bool
mod_delayed_work(struct workqueue_struct * wq,struct delayed_work * dwork,int jiffies)1777f4dd379Sjsg mod_delayed_work(struct workqueue_struct *wq,
1787f4dd379Sjsg struct delayed_work *dwork, int jiffies)
1797f4dd379Sjsg {
1807f4dd379Sjsg dwork->tq = (struct taskq *)wq;
1817f4dd379Sjsg return (timeout_add(&dwork->to, jiffies) == 0);
1827f4dd379Sjsg }
1837f4dd379Sjsg
1847f4dd379Sjsg static inline bool
cancel_delayed_work(struct delayed_work * dwork)1857f4dd379Sjsg cancel_delayed_work(struct delayed_work *dwork)
1867f4dd379Sjsg {
187eb5a2f7aSjsg if (dwork->tq == NULL)
188eb5a2f7aSjsg return false;
1897f4dd379Sjsg if (timeout_del(&dwork->to))
1907f4dd379Sjsg return true;
1917f4dd379Sjsg return task_del(dwork->tq, &dwork->work.task);
1927f4dd379Sjsg }
1937f4dd379Sjsg
1947f4dd379Sjsg static inline bool
cancel_delayed_work_sync(struct delayed_work * dwork)1957f4dd379Sjsg cancel_delayed_work_sync(struct delayed_work *dwork)
1967f4dd379Sjsg {
197eb5a2f7aSjsg if (dwork->tq == NULL)
198eb5a2f7aSjsg return false;
1997f4dd379Sjsg if (timeout_del(&dwork->to))
2007f4dd379Sjsg return true;
2017f4dd379Sjsg return task_del(dwork->tq, &dwork->work.task);
2027f4dd379Sjsg }
2037f4dd379Sjsg
2047f4dd379Sjsg static inline bool
delayed_work_pending(struct delayed_work * dwork)2057f4dd379Sjsg delayed_work_pending(struct delayed_work *dwork)
2067f4dd379Sjsg {
2077f4dd379Sjsg if (timeout_pending(&dwork->to))
2087f4dd379Sjsg return true;
2097f4dd379Sjsg return task_pending(&dwork->work.task);
2107f4dd379Sjsg }
2117f4dd379Sjsg
2127f4dd379Sjsg void flush_workqueue(struct workqueue_struct *);
2137f4dd379Sjsg bool flush_work(struct work_struct *);
2147f4dd379Sjsg bool flush_delayed_work(struct delayed_work *);
21549261a46Sjsg
21649261a46Sjsg static inline void
flush_scheduled_work(void)21749261a46Sjsg flush_scheduled_work(void)
21849261a46Sjsg {
21949261a46Sjsg flush_workqueue(system_wq);
22049261a46Sjsg }
22149261a46Sjsg
22249261a46Sjsg static inline void
drain_workqueue(struct workqueue_struct * wq)22349261a46Sjsg drain_workqueue(struct workqueue_struct *wq)
22449261a46Sjsg {
22549261a46Sjsg flush_workqueue(wq);
22649261a46Sjsg }
2277f4dd379Sjsg
228ea7e6ab0Sjsg static inline void
destroy_work_on_stack(struct work_struct * work)229ea7e6ab0Sjsg destroy_work_on_stack(struct work_struct *work)
230ea7e6ab0Sjsg {
231ea7e6ab0Sjsg if (work->tq)
232ea7e6ab0Sjsg task_del(work->tq, &work->task);
233ea7e6ab0Sjsg }
234ea7e6ab0Sjsg
23549261a46Sjsg static inline void
destroy_delayed_work_on_stack(struct delayed_work * dwork)23649261a46Sjsg destroy_delayed_work_on_stack(struct delayed_work *dwork)
23749261a46Sjsg {
23849261a46Sjsg }
2397f4dd379Sjsg
240c349dbc7Sjsg struct rcu_work {
241c349dbc7Sjsg struct work_struct work;
242c349dbc7Sjsg struct rcu_head rcu;
243c349dbc7Sjsg };
244c349dbc7Sjsg
245c349dbc7Sjsg static inline void
INIT_RCU_WORK(struct rcu_work * work,work_func_t func)246c349dbc7Sjsg INIT_RCU_WORK(struct rcu_work *work, work_func_t func)
247c349dbc7Sjsg {
248c349dbc7Sjsg INIT_WORK(&work->work, func);
249c349dbc7Sjsg }
250c349dbc7Sjsg
251c349dbc7Sjsg static inline bool
queue_rcu_work(struct workqueue_struct * wq,struct rcu_work * work)252c349dbc7Sjsg queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *work)
253c349dbc7Sjsg {
254c349dbc7Sjsg return queue_work(wq, &work->work);
255c349dbc7Sjsg }
256c349dbc7Sjsg
2577f4dd379Sjsg #endif
258