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