completion.h revision 273246
1219820Sjeff/*- 2219820Sjeff * Copyright (c) 2010 Isilon Systems, Inc. 3219820Sjeff * Copyright (c) 2010 iX Systems, Inc. 4219820Sjeff * Copyright (c) 2010 Panasas, Inc. 5271127Shselasky * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd. 6219820Sjeff * All rights reserved. 7219820Sjeff * 8219820Sjeff * Redistribution and use in source and binary forms, with or without 9219820Sjeff * modification, are permitted provided that the following conditions 10219820Sjeff * are met: 11219820Sjeff * 1. Redistributions of source code must retain the above copyright 12219820Sjeff * notice unmodified, this list of conditions, and the following 13219820Sjeff * disclaimer. 14219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 15219820Sjeff * notice, this list of conditions and the following disclaimer in the 16219820Sjeff * documentation and/or other materials provided with the distribution. 17219820Sjeff * 18219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23219820Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24219820Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25219820Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26219820Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27219820Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28219820Sjeff */ 29219820Sjeff 30273246Shselasky#ifndef _LINUX_COMPLETION_H_ 31273246Shselasky#define _LINUX_COMPLETION_H_ 32271127Shselasky 33219820Sjeff#include <linux/errno.h> 34219820Sjeff 35219820Sjeff#include <sys/param.h> 36219820Sjeff#include <sys/systm.h> 37219820Sjeff#include <sys/sleepqueue.h> 38219820Sjeff#include <sys/kernel.h> 39219820Sjeff#include <sys/proc.h> 40219820Sjeff 41219820Sjeffstruct completion { 42219820Sjeff unsigned int done; 43219820Sjeff}; 44219820Sjeff 45219820Sjeff#define INIT_COMPLETION(c) ((c).done = 0) 46219820Sjeff#define init_completion(c) ((c)->done = 0) 47219820Sjeff 48219820Sjeffstatic inline void 49219820Sjeff_complete_common(struct completion *c, int all) 50219820Sjeff{ 51219820Sjeff int wakeup_swapper; 52219820Sjeff 53219820Sjeff sleepq_lock(c); 54219820Sjeff c->done++; 55219820Sjeff if (all) 56219820Sjeff wakeup_swapper = sleepq_broadcast(c, SLEEPQ_SLEEP, 0, 0); 57219820Sjeff else 58219820Sjeff wakeup_swapper = sleepq_signal(c, SLEEPQ_SLEEP, 0, 0); 59219820Sjeff sleepq_release(c); 60219820Sjeff if (wakeup_swapper) 61219820Sjeff kick_proc0(); 62219820Sjeff} 63219820Sjeff 64219820Sjeff#define complete(c) _complete_common(c, 0) 65219820Sjeff#define complete_all(c) _complete_common(c, 1) 66219820Sjeff 67219820Sjeff/* 68219820Sjeff * Indefinite wait for done != 0 with or without signals. 69219820Sjeff */ 70219820Sjeffstatic inline long 71219820Sjeff_wait_for_common(struct completion *c, int flags) 72219820Sjeff{ 73219820Sjeff 74219820Sjeff flags |= SLEEPQ_SLEEP; 75219820Sjeff for (;;) { 76219820Sjeff sleepq_lock(c); 77219820Sjeff if (c->done) 78219820Sjeff break; 79219820Sjeff sleepq_add(c, NULL, "completion", flags, 0); 80219820Sjeff if (flags & SLEEPQ_INTERRUPTIBLE) { 81219820Sjeff if (sleepq_wait_sig(c, 0) != 0) 82219820Sjeff return (-ERESTARTSYS); 83219820Sjeff } else 84219820Sjeff sleepq_wait(c, 0); 85219820Sjeff } 86219820Sjeff c->done--; 87219820Sjeff sleepq_release(c); 88219820Sjeff 89219820Sjeff return (0); 90219820Sjeff} 91219820Sjeff 92219820Sjeff#define wait_for_completion(c) _wait_for_common(c, 0) 93219820Sjeff#define wait_for_completion_interuptible(c) \ 94219820Sjeff _wait_for_common(c, SLEEPQ_INTERRUPTIBLE) 95219820Sjeff 96219820Sjeffstatic inline long 97219820Sjeff_wait_for_timeout_common(struct completion *c, long timeout, int flags) 98219820Sjeff{ 99219820Sjeff long end; 100219820Sjeff 101219820Sjeff end = ticks + timeout; 102219820Sjeff flags |= SLEEPQ_SLEEP; 103219820Sjeff for (;;) { 104219820Sjeff sleepq_lock(c); 105219820Sjeff if (c->done) 106219820Sjeff break; 107219820Sjeff sleepq_add(c, NULL, "completion", flags, 0); 108219820Sjeff sleepq_set_timeout(c, end - ticks); 109219820Sjeff if (flags & SLEEPQ_INTERRUPTIBLE) { 110219820Sjeff if (sleepq_timedwait_sig(c, 0) != 0) 111219820Sjeff return (-ERESTARTSYS); 112219820Sjeff } else 113219820Sjeff sleepq_timedwait(c, 0); 114219820Sjeff } 115219820Sjeff c->done--; 116219820Sjeff sleepq_release(c); 117219820Sjeff timeout = end - ticks; 118219820Sjeff 119219820Sjeff return (timeout > 0 ? timeout : 1); 120219820Sjeff} 121219820Sjeff 122219820Sjeff#define wait_for_completion_timeout(c, timeout) \ 123219820Sjeff _wait_for_timeout_common(c, timeout, 0) 124219820Sjeff#define wait_for_completion_interruptible_timeout(c, timeout) \ 125219820Sjeff _wait_for_timeout_common(c, timeout, SLEEPQ_INTERRUPTIBLE) 126219820Sjeff 127219820Sjeffstatic inline int 128219820Sjefftry_wait_for_completion(struct completion *c) 129219820Sjeff{ 130219820Sjeff int isdone; 131219820Sjeff 132219820Sjeff isdone = 1; 133219820Sjeff sleepq_lock(c); 134219820Sjeff if (c->done) 135219820Sjeff c->done--; 136219820Sjeff else 137219820Sjeff isdone = 0; 138219820Sjeff sleepq_release(c); 139219820Sjeff return (isdone); 140219820Sjeff} 141219820Sjeff 142219820Sjeffstatic inline int 143219820Sjeffcompletion_done(struct completion *c) 144219820Sjeff{ 145219820Sjeff int isdone; 146219820Sjeff 147219820Sjeff isdone = 1; 148219820Sjeff sleepq_lock(c); 149219820Sjeff if (c->done == 0) 150219820Sjeff isdone = 0; 151219820Sjeff sleepq_release(c); 152219820Sjeff return (isdone); 153219820Sjeff} 154219820Sjeff 155219820Sjeff#endif /* _LINUX_COMPLETION_H_ */ 156