completion.h revision 271127
161981Sbrian/*-
261981Sbrian * Copyright (c) 2010 Isilon Systems, Inc.
361981Sbrian * Copyright (c) 2010 iX Systems, Inc.
461981Sbrian * Copyright (c) 2010 Panasas, Inc.
561981Sbrian * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
661981Sbrian * All rights reserved.
761981Sbrian *
861981Sbrian * Redistribution and use in source and binary forms, with or without
961981Sbrian * modification, are permitted provided that the following conditions
1061981Sbrian * are met:
1161981Sbrian * 1. Redistributions of source code must retain the above copyright
1261981Sbrian *    notice unmodified, this list of conditions, and the following
1361981Sbrian *    disclaimer.
1461981Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1561981Sbrian *    notice, this list of conditions and the following disclaimer in the
1661981Sbrian *    documentation and/or other materials provided with the distribution.
1761981Sbrian *
1861981Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1961981Sbrian * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2061981Sbrian * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2161981Sbrian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2261981Sbrian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2361981Sbrian * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2461981Sbrian * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2565843Sbrian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2665843Sbrian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2765843Sbrian * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2865843Sbrian */
2965843Sbrian
3065843Sbrian#ifndef	_FBSD_COMPLETION_H_
3165843Sbrian#define	_FBSD_COMPLETION_H_
3265843Sbrian
3365843Sbrian#include <linux/errno.h>
3465843Sbrian
3561981Sbrian#include <sys/param.h>
3661981Sbrian#include <sys/systm.h>
3761981Sbrian#include <sys/sleepqueue.h>
3861981Sbrian#include <sys/kernel.h>
3961981Sbrian#include <sys/proc.h>
4061981Sbrian
4161981Sbrianstruct completion {
4261981Sbrian	unsigned int done;
4361981Sbrian};
4461981Sbrian
4561981Sbrian#define	INIT_COMPLETION(c)	((c).done = 0)
4661981Sbrian#define	init_completion(c)	((c)->done = 0)
4761981Sbrian
4861981Sbrianstatic inline void
4961981Sbrian_complete_common(struct completion *c, int all)
5061981Sbrian{
5161981Sbrian	int wakeup_swapper;
5261981Sbrian
5361981Sbrian	sleepq_lock(c);
5461981Sbrian	c->done++;
5561981Sbrian	if (all)
5661981Sbrian		wakeup_swapper = sleepq_broadcast(c, SLEEPQ_SLEEP, 0, 0);
5761981Sbrian	else
5861981Sbrian		wakeup_swapper = sleepq_signal(c, SLEEPQ_SLEEP, 0, 0);
5961981Sbrian	sleepq_release(c);
6061981Sbrian	if (wakeup_swapper)
6161981Sbrian		kick_proc0();
6261981Sbrian}
6361981Sbrian
6461981Sbrian#define	complete(c)	_complete_common(c, 0)
6561981Sbrian#define	complete_all(c)	_complete_common(c, 1)
6661981Sbrian
6761981Sbrian/*
6861981Sbrian * Indefinite wait for done != 0 with or without signals.
6961981Sbrian */
7061981Sbrianstatic inline long
7161981Sbrian_wait_for_common(struct completion *c, int flags)
7261981Sbrian{
7361981Sbrian
7474314Sbrian	flags |= SLEEPQ_SLEEP;
7561981Sbrian	for (;;) {
7661981Sbrian		sleepq_lock(c);
7761981Sbrian		if (c->done)
7861981Sbrian			break;
7961981Sbrian		sleepq_add(c, NULL, "completion", flags, 0);
8061981Sbrian		if (flags & SLEEPQ_INTERRUPTIBLE) {
8162054Sbrian			if (sleepq_wait_sig(c, 0) != 0)
8277496Sbrian				return (-ERESTARTSYS);
8377492Sbrian		} else
8461981Sbrian			sleepq_wait(c, 0);
8561981Sbrian	}
8661981Sbrian	c->done--;
8761981Sbrian	sleepq_release(c);
8861981Sbrian
8961981Sbrian	return (0);
9061981Sbrian}
9161981Sbrian
9261981Sbrian#define	wait_for_completion(c)	_wait_for_common(c, 0)
9362644Ssheldonh#define	wait_for_completion_interuptible(c)				\
9461981Sbrian	_wait_for_common(c, SLEEPQ_INTERRUPTIBLE)
9561981Sbrian
9661981Sbrianstatic inline long
9761981Sbrian_wait_for_timeout_common(struct completion *c, long timeout, int flags)
9861981Sbrian{
9961981Sbrian	long end;
10061981Sbrian
10161981Sbrian	end = ticks + timeout;
10261981Sbrian	flags |= SLEEPQ_SLEEP;
10361981Sbrian	for (;;) {
10461981Sbrian		sleepq_lock(c);
10594342Sgshapiro		if (c->done)
10661981Sbrian			break;
10761981Sbrian		sleepq_add(c, NULL, "completion", flags, 0);
10861981Sbrian		sleepq_set_timeout(c, end - ticks);
10987514Scjc		if (flags & SLEEPQ_INTERRUPTIBLE) {
11061981Sbrian			if (sleepq_timedwait_sig(c, 0) != 0)
11161981Sbrian				return (-ERESTARTSYS);
11261981Sbrian		} else
11362274Sbrian			sleepq_timedwait(c, 0);
11461981Sbrian	}
11575809Sdirk	c->done--;
11675809Sdirk	sleepq_release(c);
11775809Sdirk	timeout = end - ticks;
11875809Sdirk
11972677Speter	return (timeout > 0 ? timeout : 1);
12072677Speter}
12194342Sgshapiro
12272677Speter#define	wait_for_completion_timeout(c, timeout)				\
12361981Sbrian	_wait_for_timeout_common(c, timeout, 0)
12461981Sbrian#define	wait_for_completion_interruptible_timeout(c, timeout)		\
12561981Sbrian	_wait_for_timeout_common(c, timeout, SLEEPQ_INTERRUPTIBLE)
12661981Sbrian
12787514Scjcstatic inline int
12887514Scjctry_wait_for_completion(struct completion *c)
129101607Sfanf{
13087514Scjc	int isdone;
13187514Scjc
13287514Scjc	isdone = 1;
13387514Scjc	sleepq_lock(c);
13487514Scjc	if (c->done)
13587514Scjc		c->done--;
13687514Scjc	else
13787514Scjc		isdone = 0;
13887514Scjc	sleepq_release(c);
13987514Scjc	return (isdone);
14087514Scjc}
14187514Scjc
14287514Scjcstatic inline int
14387514Scjccompletion_done(struct completion *c)
14487514Scjc{
14587514Scjc	int isdone;
14687514Scjc
14787514Scjc	isdone = 1;
14887514Scjc	sleepq_lock(c);
14987514Scjc	if (c->done == 0)
15087514Scjc		isdone = 0;
15187514Scjc	sleepq_release(c);
15287514Scjc	return (isdone);
15387514Scjc}
15487514Scjc
15587514Scjc#endif	/* _LINUX_COMPLETION_H_ */
15687514Scjc