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