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-2016 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_DELAYED_WORK(_work, func) \
85 INIT_WORK(&(_work)->work, func); \
86 lwkt_token_init(&(_work)->token, "workqueue token"); \
87 callout_init_mp(&(_work)->timer); \
90 #define INIT_DEFERRABLE_WORK INIT_DELAYED_WORK
92 #define schedule_work(work) \
94 (work)->taskqueue = taskqueue_thread[mycpuid]; \
95 taskqueue_enqueue(taskqueue_thread[mycpuid], &(work)->work_task); \
98 #define flush_scheduled_work() flush_taskqueue(taskqueue_thread[mycpuid])
100 static inline int queue_work(struct workqueue_struct
*q
, struct work_struct
*work
)
102 (work
)->taskqueue
= (q
)->taskqueue
;
103 /* Return opposite val to align with Linux logic */
104 return !taskqueue_enqueue((q
)->taskqueue
, &(work
)->work_task
);
108 _delayed_work_fn(void *arg
)
110 struct delayed_work
*work
;
113 taskqueue_enqueue(work
->work
.taskqueue
, &work
->work
.work_task
);
117 queue_delayed_work(struct workqueue_struct
*wq
, struct delayed_work
*work
,
122 pending
= work
->work
.work_task
.ta_pending
;
123 work
->work
.taskqueue
= wq
->taskqueue
;
125 lwkt_gettoken(&work
->token
);
126 callout_reset(&work
->timer
, delay
, _delayed_work_fn
, work
);
127 lwkt_reltoken(&work
->token
);
129 _delayed_work_fn((void *)work
);
135 static inline bool schedule_delayed_work(struct delayed_work
*dwork
,
138 struct workqueue_struct wq
;
139 wq
.taskqueue
= taskqueue_thread
[mycpuid
];
140 return queue_delayed_work(&wq
, dwork
, delay
);
143 static inline struct workqueue_struct
*
144 _create_workqueue_common(char *name
, int cpus
)
146 struct workqueue_struct
*wq
;
148 wq
= kmalloc(sizeof(*wq
), M_DRM
, M_WAITOK
);
149 wq
->taskqueue
= taskqueue_create((name
), M_WAITOK
,
150 taskqueue_thread_enqueue
, &wq
->taskqueue
);
151 taskqueue_start_threads(&wq
->taskqueue
, cpus
,
152 TDPRI_KERN_DAEMON
, -1, "%s", name
);
158 #define create_singlethread_workqueue(name) \
159 _create_workqueue_common(name, 1)
161 #define create_workqueue(name) \
162 _create_workqueue_common(name, MAXCPU)
164 #define alloc_ordered_workqueue(name, flags) \
165 _create_workqueue_common(name, 1)
167 #define alloc_workqueue(name, flags, max_active) \
168 _create_workqueue_common(name, max_active)
171 destroy_workqueue(struct workqueue_struct
*wq
)
173 taskqueue_free(wq
->taskqueue
);
177 #define flush_workqueue(wq) flush_taskqueue((wq)->taskqueue)
180 _flush_fn(void *context
, int pending
)
185 flush_taskqueue(struct taskqueue
*tq
)
187 struct task flushtask
;
190 TASK_INIT(&flushtask
, 0, _flush_fn
, NULL
);
191 taskqueue_enqueue(tq
, &flushtask
);
192 taskqueue_drain(tq
, &flushtask
);
197 cancel_work_sync(struct work_struct
*work
)
199 if (work
->taskqueue
&&
200 taskqueue_cancel(work
->taskqueue
, &work
->work_task
, NULL
))
201 taskqueue_drain(work
->taskqueue
, &work
->work_task
);
206 * This may leave work running on another CPU as it does on Linux.
209 cancel_delayed_work(struct delayed_work
*work
)
212 lwkt_gettoken(&work
->token
);
213 callout_stop(&work
->timer
);
214 lwkt_reltoken(&work
->token
);
215 if (work
->work
.taskqueue
)
216 return (taskqueue_cancel(work
->work
.taskqueue
,
217 &work
->work
.work_task
, NULL
) == 0);
222 cancel_delayed_work_sync(struct delayed_work
*work
)
225 lwkt_gettoken(&work
->token
);
226 callout_drain(&work
->timer
);
227 lwkt_reltoken(&work
->token
);
228 if (work
->work
.taskqueue
&&
229 taskqueue_cancel(work
->work
.taskqueue
, &work
->work
.work_task
, NULL
))
230 taskqueue_drain(work
->work
.taskqueue
, &work
->work
.work_task
);
235 mod_delayed_work(struct workqueue_struct
*wq
, struct delayed_work
*dwork
,
238 cancel_delayed_work(dwork
);
239 queue_delayed_work(wq
, dwork
, delay
);
244 flush_work(struct work_struct
*work
)
246 taskqueue_drain(work
->taskqueue
, &work
->work_task
);
250 /* System-wide workqueues */
251 extern struct workqueue_struct
*system_wq
;
252 extern struct workqueue_struct
*system_long_wq
;
253 extern struct workqueue_struct
*system_power_efficient_wq
;
255 #endif /* _LINUX_WORKQUEUE_H_ */