workqueue.h revision 225736
156167Sru/*-
2100518Sru * Copyright (c) 2010 Isilon Systems, Inc.
3100518Sru * Copyright (c) 2010 iX Systems, Inc.
442688Smarkm * Copyright (c) 2010 Panasas, Inc.
593144Sru * All rights reserved.
693144Sru *
793144Sru * Redistribution and use in source and binary forms, with or without
842688Smarkm * modification, are permitted provided that the following conditions
942688Smarkm * are met:
10100518Sru * 1. Redistributions of source code must retain the above copyright
1193144Sru *    notice unmodified, this list of conditions, and the following
1293144Sru *    disclaimer.
1393144Sru * 2. Redistributions in binary form must reproduce the above copyright
1493144Sru *    notice, this list of conditions and the following disclaimer in the
1593144Sru *    documentation and/or other materials provided with the distribution.
1693144Sru *
17100518Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1893144Sru * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1993144Sru * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20100518Sru * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2142688Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2242688Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23100518Sru * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24100518Sru * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2542688Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2642688Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27100518Sru */
2893144Sru#ifndef	_LINUX_WORKQUEUE_H_
2942688Smarkm#define	_LINUX_WORKQUEUE_H_
30146522Sru
31146522Sru#include <linux/types.h>
32146522Sru#include <linux/kernel.h>
33100518Sru#include <linux/timer.h>
3493144Sru#include <linux/slab.h>
3542688Smarkm
3693144Sru#include <sys/taskqueue.h>
3793144Sru
3893144Srustruct workqueue_struct {
3956167Sru	struct taskqueue	*taskqueue;
40146522Sru};
41146522Sru
42146522Srustruct work_struct {
43146522Sru	struct	task 		work_task;
44146522Sru	struct	taskqueue	*taskqueue;
45146522Sru	void			(*fn)(struct work_struct *);
46146522Sru};
47146522Sru
48146522Srustruct delayed_work {
49146522Sru	struct work_struct	work;
50146522Sru	struct callout		timer;
51146522Sru};
52114479Sru
53114479Srustatic inline struct delayed_work *
54114479Sruto_delayed_work(struct work_struct *work)
55114479Sru{
56146522Sru
57146522Sru 	return container_of(work, struct delayed_work, work);
58146522Sru}
5942688Smarkm
60146522Sru
61146522Srustatic inline void
6293144Sru_work_fn(void *context, int pending)
6342688Smarkm{
64146522Sru	struct work_struct *work;
65146522Sru
6693144Sru	work = context;
6742688Smarkm	work->fn(work);
68146522Sru}
69146522Sru
70146522Sru#define	INIT_WORK(work, func) 	 					\
7142688Smarkmdo {									\
72146522Sru	(work)->fn = (func);						\
73146522Sru	(work)->taskqueue = NULL;					\
74146522Sru	TASK_INIT(&(work)->work_task, 0, _work_fn, (work));		\
75146522Sru} while (0)
76100518Sru
7793144Sru#define	INIT_DELAYED_WORK(_work, func)					\
7842688Smarkmdo {									\
79100518Sru	INIT_WORK(&(_work)->work, func);				\
8093144Sru	callout_init(&(_work)->timer, CALLOUT_MPSAFE);			\
8142688Smarkm} while (0)
82146522Sru
83146522Sru#define	INIT_DELAYED_WORK_DEFERRABLE	INIT_DELAYED_WORK
8442688Smarkm
85100518Sru#define	schedule_work(work)						\
8693144Srudo {									\
8742688Smarkm	(work)->taskqueue = taskqueue_thread;				\
88100518Sru	taskqueue_enqueue(taskqueue_thread, &(work)->work_task);	\
8993144Sru} while (0)
9056167Sru
91100518Sru#define	flush_scheduled_work()	flush_taskqueue(taskqueue_thread)
9293144Sru
9342688Smarkm#define	queue_work(q, work)						\
94100518Srudo {									\
9593144Sru	(work)->taskqueue = (q)->taskqueue;				\
9642688Smarkm	taskqueue_enqueue((q)->taskqueue, &(work)->work_task);		\
97100518Sru} while (0)
9893144Sru
9942688Smarkmstatic inline void
10093144Sru_delayed_work_fn(void *arg)
10142688Smarkm{
10242688Smarkm	struct delayed_work *work;
103114479Sru
104114479Sru	work = arg;
105114479Sru	taskqueue_enqueue(work->work.taskqueue, &work->work.work_task);
106100518Sru}
10793144Sru
10842688Smarkmstatic inline int
10993144Sruqueue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work,
110146522Sru    unsigned long delay)
11142688Smarkm{
112146522Sru	int pending;
113146522Sru
114146522Sru	pending = work->work.work_task.ta_pending;
115114479Sru	work->work.taskqueue = wq->taskqueue;
11693144Sru	if (delay != 0)
11742688Smarkm		callout_reset(&work->timer, delay, _delayed_work_fn, work);
118114479Sru	else
119114479Sru		_delayed_work_fn((void *)work);
120114479Sru
121114479Sru	return (!pending);
122100518Sru}
12393144Sru
12442688Smarkmstatic inline struct workqueue_struct *
12593144Sru_create_workqueue_common(char *name, int cpus)
12693144Sru{
12742688Smarkm	struct workqueue_struct *wq;
12893144Sru
12993144Sru	wq = kmalloc(sizeof(*wq), M_WAITOK);
13042688Smarkm	wq->taskqueue = taskqueue_create((name), M_WAITOK,
131100518Sru	    taskqueue_thread_enqueue,  &wq->taskqueue);
13293144Sru	taskqueue_start_threads(&wq->taskqueue, cpus, PWAIT, (name));
13342688Smarkm
134100518Sru	return (wq);
13593144Sru}
13642688Smarkm
137100518Sru
13893144Sru#define	create_singlethread_workqueue(name)				\
13942688Smarkm	_create_workqueue_common(name, 1)
140146522Sru
141146522Sru#define	create_workqueue(name)						\
142146522Sru	_create_workqueue_common(name, MAXCPU)
143146522Sru
144146522Srustatic inline void
145146522Srudestroy_workqueue(struct workqueue_struct *wq)
146100518Sru{
147114479Sru	taskqueue_free(wq->taskqueue);
14893144Sru	kfree(wq);
149100518Sru}
15042688Smarkm
15142688Smarkm#define	flush_workqueue(wq)	flush_taskqueue((wq)->taskqueue)
152100518Sru
15342688Smarkmstatic inline void
15442688Smarkm_flush_fn(void *context, int pending)
155100518Sru{
15693144Sru}
15793144Sru
158100518Srustatic inline void
15993144Sruflush_taskqueue(struct taskqueue *tq)
16093144Sru{
161100518Sru	struct task flushtask;
16242688Smarkm
16342688Smarkm	PHOLD(curproc);
164114479Sru	TASK_INIT(&flushtask, 0, _flush_fn, NULL);
165114479Sru	taskqueue_enqueue(tq, &flushtask);
166114479Sru	taskqueue_drain(tq, &flushtask);
167100518Sru	PRELE(curproc);
16893144Sru}
16993144Sru
170100518Srustatic inline int
17142688Smarkmcancel_work_sync(struct work_struct *work)
17242688Smarkm{
173100518Sru	if (work->taskqueue &&
17493144Sru	    taskqueue_cancel(work->taskqueue, &work->work_task, NULL))
17593144Sru		taskqueue_drain(work->taskqueue, &work->work_task);
176100518Sru	return 0;
17793144Sru}
17893144Sru
179146522Sru/*
180146522Sru * This may leave work running on another CPU as it does on Linux.
181146522Sru */
182100518Srustatic inline int
18342688Smarkmcancel_delayed_work(struct delayed_work *work)
18442688Smarkm{
185100518Sru
18693144Sru	callout_stop(&work->timer);
18793144Sru	if (work->work.taskqueue &&
188100518Sru	    taskqueue_cancel(work->work.taskqueue, &work->work.work_task, NULL))
18942688Smarkm		taskqueue_drain(work->work.taskqueue, &work->work.work_task);
19042688Smarkm	return 0;
191100518Sru}
19242688Smarkm
19342688Smarkm#endif	/* _LINUX_WORKQUEUE_H_ */
194100518Sru