workqueue.h revision 250893
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 2010 Isilon Systems, Inc. 31590Srgrimes * Copyright (c) 2010 iX Systems, Inc. 41590Srgrimes * Copyright (c) 2010 Panasas, Inc. 51590Srgrimes * All rights reserved. 61590Srgrimes * 71590Srgrimes * Redistribution and use in source and binary forms, with or without 81590Srgrimes * modification, are permitted provided that the following conditions 91590Srgrimes * are met: 101590Srgrimes * 1. Redistributions of source code must retain the above copyright 111590Srgrimes * notice unmodified, this list of conditions, and the following 121590Srgrimes * disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer in the 151590Srgrimes * documentation and/or other materials provided with the distribution. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 181590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 191590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 201590Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 211590Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 221590Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231590Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241590Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251590Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 261590Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 271590Srgrimes */ 281590Srgrimes#ifndef _LINUX_WORKQUEUE_H_ 291590Srgrimes#define _LINUX_WORKQUEUE_H_ 301590Srgrimes 311590Srgrimes#include <linux/types.h> 321590Srgrimes#include <linux/kernel.h> 331590Srgrimes#include <linux/timer.h> 341590Srgrimes#include <linux/slab.h> 3527572Scharnier 361590Srgrimes#include <sys/taskqueue.h> 371590Srgrimes 381590Srgrimesstruct workqueue_struct { 391590Srgrimes struct taskqueue *taskqueue; 401590Srgrimes}; 4127572Scharnier 421590Srgrimesstruct work_struct { 4327572Scharnier struct task work_task; 4427572Scharnier struct taskqueue *taskqueue; 4550477Speter void (*fn)(struct work_struct *); 461590Srgrimes}; 471590Srgrimes 4832295Shelbigstruct delayed_work { 4927572Scharnier struct work_struct work; 5032295Shelbig struct callout timer; 511590Srgrimes}; 5278717Sdd 5332295Shelbigstatic inline struct delayed_work * 5427572Scharnierto_delayed_work(struct work_struct *work) 551590Srgrimes{ 5692920Simp 5792920Simp return container_of(work, struct delayed_work, work); 5827572Scharnier} 591590Srgrimes 601590Srgrimes 611590Srgrimesstatic inline void 621590Srgrimes_work_fn(void *context, int pending) 631590Srgrimes{ 641590Srgrimes struct work_struct *work; 651590Srgrimes 6627572Scharnier work = context; 671590Srgrimes work->fn(work); 681590Srgrimes} 691590Srgrimes 701590Srgrimes#define INIT_WORK(work, func) \ 711590Srgrimesdo { \ 721590Srgrimes (work)->fn = (func); \ 7375906Skris (work)->taskqueue = NULL; \ 7477451Sdd TASK_INIT(&(work)->work_task, 0, _work_fn, (work)); \ 7577451Sdd} while (0) 7632295Shelbig 771590Srgrimes#define INIT_DELAYED_WORK(_work, func) \ 781590Srgrimesdo { \ 7932295Shelbig INIT_WORK(&(_work)->work, func); \ 8032295Shelbig callout_init(&(_work)->timer, CALLOUT_MPSAFE); \ 8132295Shelbig} while (0) 821590Srgrimes 831590Srgrimes#define INIT_DELAYED_WORK_DEFERRABLE INIT_DELAYED_WORK 8480381Ssheldonh 851590Srgrimes#define schedule_work(work) \ 8627572Scharnierdo { \ 871590Srgrimes (work)->taskqueue = taskqueue_thread; \ 8875906Skris taskqueue_enqueue(taskqueue_thread, &(work)->work_task); \ 8975906Skris} while (0) 9075906Skris 911590Srgrimes#define flush_scheduled_work() flush_taskqueue(taskqueue_thread) 921590Srgrimes 931590Srgrimes#define queue_work(q, work) \ 941590Srgrimesdo { \ 951590Srgrimes (work)->taskqueue = (q)->taskqueue; \ 9632295Shelbig taskqueue_enqueue((q)->taskqueue, &(work)->work_task); \ 971590Srgrimes} while (0) 981590Srgrimes 991590Srgrimesstatic inline void 1001590Srgrimes_delayed_work_fn(void *arg) 1011590Srgrimes{ 1021590Srgrimes struct delayed_work *work; 1031590Srgrimes 1041590Srgrimes work = arg; 1051590Srgrimes taskqueue_enqueue(work->work.taskqueue, &work->work.work_task); 1061590Srgrimes} 1071590Srgrimes 1081590Srgrimesstatic inline int 1091590Srgrimesqueue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, 1101590Srgrimes unsigned long delay) 1111590Srgrimes{ 11232295Shelbig int pending; 11332295Shelbig 11432295Shelbig pending = work->work.work_task.ta_pending; 11532295Shelbig work->work.taskqueue = wq->taskqueue; 1161590Srgrimes if (delay != 0) 11732295Shelbig callout_reset(&work->timer, delay, _delayed_work_fn, work); 11832295Shelbig else 11932295Shelbig _delayed_work_fn((void *)work); 12032295Shelbig 12132295Shelbig return (!pending); 12232295Shelbig} 12332295Shelbig 12432295Shelbigstatic inline struct workqueue_struct * 12532295Shelbig_create_workqueue_common(char *name, int cpus) 12632295Shelbig{ 12732295Shelbig struct workqueue_struct *wq; 12832295Shelbig 12932295Shelbig wq = kmalloc(sizeof(*wq), M_WAITOK); 13032295Shelbig wq->taskqueue = taskqueue_create((name), M_WAITOK, 13132295Shelbig taskqueue_thread_enqueue, &wq->taskqueue); 13232295Shelbig taskqueue_start_threads(&wq->taskqueue, cpus, PWAIT, (name)); 13332295Shelbig 1341590Srgrimes return (wq); 13532295Shelbig} 1361590Srgrimes 1371590Srgrimes 1381590Srgrimes#define create_singlethread_workqueue(name) \ 1391590Srgrimes _create_workqueue_common(name, 1) 1401590Srgrimes 14127572Scharnier#define create_workqueue(name) \ 1421590Srgrimes _create_workqueue_common(name, MAXCPU) 1431590Srgrimes 1441590Srgrimesstatic inline void 1451590Srgrimesdestroy_workqueue(struct workqueue_struct *wq) 14677451Sdd{ 14732295Shelbig taskqueue_free(wq->taskqueue); 1481590Srgrimes kfree(wq); 1491590Srgrimes} 15027572Scharnier 1511590Srgrimes#define flush_workqueue(wq) flush_taskqueue((wq)->taskqueue) 1521590Srgrimes 15332295Shelbigstatic inline void 15432295Shelbig_flush_fn(void *context, int pending) 1551590Srgrimes{ 1561590Srgrimes} 1571590Srgrimes 15835182Sstevestatic inline void 15935182Ssteveflush_taskqueue(struct taskqueue *tq) 1601590Srgrimes{ 1611590Srgrimes struct task flushtask; 1621590Srgrimes 1631590Srgrimes PHOLD(curproc); 1641590Srgrimes TASK_INIT(&flushtask, 0, _flush_fn, NULL); 1651590Srgrimes taskqueue_enqueue(tq, &flushtask); 1661590Srgrimes taskqueue_drain(tq, &flushtask); 1671590Srgrimes PRELE(curproc); 1681590Srgrimes} 16980381Ssheldonh 1701590Srgrimesstatic inline int 1711590Srgrimescancel_work_sync(struct work_struct *work) 1721590Srgrimes{ 1731590Srgrimes if (work->taskqueue && 1741590Srgrimes taskqueue_cancel(work->taskqueue, &work->work_task, NULL)) 1751590Srgrimes taskqueue_drain(work->taskqueue, &work->work_task); 1761590Srgrimes return 0; 1771590Srgrimes} 17880381Ssheldonh 1791590Srgrimes/* 1801590Srgrimes * This may leave work running on another CPU as it does on Linux. 1811590Srgrimes */ 1821590Srgrimesstatic inline int 1831590Srgrimescancel_delayed_work(struct delayed_work *work) 1841590Srgrimes{ 18580381Ssheldonh 1861590Srgrimes callout_stop(&work->timer); 1871590Srgrimes if (work->work.taskqueue) 1881590Srgrimes return (taskqueue_cancel(work->work.taskqueue, 1891590Srgrimes &work->work.work_task, NULL) == 0); 19080381Ssheldonh return 0; 1911590Srgrimes} 1921590Srgrimes 1931590Srgrimes#endif /* _LINUX_WORKQUEUE_H_ */ 19427572Scharnier