124b50f1aSFrançois Tigeot /*
2647fa573SFrançois Tigeot * Copyright (c) 2014-2020 François Tigeot <ftigeot@wolfpond.org>
324b50f1aSFrançois Tigeot * All rights reserved.
424b50f1aSFrançois Tigeot *
524b50f1aSFrançois Tigeot * Redistribution and use in source and binary forms, with or without
624b50f1aSFrançois Tigeot * modification, are permitted provided that the following conditions
724b50f1aSFrançois Tigeot * are met:
824b50f1aSFrançois Tigeot * 1. Redistributions of source code must retain the above copyright
924b50f1aSFrançois Tigeot * notice unmodified, this list of conditions, and the following
1024b50f1aSFrançois Tigeot * disclaimer.
1124b50f1aSFrançois Tigeot * 2. Redistributions in binary form must reproduce the above copyright
1224b50f1aSFrançois Tigeot * notice, this list of conditions and the following disclaimer in the
1324b50f1aSFrançois Tigeot * documentation and/or other materials provided with the distribution.
1424b50f1aSFrançois Tigeot *
1524b50f1aSFrançois Tigeot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1624b50f1aSFrançois Tigeot * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1724b50f1aSFrançois Tigeot * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1824b50f1aSFrançois Tigeot * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1924b50f1aSFrançois Tigeot * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2024b50f1aSFrançois Tigeot * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2124b50f1aSFrançois Tigeot * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2224b50f1aSFrançois Tigeot * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2324b50f1aSFrançois Tigeot * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2424b50f1aSFrançois Tigeot * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2524b50f1aSFrançois Tigeot */
2624b50f1aSFrançois Tigeot #ifndef _LINUX_COMPLETION_H_
2724b50f1aSFrançois Tigeot #define _LINUX_COMPLETION_H_
2824b50f1aSFrançois Tigeot
2924b50f1aSFrançois Tigeot #include <linux/wait.h>
3039cfddd2SFrançois Tigeot #include <linux/errno.h>
3124b50f1aSFrançois Tigeot
3209f141c4SFrançois Tigeot #include <sys/kernel.h>
3309f141c4SFrançois Tigeot
3424b50f1aSFrançois Tigeot struct completion {
3524b50f1aSFrançois Tigeot unsigned int done;
3624b50f1aSFrançois Tigeot wait_queue_head_t wait;
3724b50f1aSFrançois Tigeot };
3824b50f1aSFrançois Tigeot
3924b50f1aSFrançois Tigeot static inline void
init_completion(struct completion * c)4024b50f1aSFrançois Tigeot init_completion(struct completion *c)
4124b50f1aSFrançois Tigeot {
4224b50f1aSFrançois Tigeot c->done = 0;
4324b50f1aSFrançois Tigeot init_waitqueue_head(&c->wait);
4424b50f1aSFrançois Tigeot }
4524b50f1aSFrançois Tigeot
462097fbd4SPeeter Must static inline void
reinit_completion(struct completion * c)472097fbd4SPeeter Must reinit_completion(struct completion *c)
482097fbd4SPeeter Must {
492097fbd4SPeeter Must c->done = 0;
502097fbd4SPeeter Must }
512097fbd4SPeeter Must
5224b50f1aSFrançois Tigeot #define INIT_COMPLETION(c) (c.done = 0)
5324b50f1aSFrançois Tigeot
5444e1bd6eSMatthew Dillon /*
5544e1bd6eSMatthew Dillon * Completion interlock and wakeup. Be careful not to execute the wakeup
5644e1bd6eSMatthew Dillon * from inside the spinlock as this can deadlock if the IPIQ fifo is full.
5744e1bd6eSMatthew Dillon * (also note that wakeup() is asynchronous anyway, so no point doing that).
5844e1bd6eSMatthew Dillon */
5924b50f1aSFrançois Tigeot static inline void
complete(struct completion * c)6024b50f1aSFrançois Tigeot complete(struct completion *c)
6124b50f1aSFrançois Tigeot {
6288c5318eSFrançois Tigeot lockmgr(&c->wait.lock, LK_EXCLUSIVE);
63647fa573SFrançois Tigeot if (c->done != UINT_MAX)
6424b50f1aSFrançois Tigeot c->done++;
6588c5318eSFrançois Tigeot lockmgr(&c->wait.lock, LK_RELEASE);
6644e1bd6eSMatthew Dillon wakeup_one(&c->wait);
6724b50f1aSFrançois Tigeot }
6824b50f1aSFrançois Tigeot
6924b50f1aSFrançois Tigeot static inline void
complete_all(struct completion * c)7024b50f1aSFrançois Tigeot complete_all(struct completion *c)
7124b50f1aSFrançois Tigeot {
7288c5318eSFrançois Tigeot lockmgr(&c->wait.lock, LK_EXCLUSIVE);
73647fa573SFrançois Tigeot c->done = UINT_MAX;
7488c5318eSFrançois Tigeot lockmgr(&c->wait.lock, LK_RELEASE);
7544e1bd6eSMatthew Dillon wakeup(&c->wait);
7624b50f1aSFrançois Tigeot }
7724b50f1aSFrançois Tigeot
7824b50f1aSFrançois Tigeot static inline long
__wait_for_completion_generic(struct completion * c,unsigned long timeout,int flags)7939cfddd2SFrançois Tigeot __wait_for_completion_generic(struct completion *c,
8039cfddd2SFrançois Tigeot unsigned long timeout, int flags)
8124b50f1aSFrançois Tigeot {
8224b50f1aSFrançois Tigeot int start_jiffies, elapsed_jiffies, remaining_jiffies;
8324b50f1aSFrançois Tigeot bool timeout_expired = false, awakened = false;
8424b50f1aSFrançois Tigeot long ret = 1;
8524b50f1aSFrançois Tigeot
8624b50f1aSFrançois Tigeot start_jiffies = ticks;
8724b50f1aSFrançois Tigeot
8888c5318eSFrançois Tigeot lockmgr(&c->wait.lock, LK_EXCLUSIVE);
8988c5318eSFrançois Tigeot while (c->done == 0 && !timeout_expired) {
9039cfddd2SFrançois Tigeot ret = lksleep(&c->wait, &c->wait.lock, flags, "lwfcg", timeout);
9124b50f1aSFrançois Tigeot switch(ret) {
9224b50f1aSFrançois Tigeot case EWOULDBLOCK:
9324b50f1aSFrançois Tigeot timeout_expired = true;
9424b50f1aSFrançois Tigeot ret = 0;
9524b50f1aSFrançois Tigeot break;
9624b50f1aSFrançois Tigeot case ERESTART:
97797013cfSFrançois Tigeot ret = -ERESTARTSYS;
9824b50f1aSFrançois Tigeot break;
9924b50f1aSFrançois Tigeot case 0:
10024b50f1aSFrançois Tigeot awakened = true;
10124b50f1aSFrançois Tigeot break;
10224b50f1aSFrançois Tigeot }
10324b50f1aSFrançois Tigeot }
10488c5318eSFrançois Tigeot lockmgr(&c->wait.lock, LK_RELEASE);
10524b50f1aSFrançois Tigeot
10624b50f1aSFrançois Tigeot if (awakened) {
10724b50f1aSFrançois Tigeot elapsed_jiffies = ticks - start_jiffies;
10824b50f1aSFrançois Tigeot remaining_jiffies = timeout - elapsed_jiffies;
10924b50f1aSFrançois Tigeot if (remaining_jiffies > 0)
11024b50f1aSFrançois Tigeot ret = remaining_jiffies;
11124b50f1aSFrançois Tigeot }
11224b50f1aSFrançois Tigeot
11324b50f1aSFrançois Tigeot return ret;
11424b50f1aSFrançois Tigeot }
11524b50f1aSFrançois Tigeot
116*3f2dd94aSFrançois Tigeot int wait_for_completion_interruptible(struct completion *c);
117*3f2dd94aSFrançois Tigeot
11839cfddd2SFrançois Tigeot static inline long
wait_for_completion_interruptible_timeout(struct completion * c,unsigned long timeout)11939cfddd2SFrançois Tigeot wait_for_completion_interruptible_timeout(struct completion *c,
12039cfddd2SFrançois Tigeot unsigned long timeout)
12139cfddd2SFrançois Tigeot {
12239cfddd2SFrançois Tigeot return __wait_for_completion_generic(c, timeout, PCATCH);
12339cfddd2SFrançois Tigeot }
12439cfddd2SFrançois Tigeot
12539cfddd2SFrançois Tigeot static inline unsigned long
wait_for_completion_timeout(struct completion * c,unsigned long timeout)12639cfddd2SFrançois Tigeot wait_for_completion_timeout(struct completion *c, unsigned long timeout)
12739cfddd2SFrançois Tigeot {
12839cfddd2SFrançois Tigeot return __wait_for_completion_generic(c, timeout, 0);
12939cfddd2SFrançois Tigeot }
13039cfddd2SFrançois Tigeot
131f1e2e235SFrançois Tigeot void wait_for_completion(struct completion *c);
132f1e2e235SFrançois Tigeot
13339cfddd2SFrançois Tigeot /*
13439cfddd2SFrançois Tigeot * try_wait_for_completion: try to decrement a completion without blocking
13539cfddd2SFrançois Tigeot * its thread
13639cfddd2SFrançois Tigeot * return: false if the completion thread would need to be blocked/queued
13739cfddd2SFrançois Tigeot * true if a non-blocking decrement was successful
13839cfddd2SFrançois Tigeot */
13939cfddd2SFrançois Tigeot static inline bool
try_wait_for_completion(struct completion * c)14039cfddd2SFrançois Tigeot try_wait_for_completion(struct completion *c)
14139cfddd2SFrançois Tigeot {
14239cfddd2SFrançois Tigeot bool ret = false;
14339cfddd2SFrançois Tigeot
14439cfddd2SFrançois Tigeot /* we can't decrement c->done below 0 */
14539cfddd2SFrançois Tigeot if (READ_ONCE(c->done) == 0)
14639cfddd2SFrançois Tigeot return false;
14739cfddd2SFrançois Tigeot
14839cfddd2SFrançois Tigeot lockmgr(&c->wait.lock, LK_EXCLUSIVE);
14939cfddd2SFrançois Tigeot if (c->done > 0) {
15039cfddd2SFrançois Tigeot c->done--;
15139cfddd2SFrançois Tigeot ret = true;
15239cfddd2SFrançois Tigeot }
15339cfddd2SFrançois Tigeot lockmgr(&c->wait.lock, LK_RELEASE);
15439cfddd2SFrançois Tigeot
15539cfddd2SFrançois Tigeot return ret;
15639cfddd2SFrançois Tigeot }
15739cfddd2SFrançois Tigeot
15824b50f1aSFrançois Tigeot #endif /* _LINUX_COMPLETION_H_ */
159