2 * Copyright (c) 2010 Isilon Systems, Inc.
3 * Copyright (c) 2010 iX Systems, Inc.
4 * Copyright (c) 2010 Panasas, Inc.
5 * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
6 * Copyright (c) 2014-2017 François Tigeot
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice unmodified, this list of conditions, and the following
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #ifndef _LINUX_WORKQUEUE_H_
31 #define _LINUX_WORKQUEUE_H_
33 #include <sys/types.h>
34 #include <sys/malloc.h>
36 #include <linux/types.h>
37 #include <linux/kernel.h>
38 #include <linux/timer.h>
39 #include <linux/lockdep.h>
41 #include <sys/taskqueue.h>
43 struct workqueue_struct
{
44 struct taskqueue
*taskqueue
;
48 struct task work_task
;
49 struct taskqueue
*taskqueue
;
50 void (*fn
)(struct work_struct
*);
54 struct work_struct work
;
56 struct lwkt_token token
;
59 static inline struct delayed_work
*
60 to_delayed_work(struct work_struct
*work
)
63 return container_of(work
, struct delayed_work
, work
);
68 _work_fn(void *context
, int pending
)
70 struct work_struct
*work
;
76 #define INIT_WORK(work, func) \
78 (work)->fn = (func); \
79 (work)->taskqueue = NULL; \
80 TASK_INIT(&(work)->work_task, 0, _work_fn, (work)); \
83 #define INIT_WORK_ONSTACK(work, func) INIT_WORK(work, func)
85 #define INIT_DELAYED_WORK(_work, func) \
87 INIT_WORK(&(_work)->work, func); \
88 lwkt_token_init(&(_work)->token, "workqueue token"); \
89 callout_init_mp(&(_work)->timer); \
92 #define INIT_DEFERRABLE_WORK INIT_DELAYED_WORK
94 #define schedule_work(work) \
96 (work)->taskqueue = taskqueue_thread[mycpuid]; \
97 taskqueue_enqueue(taskqueue_thread[mycpuid], &(work)->work_task); \
100 #define flush_scheduled_work() flush_taskqueue(taskqueue_thread[mycpuid])
102 static inline int queue_work(struct workqueue_struct
*q
, struct work_struct
*work
)
104 (work
)->taskqueue
= (q
)->taskqueue
;
105 /* Return opposite val to align with Linux logic */
106 return !taskqueue_enqueue((q
)->taskqueue
, &(work
)->work_task
);
110 _delayed_work_fn(void *arg
)
112 struct delayed_work
*work
;
115 taskqueue_enqueue(work
->work
.taskqueue
, &work
->work
.work_task
);
119 queue_delayed_work(struct workqueue_struct
*wq
, struct delayed_work
*work
,
124 pending
= work
->work
.work_task
.ta_pending
;
125 work
->work
.taskqueue
= wq
->taskqueue
;
127 lwkt_gettoken(&work
->token
);
128 callout_reset(&work
->timer
, delay
, _delayed_work_fn
, work
);
129 lwkt_reltoken(&work
->token
);
131 _delayed_work_fn((void *)work
);
137 static inline bool schedule_delayed_work(struct delayed_work
*dwork
,
140 struct workqueue_struct wq
;
141 wq
.taskqueue
= taskqueue_thread
[mycpuid
];
142 return queue_delayed_work(&wq
, dwork
, delay
);
145 static inline struct workqueue_struct
*
146 _create_workqueue_common(char *name
, int cpus
)
148 struct workqueue_struct
*wq
;
150 wq
= kmalloc(sizeof(*wq
), M_DRM
, M_WAITOK
);
151 wq
->taskqueue
= taskqueue_create((name
), M_WAITOK
,
152 taskqueue_thread_enqueue
, &wq
->taskqueue
);
153 taskqueue_start_threads(&wq
->taskqueue
, cpus
,
154 TDPRI_KERN_DAEMON
, -1, "%s", name
);
160 #define create_singlethread_workqueue(name) \
161 _create_workqueue_common(name, 1)
163 #define create_workqueue(name) \
164 _create_workqueue_common(name, MAXCPU)
166 #define alloc_ordered_workqueue(name, flags) \
167 _create_workqueue_common(name, 1)
169 #define alloc_workqueue(name, flags, max_active) \
170 _create_workqueue_common(name, max_active)
173 destroy_workqueue(struct workqueue_struct
*wq
)
175 taskqueue_free(wq
->taskqueue
);
179 #define flush_workqueue(wq) flush_taskqueue((wq)->taskqueue)
182 _flush_fn(void *context
, int pending
)
187 flush_taskqueue(struct taskqueue
*tq
)
189 struct task flushtask
;
192 TASK_INIT(&flushtask
, 0, _flush_fn
, NULL
);
193 taskqueue_enqueue(tq
, &flushtask
);
194 taskqueue_drain(tq
, &flushtask
);
199 cancel_work_sync(struct work_struct
*work
)
201 if (work
->taskqueue
&&
202 taskqueue_cancel(work
->taskqueue
, &work
->work_task
, NULL
))
203 taskqueue_drain(work
->taskqueue
, &work
->work_task
);
208 * This may leave work running on another CPU as it does on Linux.
211 cancel_delayed_work(struct delayed_work
*work
)
214 lwkt_gettoken(&work
->token
);
215 callout_stop(&work
->timer
);
216 lwkt_reltoken(&work
->token
);
217 if (work
->work
.taskqueue
)
218 return (taskqueue_cancel(work
->work
.taskqueue
,
219 &work
->work
.work_task
, NULL
) == 0);
224 cancel_delayed_work_sync(struct delayed_work
*work
)
227 lwkt_gettoken(&work
->token
);
228 callout_drain(&work
->timer
);
229 lwkt_reltoken(&work
->token
);
230 if (work
->work
.taskqueue
&&
231 taskqueue_cancel(work
->work
.taskqueue
, &work
->work
.work_task
, NULL
))
232 taskqueue_drain(work
->work
.taskqueue
, &work
->work
.work_task
);
237 mod_delayed_work(struct workqueue_struct
*wq
, struct delayed_work
*dwork
,
240 cancel_delayed_work(dwork
);
241 queue_delayed_work(wq
, dwork
, delay
);
246 flush_work(struct work_struct
*work
)
248 taskqueue_drain(work
->taskqueue
, &work
->work_task
);
253 destroy_work_on_stack(struct work_struct
*work
)
257 /* System-wide workqueues */
258 extern struct workqueue_struct
*system_wq
;
259 extern struct workqueue_struct
*system_long_wq
;
260 extern struct workqueue_struct
*system_power_efficient_wq
;
262 #endif /* _LINUX_WORKQUEUE_H_ */