1219820Sjeff/*- 2219820Sjeff * Copyright (c) 2010 Isilon Systems, Inc. 3219820Sjeff * Copyright (c) 2010 iX Systems, Inc. 4219820Sjeff * Copyright (c) 2010 Panasas, Inc. 5219820Sjeff * All rights reserved. 6219820Sjeff * 7219820Sjeff * Redistribution and use in source and binary forms, with or without 8219820Sjeff * modification, are permitted provided that the following conditions 9219820Sjeff * are met: 10219820Sjeff * 1. Redistributions of source code must retain the above copyright 11219820Sjeff * notice unmodified, this list of conditions, and the following 12219820Sjeff * disclaimer. 13219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 14219820Sjeff * notice, this list of conditions and the following disclaimer in the 15219820Sjeff * documentation and/or other materials provided with the distribution. 16219820Sjeff * 17219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22219820Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23219820Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24219820Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25219820Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26219820Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27219820Sjeff */ 28219820Sjeff#ifndef _LINUX_WORKQUEUE_H_ 29219820Sjeff#define _LINUX_WORKQUEUE_H_ 30219820Sjeff 31219820Sjeff#include <linux/types.h> 32219820Sjeff#include <linux/kernel.h> 33219820Sjeff#include <linux/timer.h> 34219820Sjeff#include <linux/slab.h> 35219820Sjeff 36219820Sjeff#include <sys/taskqueue.h> 37219820Sjeff 38219820Sjeffstruct workqueue_struct { 39219820Sjeff struct taskqueue *taskqueue; 40219820Sjeff}; 41219820Sjeff 42219820Sjeffstruct work_struct { 43219820Sjeff struct task work_task; 44219820Sjeff struct taskqueue *taskqueue; 45219820Sjeff void (*fn)(struct work_struct *); 46219820Sjeff}; 47219820Sjeff 48219820Sjeffstruct delayed_work { 49219820Sjeff struct work_struct work; 50219820Sjeff struct callout timer; 51219820Sjeff}; 52219820Sjeff 53219820Sjeffstatic inline struct delayed_work * 54219820Sjeffto_delayed_work(struct work_struct *work) 55219820Sjeff{ 56219820Sjeff 57219820Sjeff return container_of(work, struct delayed_work, work); 58219820Sjeff} 59219820Sjeff 60219820Sjeff 61219820Sjeffstatic inline void 62219820Sjeff_work_fn(void *context, int pending) 63219820Sjeff{ 64219820Sjeff struct work_struct *work; 65219820Sjeff 66219820Sjeff work = context; 67219820Sjeff work->fn(work); 68219820Sjeff} 69219820Sjeff 70219820Sjeff#define INIT_WORK(work, func) \ 71219820Sjeffdo { \ 72219820Sjeff (work)->fn = (func); \ 73219820Sjeff (work)->taskqueue = NULL; \ 74219820Sjeff TASK_INIT(&(work)->work_task, 0, _work_fn, (work)); \ 75219820Sjeff} while (0) 76219820Sjeff 77219820Sjeff#define INIT_DELAYED_WORK(_work, func) \ 78219820Sjeffdo { \ 79219820Sjeff INIT_WORK(&(_work)->work, func); \ 80219820Sjeff callout_init(&(_work)->timer, CALLOUT_MPSAFE); \ 81219820Sjeff} while (0) 82219820Sjeff 83219820Sjeff#define INIT_DELAYED_WORK_DEFERRABLE INIT_DELAYED_WORK 84219820Sjeff 85219820Sjeff#define schedule_work(work) \ 86219820Sjeffdo { \ 87219820Sjeff (work)->taskqueue = taskqueue_thread; \ 88219820Sjeff taskqueue_enqueue(taskqueue_thread, &(work)->work_task); \ 89219820Sjeff} while (0) 90219820Sjeff 91219820Sjeff#define flush_scheduled_work() flush_taskqueue(taskqueue_thread) 92219820Sjeff 93219820Sjeff#define queue_work(q, work) \ 94219820Sjeffdo { \ 95219820Sjeff (work)->taskqueue = (q)->taskqueue; \ 96219820Sjeff taskqueue_enqueue((q)->taskqueue, &(work)->work_task); \ 97219820Sjeff} while (0) 98219820Sjeff 99219820Sjeffstatic inline void 100219820Sjeff_delayed_work_fn(void *arg) 101219820Sjeff{ 102219820Sjeff struct delayed_work *work; 103219820Sjeff 104219820Sjeff work = arg; 105219820Sjeff taskqueue_enqueue(work->work.taskqueue, &work->work.work_task); 106219820Sjeff} 107219820Sjeff 108219820Sjeffstatic inline int 109219820Sjeffqueue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, 110219820Sjeff unsigned long delay) 111219820Sjeff{ 112219820Sjeff int pending; 113219820Sjeff 114219820Sjeff pending = work->work.work_task.ta_pending; 115219820Sjeff work->work.taskqueue = wq->taskqueue; 116219820Sjeff if (delay != 0) 117219820Sjeff callout_reset(&work->timer, delay, _delayed_work_fn, work); 118219820Sjeff else 119219820Sjeff _delayed_work_fn((void *)work); 120219820Sjeff 121219820Sjeff return (!pending); 122219820Sjeff} 123219820Sjeff 124219820Sjeffstatic inline struct workqueue_struct * 125219820Sjeff_create_workqueue_common(char *name, int cpus) 126219820Sjeff{ 127219820Sjeff struct workqueue_struct *wq; 128219820Sjeff 129219820Sjeff wq = kmalloc(sizeof(*wq), M_WAITOK); 130219820Sjeff wq->taskqueue = taskqueue_create((name), M_WAITOK, 131219820Sjeff taskqueue_thread_enqueue, &wq->taskqueue); 132252555Snp taskqueue_start_threads(&wq->taskqueue, cpus, PWAIT, "%s", name); 133219820Sjeff 134219820Sjeff return (wq); 135219820Sjeff} 136219820Sjeff 137219820Sjeff 138219820Sjeff#define create_singlethread_workqueue(name) \ 139219820Sjeff _create_workqueue_common(name, 1) 140219820Sjeff 141219820Sjeff#define create_workqueue(name) \ 142219820Sjeff _create_workqueue_common(name, MAXCPU) 143219820Sjeff 144219820Sjeffstatic inline void 145219820Sjeffdestroy_workqueue(struct workqueue_struct *wq) 146219820Sjeff{ 147219820Sjeff taskqueue_free(wq->taskqueue); 148219820Sjeff kfree(wq); 149219820Sjeff} 150219820Sjeff 151219820Sjeff#define flush_workqueue(wq) flush_taskqueue((wq)->taskqueue) 152219820Sjeff 153219820Sjeffstatic inline void 154219820Sjeff_flush_fn(void *context, int pending) 155219820Sjeff{ 156219820Sjeff} 157219820Sjeff 158219820Sjeffstatic inline void 159219820Sjeffflush_taskqueue(struct taskqueue *tq) 160219820Sjeff{ 161219820Sjeff struct task flushtask; 162219820Sjeff 163221055Sjeff PHOLD(curproc); 164219820Sjeff TASK_INIT(&flushtask, 0, _flush_fn, NULL); 165219820Sjeff taskqueue_enqueue(tq, &flushtask); 166219820Sjeff taskqueue_drain(tq, &flushtask); 167221055Sjeff PRELE(curproc); 168219820Sjeff} 169219820Sjeff 170219820Sjeffstatic inline int 171219820Sjeffcancel_work_sync(struct work_struct *work) 172219820Sjeff{ 173219820Sjeff if (work->taskqueue && 174219820Sjeff taskqueue_cancel(work->taskqueue, &work->work_task, NULL)) 175219820Sjeff taskqueue_drain(work->taskqueue, &work->work_task); 176219820Sjeff return 0; 177219820Sjeff} 178219820Sjeff 179219820Sjeff/* 180219820Sjeff * This may leave work running on another CPU as it does on Linux. 181219820Sjeff */ 182219820Sjeffstatic inline int 183219820Sjeffcancel_delayed_work(struct delayed_work *work) 184219820Sjeff{ 185219820Sjeff 186219820Sjeff callout_stop(&work->timer); 187250893Sdelphij if (work->work.taskqueue) 188250893Sdelphij return (taskqueue_cancel(work->work.taskqueue, 189250893Sdelphij &work->work.work_task, NULL) == 0); 190219820Sjeff return 0; 191219820Sjeff} 192219820Sjeff 193219820Sjeff#endif /* _LINUX_WORKQUEUE_H_ */ 194