1 /* $OpenBSD: completion.h,v 1.9 2020/06/22 14:19:35 jsg 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 26 struct completion { 27 u_int done; 28 struct mutex lock; 29 }; 30 31 static inline void 32 init_completion(struct completion *x) 33 { 34 x->done = 0; 35 mtx_init(&x->lock, IPL_TTY); 36 } 37 38 static inline void 39 reinit_completion(struct completion *x) 40 { 41 x->done = 0; 42 } 43 44 static inline u_long 45 wait_for_completion_timeout(struct completion *x, u_long timo) 46 { 47 int ret; 48 49 KASSERT(!cold); 50 51 mtx_enter(&x->lock); 52 while (x->done == 0) { 53 ret = msleep(x, &x->lock, 0, "wfct", timo); 54 if (ret) { 55 mtx_leave(&x->lock); 56 /* timeout */ 57 return 0; 58 } 59 } 60 if (x->done != UINT_MAX) 61 x->done--; 62 mtx_leave(&x->lock); 63 64 return 1; 65 } 66 67 static inline void 68 wait_for_completion(struct completion *x) 69 { 70 KASSERT(!cold); 71 72 mtx_enter(&x->lock); 73 while (x->done == 0) { 74 msleep_nsec(x, &x->lock, 0, "wfcom", INFSLP); 75 } 76 if (x->done != UINT_MAX) 77 x->done--; 78 mtx_leave(&x->lock); 79 } 80 81 static inline u_long 82 wait_for_completion_interruptible(struct completion *x) 83 { 84 int ret; 85 86 KASSERT(!cold); 87 88 mtx_enter(&x->lock); 89 while (x->done == 0) { 90 ret = msleep_nsec(x, &x->lock, PCATCH, "wfci", INFSLP); 91 if (ret) { 92 mtx_leave(&x->lock); 93 if (ret == EWOULDBLOCK) 94 return 0; 95 return -ERESTARTSYS; 96 } 97 } 98 if (x->done != UINT_MAX) 99 x->done--; 100 mtx_leave(&x->lock); 101 102 return 0; 103 } 104 105 static inline u_long 106 wait_for_completion_interruptible_timeout(struct completion *x, u_long timo) 107 { 108 int ret; 109 110 KASSERT(!cold); 111 112 mtx_enter(&x->lock); 113 while (x->done == 0) { 114 ret = msleep(x, &x->lock, PCATCH, "wfcit", timo); 115 if (ret) { 116 mtx_leave(&x->lock); 117 if (ret == EWOULDBLOCK) 118 return 0; 119 return -ERESTARTSYS; 120 } 121 } 122 if (x->done != UINT_MAX) 123 x->done--; 124 mtx_leave(&x->lock); 125 126 return 1; 127 } 128 129 static inline void 130 complete(struct completion *x) 131 { 132 mtx_enter(&x->lock); 133 if (x->done != UINT_MAX) 134 x->done++; 135 mtx_leave(&x->lock); 136 wakeup_one(x); 137 } 138 139 static inline void 140 complete_all(struct completion *x) 141 { 142 mtx_enter(&x->lock); 143 x->done = UINT_MAX; 144 mtx_leave(&x->lock); 145 wakeup(x); 146 } 147 148 static inline bool 149 try_wait_for_completion(struct completion *x) 150 { 151 mtx_enter(&x->lock); 152 if (x->done == 0) { 153 mtx_leave(&x->lock); 154 return false; 155 } 156 if (x->done != UINT_MAX) 157 x->done--; 158 mtx_leave(&x->lock); 159 return true; 160 } 161 162 #endif 163