completion.h revision 271127
1115013Smarcel/*- 2160157Smarcel * Copyright (c) 2010 Isilon Systems, Inc. 3121642Smarcel * Copyright (c) 2010 iX Systems, Inc. 4121642Smarcel * Copyright (c) 2010 Panasas, Inc. 5121642Smarcel * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd. 6121642Smarcel * All rights reserved. 7121642Smarcel * 8121642Smarcel * Redistribution and use in source and binary forms, with or without 9121642Smarcel * modification, are permitted provided that the following conditions 10121642Smarcel * are met: 11115013Smarcel * 1. Redistributions of source code must retain the above copyright 12121642Smarcel * notice unmodified, this list of conditions, and the following 13121642Smarcel * disclaimer. 14121642Smarcel * 2. Redistributions in binary form must reproduce the above copyright 15121642Smarcel * notice, this list of conditions and the following disclaimer in the 16121642Smarcel * documentation and/or other materials provided with the distribution. 17121642Smarcel * 18121642Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19121642Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20121642Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21121642Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22121642Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23121642Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24121642Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25115013Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26115013Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27115013Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28115013Smarcel */ 29115013Smarcel 30115013Smarcel#ifndef _FBSD_COMPLETION_H_ 31115013Smarcel#define _FBSD_COMPLETION_H_ 32115013Smarcel 33115013Smarcel#include <linux/errno.h> 34120925Smarcel 35115013Smarcel#include <sys/param.h> 36160163Smarcel#include <sys/systm.h> 37160163Smarcel#include <sys/sleepqueue.h> 38160163Smarcel#include <sys/kernel.h> 39160163Smarcel#include <sys/proc.h> 40115013Smarcel 41115013Smarcelstruct completion { 42160163Smarcel unsigned int done; 43160163Smarcel}; 44160163Smarcel 45160163Smarcel#define INIT_COMPLETION(c) ((c).done = 0) 46115013Smarcel#define init_completion(c) ((c)->done = 0) 47115013Smarcel 48115013Smarcelstatic inline void 49115013Smarcel_complete_common(struct completion *c, int all) 50115013Smarcel{ 51115013Smarcel int wakeup_swapper; 52115013Smarcel 53115013Smarcel sleepq_lock(c); 54115013Smarcel c->done++; 55115013Smarcel if (all) 56115013Smarcel wakeup_swapper = sleepq_broadcast(c, SLEEPQ_SLEEP, 0, 0); 57115013Smarcel else 58115013Smarcel wakeup_swapper = sleepq_signal(c, SLEEPQ_SLEEP, 0, 0); 59115013Smarcel sleepq_release(c); 60115013Smarcel if (wakeup_swapper) 61160157Smarcel kick_proc0(); 62115013Smarcel} 63160157Smarcel 64160157Smarcel#define complete(c) _complete_common(c, 0) 65160157Smarcel#define complete_all(c) _complete_common(c, 1) 66160157Smarcel 67115013Smarcel/* 68115013Smarcel * Indefinite wait for done != 0 with or without signals. 69160157Smarcel */ 70115013Smarcelstatic inline long 71115013Smarcel_wait_for_common(struct completion *c, int flags) 72115013Smarcel{ 73160157Smarcel 74115013Smarcel flags |= SLEEPQ_SLEEP; 75115013Smarcel for (;;) { 76115013Smarcel sleepq_lock(c); 77160157Smarcel if (c->done) 78115013Smarcel break; 79115013Smarcel sleepq_add(c, NULL, "completion", flags, 0); 80115013Smarcel if (flags & SLEEPQ_INTERRUPTIBLE) { 81160157Smarcel if (sleepq_wait_sig(c, 0) != 0) 82115013Smarcel return (-ERESTARTSYS); 83115013Smarcel } else 84115013Smarcel sleepq_wait(c, 0); 85160157Smarcel } 86115013Smarcel c->done--; 87115013Smarcel sleepq_release(c); 88115013Smarcel 89115013Smarcel return (0); 90160157Smarcel} 91115013Smarcel 92115013Smarcel#define wait_for_completion(c) _wait_for_common(c, 0) 93115013Smarcel#define wait_for_completion_interuptible(c) \ 94160157Smarcel _wait_for_common(c, SLEEPQ_INTERRUPTIBLE) 95115013Smarcel 96115013Smarcelstatic inline long 97115013Smarcel_wait_for_timeout_common(struct completion *c, long timeout, int flags) 98160157Smarcel{ 99115013Smarcel long end; 100115013Smarcel 101115013Smarcel end = ticks + timeout; 102160157Smarcel flags |= SLEEPQ_SLEEP; 103115013Smarcel for (;;) { 104115013Smarcel sleepq_lock(c); 105115013Smarcel if (c->done) 106160157Smarcel break; 107115013Smarcel sleepq_add(c, NULL, "completion", flags, 0); 108115013Smarcel sleepq_set_timeout(c, end - ticks); 109115013Smarcel if (flags & SLEEPQ_INTERRUPTIBLE) { 110115013Smarcel if (sleepq_timedwait_sig(c, 0) != 0) 111160157Smarcel return (-ERESTARTSYS); 112115013Smarcel } else 113115013Smarcel sleepq_timedwait(c, 0); 114115013Smarcel } 115160157Smarcel c->done--; 116115013Smarcel sleepq_release(c); 117115013Smarcel timeout = end - ticks; 118115013Smarcel 119115013Smarcel return (timeout > 0 ? timeout : 1); 120160157Smarcel} 121115013Smarcel 122115013Smarcel#define wait_for_completion_timeout(c, timeout) \ 123115013Smarcel _wait_for_timeout_common(c, timeout, 0) 124115013Smarcel#define wait_for_completion_interruptible_timeout(c, timeout) \ 125160157Smarcel _wait_for_timeout_common(c, timeout, SLEEPQ_INTERRUPTIBLE) 126115013Smarcel 127115013Smarcelstatic inline int 128115013Smarceltry_wait_for_completion(struct completion *c) 129115013Smarcel{ 130160157Smarcel int isdone; 131115013Smarcel 132115013Smarcel isdone = 1; 133115013Smarcel sleepq_lock(c); 134115013Smarcel if (c->done) 135160157Smarcel c->done--; 136115013Smarcel else 137115013Smarcel isdone = 0; 138115013Smarcel sleepq_release(c); 139115013Smarcel return (isdone); 140160157Smarcel} 141115013Smarcel 142115013Smarcelstatic inline int 143115013Smarcelcompletion_done(struct completion *c) 144115013Smarcel{ 145160157Smarcel int isdone; 146115013Smarcel 147115013Smarcel isdone = 1; 148115013Smarcel sleepq_lock(c); 149115013Smarcel if (c->done == 0) 150160157Smarcel isdone = 0; 151115013Smarcel sleepq_release(c); 152115013Smarcel return (isdone); 153115013Smarcel} 154115013Smarcel 155160157Smarcel#endif /* _LINUX_COMPLETION_H_ */ 156115013Smarcel