kern_condvar.c revision 126885
1/*- 2 * Copyright (c) 2000 Jake Burkholder <jake@freebsd.org>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/kern/kern_condvar.c 126885 2004-03-12 19:06:18Z jhb $"); 29 30#include "opt_ktrace.h" 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/lock.h> 35#include <sys/mutex.h> 36#include <sys/proc.h> 37#include <sys/kernel.h> 38#include <sys/ktr.h> 39#include <sys/condvar.h> 40#include <sys/sched.h> 41#include <sys/signalvar.h> 42#include <sys/sleepqueue.h> 43#include <sys/resourcevar.h> 44#ifdef KTRACE 45#include <sys/uio.h> 46#include <sys/ktrace.h> 47#endif 48 49/* 50 * Common sanity checks for cv_wait* functions. 51 */ 52#define CV_ASSERT(cvp, mp, td) do { \ 53 KASSERT((td) != NULL, ("%s: curthread NULL", __func__)); \ 54 KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__)); \ 55 KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__)); \ 56 KASSERT((mp) != NULL, ("%s: mp NULL", __func__)); \ 57 mtx_assert((mp), MA_OWNED | MA_NOTRECURSED); \ 58} while (0) 59 60/* 61 * Initialize a condition variable. Must be called before use. 62 */ 63void 64cv_init(struct cv *cvp, const char *desc) 65{ 66 67 cvp->cv_description = desc; 68} 69 70/* 71 * Destroy a condition variable. The condition variable must be re-initialized 72 * in order to be re-used. 73 */ 74void 75cv_destroy(struct cv *cvp) 76{ 77#ifdef INVARIANTS 78 struct sleepqueue *sq; 79 80 sq = sleepq_lookup(cvp); 81 sleepq_release(cvp); 82 KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__)); 83#endif 84} 85 86/* 87 * Wait on a condition variable. The current thread is placed on the condition 88 * variable's wait queue and suspended. A cv_signal or cv_broadcast on the same 89 * condition variable will resume the thread. The mutex is released before 90 * sleeping and will be held on return. It is recommended that the mutex be 91 * held when cv_signal or cv_broadcast are called. 92 */ 93void 94cv_wait(struct cv *cvp, struct mtx *mp) 95{ 96 struct sleepqueue *sq; 97 struct thread *td; 98 WITNESS_SAVE_DECL(mp); 99 100 td = curthread; 101#ifdef KTRACE 102 if (KTRPOINT(td, KTR_CSW)) 103 ktrcsw(1, 0); 104#endif 105 CV_ASSERT(cvp, mp, td); 106 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 107 "Waiting on \"%s\"", cvp->cv_description); 108 WITNESS_SAVE(&mp->mtx_object, mp); 109 110 if (cold || panicstr) { 111 /* 112 * During autoconfiguration, just give interrupts 113 * a chance, then just return. Don't run any other 114 * thread or panic below, in case this is the idle 115 * process and already asleep. 116 */ 117 return; 118 } 119 120 sq = sleepq_lookup(cvp); 121 122 DROP_GIANT(); 123 mtx_unlock(mp); 124 125 sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 126 sleepq_wait(cvp); 127 128#ifdef KTRACE 129 if (KTRPOINT(td, KTR_CSW)) 130 ktrcsw(0, 0); 131#endif 132 PICKUP_GIANT(); 133 mtx_lock(mp); 134 WITNESS_RESTORE(&mp->mtx_object, mp); 135} 136 137/* 138 * Wait on a condition variable, allowing interruption by signals. Return 0 if 139 * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 140 * a signal was caught. If ERESTART is returned the system call should be 141 * restarted if possible. 142 */ 143int 144cv_wait_sig(struct cv *cvp, struct mtx *mp) 145{ 146 struct sleepqueue *sq; 147 struct thread *td; 148 struct proc *p; 149 int rval, sig; 150 WITNESS_SAVE_DECL(mp); 151 152 td = curthread; 153 p = td->td_proc; 154 rval = 0; 155#ifdef KTRACE 156 if (KTRPOINT(td, KTR_CSW)) 157 ktrcsw(1, 0); 158#endif 159 CV_ASSERT(cvp, mp, td); 160 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 161 "Waiting on \"%s\"", cvp->cv_description); 162 WITNESS_SAVE(&mp->mtx_object, mp); 163 164 if (cold || panicstr) { 165 /* 166 * After a panic, or during autoconfiguration, just give 167 * interrupts a chance, then just return; don't run any other 168 * procs or panic below, in case this is the idle process and 169 * already asleep. 170 */ 171 return 0; 172 } 173 174 sq = sleepq_lookup(cvp); 175 176 /* XXX: Missing the threading checks from msleep! */ 177 178 DROP_GIANT(); 179 mtx_unlock(mp); 180 181 sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 182 sig = sleepq_catch_signals(cvp); 183 /* 184 * XXX: Missing magic return value handling for no signal 185 * caught but thread woken up during check. 186 */ 187 rval = sleepq_wait_sig(cvp); 188 if (rval == 0) 189 rval = sleepq_calc_signal_retval(sig); 190 191 /* XXX: Part of missing threading checks? */ 192 PROC_LOCK(p); 193 if (p->p_flag & P_WEXIT) 194 rval = EINTR; 195 PROC_UNLOCK(p); 196 197#ifdef KTRACE 198 if (KTRPOINT(td, KTR_CSW)) 199 ktrcsw(0, 0); 200#endif 201 PICKUP_GIANT(); 202 mtx_lock(mp); 203 WITNESS_RESTORE(&mp->mtx_object, mp); 204 205 return (rval); 206} 207 208/* 209 * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 210 * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 211 * expires. 212 */ 213int 214cv_timedwait(struct cv *cvp, struct mtx *mp, int timo) 215{ 216 struct sleepqueue *sq; 217 struct thread *td; 218 int rval; 219 WITNESS_SAVE_DECL(mp); 220 221 td = curthread; 222 rval = 0; 223#ifdef KTRACE 224 if (KTRPOINT(td, KTR_CSW)) 225 ktrcsw(1, 0); 226#endif 227 CV_ASSERT(cvp, mp, td); 228 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 229 "Waiting on \"%s\"", cvp->cv_description); 230 WITNESS_SAVE(&mp->mtx_object, mp); 231 232 if (cold || panicstr) { 233 /* 234 * After a panic, or during autoconfiguration, just give 235 * interrupts a chance, then just return; don't run any other 236 * thread or panic below, in case this is the idle process and 237 * already asleep. 238 */ 239 return 0; 240 } 241 242 sq = sleepq_lookup(cvp); 243 244 DROP_GIANT(); 245 mtx_unlock(mp); 246 247 sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 248 sleepq_set_timeout(cvp, timo); 249 rval = sleepq_timedwait(cvp, 0); 250 251#ifdef KTRACE 252 if (KTRPOINT(td, KTR_CSW)) 253 ktrcsw(0, 0); 254#endif 255 PICKUP_GIANT(); 256 mtx_lock(mp); 257 WITNESS_RESTORE(&mp->mtx_object, mp); 258 259 return (rval); 260} 261 262/* 263 * Wait on a condition variable for at most timo/hz seconds, allowing 264 * interruption by signals. Returns 0 if the thread was resumed by cv_signal 265 * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 266 * a signal was caught. 267 */ 268int 269cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) 270{ 271 struct sleepqueue *sq; 272 struct thread *td; 273 struct proc *p; 274 int rval; 275 int sig; 276 WITNESS_SAVE_DECL(mp); 277 278 td = curthread; 279 p = td->td_proc; 280 rval = 0; 281#ifdef KTRACE 282 if (KTRPOINT(td, KTR_CSW)) 283 ktrcsw(1, 0); 284#endif 285 CV_ASSERT(cvp, mp, td); 286 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 287 "Waiting on \"%s\"", cvp->cv_description); 288 WITNESS_SAVE(&mp->mtx_object, mp); 289 290 if (cold || panicstr) { 291 /* 292 * After a panic, or during autoconfiguration, just give 293 * interrupts a chance, then just return; don't run any other 294 * thread or panic below, in case this is the idle process and 295 * already asleep. 296 */ 297 return 0; 298 } 299 300 sq = sleepq_lookup(cvp); 301 302 DROP_GIANT(); 303 mtx_unlock(mp); 304 305 sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 306 sleepq_set_timeout(cvp, timo); 307 sig = sleepq_catch_signals(cvp); 308 /* 309 * XXX: Missing magic return value handling for no signal 310 * caught but thread woken up during check. 311 */ 312 rval = sleepq_timedwait_sig(cvp, sig != 0); 313 if (rval == 0) 314 rval = sleepq_calc_signal_retval(sig); 315 316 /* XXX: Part of missing threading checks? */ 317 PROC_LOCK(p); 318 if (p->p_flag & P_WEXIT) 319 rval = EINTR; 320 PROC_UNLOCK(p); 321 322#ifdef KTRACE 323 if (KTRPOINT(td, KTR_CSW)) 324 ktrcsw(0, 0); 325#endif 326 PICKUP_GIANT(); 327 mtx_lock(mp); 328 WITNESS_RESTORE(&mp->mtx_object, mp); 329 330 return (rval); 331} 332 333/* 334 * Signal a condition variable, wakes up one waiting thread. Will also wakeup 335 * the swapper if the process is not in memory, so that it can bring the 336 * sleeping process in. Note that this may also result in additional threads 337 * being made runnable. Should be called with the same mutex as was passed to 338 * cv_wait held. 339 */ 340void 341cv_signal(struct cv *cvp) 342{ 343 344 sleepq_signal(cvp, SLEEPQ_CONDVAR, -1); 345} 346 347/* 348 * Broadcast a signal to a condition variable. Wakes up all waiting threads. 349 * Should be called with the same mutex as was passed to cv_wait held. 350 */ 351void 352cv_broadcastpri(struct cv *cvp, int pri) 353{ 354 355 sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri); 356} 357