completion.h revision 219820
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_COMPLETION_H_
29219820Sjeff#define	_LINUX_COMPLETION_H_
30219820Sjeff
31219820Sjeff#include <linux/errno.h>
32219820Sjeff#include <linux/sched.h>
33219820Sjeff#include <linux/wait.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