Home | History | Annotate | Line # | Download | only in kern
kern_condvar.c revision 1.14.14.2
      1 /*	$NetBSD: kern_condvar.c,v 1.14.14.2 2008/06/02 13:24:07 mjf Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Andrew Doran.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Kernel condition variable implementation, modeled after those found in
     34  * Solaris, a description of which can be found in:
     35  *
     36  *	Solaris Internals: Core Kernel Architecture, Jim Mauro and
     37  *	    Richard McDougall.
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 __KERNEL_RCSID(0, "$NetBSD: kern_condvar.c,v 1.14.14.2 2008/06/02 13:24:07 mjf Exp $");
     42 
     43 #include <sys/param.h>
     44 #include <sys/proc.h>
     45 #include <sys/sched.h>
     46 #include <sys/systm.h>
     47 #include <sys/condvar.h>
     48 #include <sys/sleepq.h>
     49 #include <sys/lockdebug.h>
     50 
     51 #include <uvm/uvm_extern.h>
     52 
     53 #define	CV_SLEEPQ(cv)	((sleepq_t *)(cv)->cv_opaque)
     54 #define	CV_DEBUG_P(cv)	((cv)->cv_wmesg != nodebug)
     55 #define	CV_RA		((uintptr_t)__builtin_return_address(0))
     56 
     57 static u_int	cv_unsleep(lwp_t *, bool);
     58 static void	cv_wakeup_one(kcondvar_t *);
     59 static void	cv_wakeup_all(kcondvar_t *);
     60 
     61 static syncobj_t cv_syncobj = {
     62 	SOBJ_SLEEPQ_SORTED,
     63 	cv_unsleep,
     64 	sleepq_changepri,
     65 	sleepq_lendpri,
     66 	syncobj_noowner,
     67 };
     68 
     69 lockops_t cv_lockops = {
     70 	"Condition variable",
     71 	LOCKOPS_CV,
     72 	NULL
     73 };
     74 
     75 static const char deadcv[] = "deadcv";
     76 static const char nodebug[] = "nodebug";
     77 
     78 /*
     79  * cv_init:
     80  *
     81  *	Initialize a condition variable for use.
     82  */
     83 void
     84 cv_init(kcondvar_t *cv, const char *wmesg)
     85 {
     86 #ifdef LOCKDEBUG
     87 	bool dodebug;
     88 
     89 	dodebug = LOCKDEBUG_ALLOC(cv, &cv_lockops,
     90 	    (uintptr_t)__builtin_return_address(0));
     91 	if (!dodebug) {
     92 		/* XXX This will break vfs_lockf. */
     93 		wmesg = nodebug;
     94 	}
     95 #endif
     96 	KASSERT(wmesg != NULL);
     97 	cv->cv_wmesg = wmesg;
     98 	sleepq_init(CV_SLEEPQ(cv));
     99 }
    100 
    101 /*
    102  * cv_destroy:
    103  *
    104  *	Tear down a condition variable.
    105  */
    106 void
    107 cv_destroy(kcondvar_t *cv)
    108 {
    109 
    110 	LOCKDEBUG_FREE(CV_DEBUG_P(cv), cv);
    111 #ifdef DIAGNOSTIC
    112 	KASSERT(cv_is_valid(cv));
    113 	cv->cv_wmesg = deadcv;
    114 #endif
    115 }
    116 
    117 /*
    118  * cv_enter:
    119  *
    120  *	Look up and lock the sleep queue corresponding to the given
    121  *	condition variable, and increment the number of waiters.
    122  */
    123 static inline void
    124 cv_enter(kcondvar_t *cv, kmutex_t *mtx, lwp_t *l)
    125 {
    126 	sleepq_t *sq;
    127 	kmutex_t *mp;
    128 
    129 	KASSERT(cv_is_valid(cv));
    130 	KASSERT((l->l_pflag & LP_INTR) == 0 || panicstr != NULL);
    131 
    132 	LOCKDEBUG_LOCKED(CV_DEBUG_P(cv), cv, mtx, CV_RA, 0);
    133 
    134 	l->l_kpriority = true;
    135 	(void)sleeptab_lookup(&sleeptab, cv, &mp);
    136 	sq = CV_SLEEPQ(cv);
    137 	sleepq_enter(sq, l, mp);
    138 	sleepq_enqueue(sq, cv, cv->cv_wmesg, &cv_syncobj);
    139 	mutex_exit(mtx);
    140 }
    141 
    142 /*
    143  * cv_exit:
    144  *
    145  *	After resuming execution, check to see if we have been restarted
    146  *	as a result of cv_signal().  If we have, but cannot take the
    147  *	wakeup (because of eg a pending Unix signal or timeout) then try
    148  *	to ensure that another LWP sees it.  This is necessary because
    149  *	there may be multiple waiters, and at least one should take the
    150  *	wakeup if possible.
    151  */
    152 static inline int
    153 cv_exit(kcondvar_t *cv, kmutex_t *mtx, lwp_t *l, const int error)
    154 {
    155 
    156 	mutex_enter(mtx);
    157 	if (__predict_false(error != 0))
    158 		cv_signal(cv);
    159 
    160 	LOCKDEBUG_UNLOCKED(CV_DEBUG_P(cv), cv, CV_RA, 0);
    161 	KASSERT(cv_is_valid(cv));
    162 
    163 	return error;
    164 }
    165 
    166 /*
    167  * cv_unsleep:
    168  *
    169  *	Remove an LWP from the condition variable and sleep queue.  This
    170  *	is called when the LWP has not been awoken normally but instead
    171  *	interrupted: for example, when a signal is received.  Must be
    172  *	called with the LWP locked, and must return it unlocked.
    173  */
    174 static u_int
    175 cv_unsleep(lwp_t *l, bool cleanup)
    176 {
    177 	kcondvar_t *cv;
    178 
    179 	cv = (kcondvar_t *)(uintptr_t)l->l_wchan;
    180 
    181 	KASSERT(l->l_wchan == (wchan_t)cv);
    182 	KASSERT(l->l_sleepq == CV_SLEEPQ(cv));
    183 	KASSERT(cv_is_valid(cv));
    184 	KASSERT(!TAILQ_EMPTY(CV_SLEEPQ(cv)));
    185 
    186 	return sleepq_unsleep(l, cleanup);
    187 }
    188 
    189 /*
    190  * cv_wait:
    191  *
    192  *	Wait non-interruptably on a condition variable until awoken.
    193  */
    194 void
    195 cv_wait(kcondvar_t *cv, kmutex_t *mtx)
    196 {
    197 	lwp_t *l = curlwp;
    198 
    199 	KASSERT(mutex_owned(mtx));
    200 
    201 	cv_enter(cv, mtx, l);
    202 	(void)sleepq_block(0, false);
    203 	(void)cv_exit(cv, mtx, l, 0);
    204 }
    205 
    206 /*
    207  * cv_wait_sig:
    208  *
    209  *	Wait on a condition variable until a awoken or a signal is received.
    210  *	Will also return early if the process is exiting.  Returns zero if
    211  *	awoken normallly, ERESTART if a signal was received and the system
    212  *	call is restartable, or EINTR otherwise.
    213  */
    214 int
    215 cv_wait_sig(kcondvar_t *cv, kmutex_t *mtx)
    216 {
    217 	lwp_t *l = curlwp;
    218 	int error;
    219 
    220 	KASSERT(mutex_owned(mtx));
    221 
    222 	cv_enter(cv, mtx, l);
    223 	error = sleepq_block(0, true);
    224 	return cv_exit(cv, mtx, l, error);
    225 }
    226 
    227 /*
    228  * cv_timedwait:
    229  *
    230  *	Wait on a condition variable until awoken or the specified timeout
    231  *	expires.  Returns zero if awoken normally or EWOULDBLOCK if the
    232  *	timeout expired.
    233  */
    234 int
    235 cv_timedwait(kcondvar_t *cv, kmutex_t *mtx, int timo)
    236 {
    237 	lwp_t *l = curlwp;
    238 	int error;
    239 
    240 	KASSERT(mutex_owned(mtx));
    241 
    242 	cv_enter(cv, mtx, l);
    243 	error = sleepq_block(timo, false);
    244 	return cv_exit(cv, mtx, l, error);
    245 }
    246 
    247 /*
    248  * cv_timedwait_sig:
    249  *
    250  *	Wait on a condition variable until a timeout expires, awoken or a
    251  *	signal is received.  Will also return early if the process is
    252  *	exiting.  Returns zero if awoken normallly, EWOULDBLOCK if the
    253  *	timeout expires, ERESTART if a signal was received and the system
    254  *	call is restartable, or EINTR otherwise.
    255  */
    256 int
    257 cv_timedwait_sig(kcondvar_t *cv, kmutex_t *mtx, int timo)
    258 {
    259 	lwp_t *l = curlwp;
    260 	int error;
    261 
    262 	KASSERT(mutex_owned(mtx));
    263 
    264 	cv_enter(cv, mtx, l);
    265 	error = sleepq_block(timo, true);
    266 	return cv_exit(cv, mtx, l, error);
    267 }
    268 
    269 /*
    270  * cv_signal:
    271  *
    272  *	Wake the highest priority LWP waiting on a condition variable.
    273  *	Must be called with the interlocking mutex held.
    274  */
    275 void
    276 cv_signal(kcondvar_t *cv)
    277 {
    278 
    279 	LOCKDEBUG_WAKEUP(CV_DEBUG_P(cv), cv, CV_RA);
    280 	KASSERT(cv_is_valid(cv));
    281 
    282 	if (__predict_false(TAILQ_FIRST(CV_SLEEPQ(cv)) != NULL))
    283 		cv_wakeup_one(cv);
    284 }
    285 
    286 static void __noinline
    287 cv_wakeup_one(kcondvar_t *cv)
    288 {
    289 	sleepq_t *sq;
    290 	kmutex_t *mp;
    291 	int swapin;
    292 	lwp_t *l;
    293 
    294 	KASSERT(cv_is_valid(cv));
    295 
    296 	sq = CV_SLEEPQ(cv);
    297 	(void)sleeptab_lookup(&sleeptab, cv, &mp);
    298 	l = TAILQ_FIRST(sq);
    299 	if (l == NULL) {
    300 		mutex_spin_exit(mp);
    301 		return;
    302 	}
    303 	KASSERT(l->l_sleepq == sq);
    304 	KASSERT(l->l_mutex == mp);
    305 	KASSERT(l->l_wchan == cv);
    306 	swapin = sleepq_remove(sq, l);
    307 	mutex_spin_exit(mp);
    308 
    309 	/*
    310 	 * If there are newly awakend threads that need to be swapped in,
    311 	 * then kick the swapper into action.
    312 	 */
    313 	if (swapin)
    314 		uvm_kick_scheduler();
    315 
    316 	KASSERT(cv_is_valid(cv));
    317 }
    318 
    319 /*
    320  * cv_broadcast:
    321  *
    322  *	Wake all LWPs waiting on a condition variable.  Must be called
    323  *	with the interlocking mutex held.
    324  */
    325 void
    326 cv_broadcast(kcondvar_t *cv)
    327 {
    328 
    329 	LOCKDEBUG_WAKEUP(CV_DEBUG_P(cv), cv, CV_RA);
    330 	KASSERT(cv_is_valid(cv));
    331 
    332 	if (__predict_false(TAILQ_FIRST(CV_SLEEPQ(cv)) != NULL))
    333 		cv_wakeup_all(cv);
    334 }
    335 
    336 static void __noinline
    337 cv_wakeup_all(kcondvar_t *cv)
    338 {
    339 	sleepq_t *sq;
    340 	kmutex_t *mp;
    341 	int swapin;
    342 	lwp_t *l, *next;
    343 
    344 	KASSERT(cv_is_valid(cv));
    345 
    346 	sq = CV_SLEEPQ(cv);
    347 	(void)sleeptab_lookup(&sleeptab, cv, &mp);
    348 	swapin = 0;
    349 	for (l = TAILQ_FIRST(sq); l != NULL; l = next) {
    350 		KASSERT(l->l_sleepq == sq);
    351 		KASSERT(l->l_mutex == mp);
    352 		KASSERT(l->l_wchan == cv);
    353 		next = TAILQ_NEXT(l, l_sleepchain);
    354 		swapin |= sleepq_remove(sq, l);
    355 	}
    356 	mutex_spin_exit(mp);
    357 
    358 	/*
    359 	 * If there are newly awakend threads that need to be swapped in,
    360 	 * then kick the swapper into action.
    361 	 */
    362 	if (swapin)
    363 		uvm_kick_scheduler();
    364 
    365 	KASSERT(cv_is_valid(cv));
    366 }
    367 
    368 /*
    369  * cv_wakeup:
    370  *
    371  *	Wake all LWPs waiting on a condition variable.  For cases
    372  *	where the address may be waited on by mtsleep()/tsleep().
    373  *	Not a documented call.
    374  */
    375 void
    376 cv_wakeup(kcondvar_t *cv)
    377 {
    378 
    379 	cv_wakeup_all(cv);
    380 	wakeup(cv);
    381 }
    382 
    383 /*
    384  * cv_has_waiters:
    385  *
    386  *	For diagnostic assertions: return non-zero if a condition
    387  *	variable has waiters.
    388  */
    389 bool
    390 cv_has_waiters(kcondvar_t *cv)
    391 {
    392 
    393 	/* No need to interlock here */
    394 	return !TAILQ_EMPTY(CV_SLEEPQ(cv));
    395 }
    396 
    397 /*
    398  * cv_is_valid:
    399  *
    400  *	For diagnostic assertions: return non-zero if a condition
    401  *	variable appears to be valid.  No locks need be held.
    402  */
    403 bool
    404 cv_is_valid(kcondvar_t *cv)
    405 {
    406 
    407 	return cv->cv_wmesg != deadcv && cv->cv_wmesg != NULL;
    408 }
    409