1/* $OpenBSD: completion.h,v 1.10 2024/01/06 09:33:08 kettenis Exp $ */ 2/* 3 * Copyright (c) 2015, 2018 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#ifndef _LINUX_COMPLETION_H 19#define _LINUX_COMPLETION_H 20 21#include <sys/param.h> 22#include <sys/systm.h> 23#include <sys/mutex.h> 24#include <linux/wait.h> 25 26struct completion { 27 u_int done; 28 struct mutex lock; 29}; 30 31#define DECLARE_COMPLETION_ONSTACK(name) \ 32 struct completion name = { 0, MUTEX_INITIALIZER(IPL_TTY) } 33 34static inline void 35init_completion(struct completion *x) 36{ 37 x->done = 0; 38 mtx_init(&x->lock, IPL_TTY); 39} 40 41static inline void 42reinit_completion(struct completion *x) 43{ 44 x->done = 0; 45} 46 47static inline u_long 48wait_for_completion_timeout(struct completion *x, u_long timo) 49{ 50 int ret; 51 52 KASSERT(!cold); 53 54 mtx_enter(&x->lock); 55 while (x->done == 0) { 56 ret = msleep(x, &x->lock, 0, "wfct", timo); 57 if (ret) { 58 mtx_leave(&x->lock); 59 /* timeout */ 60 return 0; 61 } 62 } 63 if (x->done != UINT_MAX) 64 x->done--; 65 mtx_leave(&x->lock); 66 67 return 1; 68} 69 70static inline void 71wait_for_completion(struct completion *x) 72{ 73 KASSERT(!cold); 74 75 mtx_enter(&x->lock); 76 while (x->done == 0) { 77 msleep_nsec(x, &x->lock, 0, "wfcom", INFSLP); 78 } 79 if (x->done != UINT_MAX) 80 x->done--; 81 mtx_leave(&x->lock); 82} 83 84static inline u_long 85wait_for_completion_interruptible(struct completion *x) 86{ 87 int ret; 88 89 KASSERT(!cold); 90 91 mtx_enter(&x->lock); 92 while (x->done == 0) { 93 ret = msleep_nsec(x, &x->lock, PCATCH, "wfci", INFSLP); 94 if (ret) { 95 mtx_leave(&x->lock); 96 if (ret == EWOULDBLOCK) 97 return 0; 98 return -ERESTARTSYS; 99 } 100 } 101 if (x->done != UINT_MAX) 102 x->done--; 103 mtx_leave(&x->lock); 104 105 return 0; 106} 107 108static inline u_long 109wait_for_completion_interruptible_timeout(struct completion *x, u_long timo) 110{ 111 int ret; 112 113 KASSERT(!cold); 114 115 mtx_enter(&x->lock); 116 while (x->done == 0) { 117 ret = msleep(x, &x->lock, PCATCH, "wfcit", timo); 118 if (ret) { 119 mtx_leave(&x->lock); 120 if (ret == EWOULDBLOCK) 121 return 0; 122 return -ERESTARTSYS; 123 } 124 } 125 if (x->done != UINT_MAX) 126 x->done--; 127 mtx_leave(&x->lock); 128 129 return 1; 130} 131 132static inline void 133complete(struct completion *x) 134{ 135 mtx_enter(&x->lock); 136 if (x->done != UINT_MAX) 137 x->done++; 138 mtx_leave(&x->lock); 139 wakeup_one(x); 140} 141 142static inline void 143complete_all(struct completion *x) 144{ 145 mtx_enter(&x->lock); 146 x->done = UINT_MAX; 147 mtx_leave(&x->lock); 148 wakeup(x); 149} 150 151static inline bool 152try_wait_for_completion(struct completion *x) 153{ 154 mtx_enter(&x->lock); 155 if (x->done == 0) { 156 mtx_leave(&x->lock); 157 return false; 158 } 159 if (x->done != UINT_MAX) 160 x->done--; 161 mtx_leave(&x->lock); 162 return true; 163} 164 165#endif 166