completion.h revision 219820
11541Srgrimes/*-
2181905Sed * Copyright (c) 2010 Isilon Systems, Inc.
397379Sdes * Copyright (c) 2010 iX Systems, Inc.
497379Sdes * Copyright (c) 2010 Panasas, Inc.
5181905Sed * All rights reserved.
6181905Sed *
797379Sdes * Redistribution and use in source and binary forms, with or without
81541Srgrimes * modification, are permitted provided that the following conditions
91541Srgrimes * are met:
101541Srgrimes * 1. Redistributions of source code must retain the above copyright
111541Srgrimes *    notice unmodified, this list of conditions, and the following
121541Srgrimes *    disclaimer.
131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer in the
151541Srgrimes *    documentation and/or other materials provided with the distribution.
161541Srgrimes *
17181905Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
181541Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
191541Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20181905Sed * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
211541Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
221541Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231541Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241541Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251541Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
261541Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271541Srgrimes */
281541Srgrimes#ifndef	_LINUX_COMPLETION_H_
2950477Speter#define	_LINUX_COMPLETION_H_
301541Srgrimes
311541Srgrimes#include <linux/errno.h>
322165Spaul#include <linux/sched.h>
334825Sbde#include <linux/wait.h>
342165Spaul
35181907Sed#include <sys/param.h>
3659288Sjlemon#include <sys/systm.h>
37181907Sed#include <sys/sleepqueue.h>
38181907Sed#include <sys/kernel.h>
39181907Sed#include <sys/proc.h>
4070834Swollman
41181907Sedstruct completion {
42181907Sed	unsigned int done;
43181907Sed};
441541Srgrimes
45135377Sphk#define	INIT_COMPLETION(c)	((c).done = 0)
46181907Sed#define	init_completion(c)	((c)->done = 0)
47181907Sed
48181907Sedstatic inline void
49181907Sed_complete_common(struct completion *c, int all)
50131387Smarcel{
51181907Sed	int wakeup_swapper;
52131373Sphk
531541Srgrimes	sleepq_lock(c);
54181907Sed	c->done++;
551541Srgrimes	if (all)
56181907Sed		wakeup_swapper = sleepq_broadcast(c, SLEEPQ_SLEEP, 0, 0);
57181907Sed	else
58181907Sed		wakeup_swapper = sleepq_signal(c, SLEEPQ_SLEEP, 0, 0);
59181907Sed	sleepq_release(c);
601541Srgrimes	if (wakeup_swapper)
611541Srgrimes		kick_proc0();
62181907Sed}
63181907Sed
64181907Sed#define	complete(c)	_complete_common(c, 0)
65181907Sed#define	complete_all(c)	_complete_common(c, 1)
66183922Sed
67188147Sed/*
68188147Sed * Indefinite wait for done != 0 with or without signals.
69188147Sed */
70188147Sedstatic inline long
71188147Sed_wait_for_common(struct completion *c, int flags)
72188147Sed{
73188147Sed
74188147Sed	flags |= SLEEPQ_SLEEP;
75188147Sed	for (;;) {
76188147Sed		sleepq_lock(c);
77188147Sed		if (c->done)
78188147Sed			break;
79188147Sed		sleepq_add(c, NULL, "completion", flags, 0);
80181907Sed		if (flags & SLEEPQ_INTERRUPTIBLE) {
81188147Sed			if (sleepq_wait_sig(c, 0) != 0)
82188147Sed				return (-ERESTARTSYS);
83188147Sed		} else
84188147Sed			sleepq_wait(c, 0);
85188147Sed	}
86181907Sed	c->done--;
87130261Sphk	sleepq_release(c);
88181907Sed
89181907Sed	return (0);
90181907Sed}
91181907Sed
92181907Sed#define	wait_for_completion(c)	_wait_for_common(c, 0)
93131373Sphk#define	wait_for_completion_interuptible(c)				\
94181907Sed	_wait_for_common(c, SLEEPQ_INTERRUPTIBLE)
95181907Sed
96181907Sedstatic inline long
97181907Sed_wait_for_timeout_common(struct completion *c, long timeout, int flags)
98181907Sed{
991541Srgrimes	long end;
100181907Sed
101181907Sed	end = ticks + timeout;
102181907Sed	flags |= SLEEPQ_SLEEP;
103181907Sed	for (;;) {
1041541Srgrimes		sleepq_lock(c);
105181907Sed		if (c->done)
106181907Sed			break;
107181907Sed		sleepq_add(c, NULL, "completion", flags, 0);
108181907Sed		sleepq_set_timeout(c, end - ticks);
109182763Sed		if (flags & SLEEPQ_INTERRUPTIBLE) {
1101541Srgrimes			if (sleepq_timedwait_sig(c, 0) != 0)
111181907Sed				return (-ERESTARTSYS);
112181907Sed		} else
113181907Sed			sleepq_timedwait(c, 0);
114181907Sed	}
115181907Sed	c->done--;
116181907Sed	sleepq_release(c);
117181907Sed	timeout = end - ticks;
118183276Sed
119181907Sed	return (timeout > 0 ? timeout : 1);
120181907Sed}
121181907Sed
122181907Sed#define	wait_for_completion_timeout(c, timeout)				\
123181907Sed	_wait_for_timeout_common(c, timeout, 0)
124181907Sed#define	wait_for_completion_interruptible_timeout(c, timeout)		\
125183276Sed	_wait_for_timeout_common(c, timeout, SLEEPQ_INTERRUPTIBLE)
126183276Sed
127181907Sedstatic inline int
12897366Sdestry_wait_for_completion(struct completion *c)
12997366Sdes{
13097366Sdes	int isdone;
131181907Sed
1327850Sbde	isdone = 1;
133181907Sed	sleepq_lock(c);
134181907Sed	if (c->done)
135181907Sed		c->done--;
136181907Sed	else
137181907Sed		isdone = 0;
138181907Sed	sleepq_release(c);
139181907Sed	return (isdone);
140181907Sed}
141181907Sed
142181907Sedstatic inline int
143181907Sedcompletion_done(struct completion *c)
144181907Sed{
145181907Sed	int isdone;
146181907Sed
1471541Srgrimes	isdone = 1;
1481541Srgrimes	sleepq_lock(c);
14955205Speter	if (c->done == 0)
150135368Sphk		isdone = 0;
151181907Sed	sleepq_release(c);
152183274Sed	return (isdone);
153183274Sed}
154183274Sed
155183274Sed#endif	/* _LINUX_COMPLETION_H_ */
156135368Sphk