xref: /openbsd/lib/libc/thread/rthread_sync.c (revision d556a964)
1 /*	$OpenBSD: rthread_sync.c,v 1.6 2024/01/10 04:28:43 cheloha Exp $ */
2 /*
3  * Copyright (c) 2004,2005 Ted Unangst <tedu@openbsd.org>
4  * Copyright (c) 2012 Philip Guenther <guenther@openbsd.org>
5  * All Rights Reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 /*
20  * Mutexes and conditions - synchronization functions.
21  */
22 
23 #include <assert.h>
24 #include <errno.h>
25 #include <pthread.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include "rthread.h"
31 #include "cancel.h"		/* in libc/include */
32 
33 static _atomic_lock_t static_init_lock = _SPINLOCK_UNLOCKED;
34 
35 /*
36  * mutexen
37  */
38 int
pthread_mutex_init(pthread_mutex_t * mutexp,const pthread_mutexattr_t * attr)39 pthread_mutex_init(pthread_mutex_t *mutexp, const pthread_mutexattr_t *attr)
40 {
41 	struct pthread_mutex *mutex;
42 
43 	mutex = calloc(1, sizeof(*mutex));
44 	if (!mutex)
45 		return (errno);
46 	mutex->lock = _SPINLOCK_UNLOCKED;
47 	TAILQ_INIT(&mutex->lockers);
48 	if (attr == NULL) {
49 		mutex->type = PTHREAD_MUTEX_DEFAULT;
50 		mutex->prioceiling = -1;
51 	} else {
52 		mutex->type = (*attr)->ma_type;
53 		mutex->prioceiling = (*attr)->ma_protocol ==
54 		    PTHREAD_PRIO_PROTECT ? (*attr)->ma_prioceiling : -1;
55 	}
56 	*mutexp = mutex;
57 
58 	return (0);
59 }
60 DEF_STRONG(pthread_mutex_init);
61 
62 int
pthread_mutex_destroy(pthread_mutex_t * mutexp)63 pthread_mutex_destroy(pthread_mutex_t *mutexp)
64 {
65 	struct pthread_mutex *mutex;
66 
67 	assert(mutexp);
68 	mutex = (struct pthread_mutex *)*mutexp;
69 	if (mutex) {
70 		if (mutex->count || mutex->owner != NULL ||
71 		    !TAILQ_EMPTY(&mutex->lockers)) {
72 #define MSG "pthread_mutex_destroy on mutex with waiters!\n"
73 			write(2, MSG, sizeof(MSG) - 1);
74 #undef MSG
75 			return (EBUSY);
76 		}
77 		free(mutex);
78 		*mutexp = NULL;
79 	}
80 	return (0);
81 }
82 DEF_STRONG(pthread_mutex_destroy);
83 
84 static int
_rthread_mutex_lock(pthread_mutex_t * mutexp,int trywait,const struct timespec * abstime)85 _rthread_mutex_lock(pthread_mutex_t *mutexp, int trywait,
86     const struct timespec *abstime)
87 {
88 	struct pthread_mutex *mutex;
89 	pthread_t self = pthread_self();
90 	int ret = 0;
91 
92 	/*
93 	 * If the mutex is statically initialized, perform the dynamic
94 	 * initialization. Note: _thread_mutex_lock() in libc requires
95 	 * _rthread_mutex_lock() to perform the mutex init when *mutexp
96 	 * is NULL.
97 	 */
98 	if (*mutexp == NULL) {
99 		_spinlock(&static_init_lock);
100 		if (*mutexp == NULL)
101 			ret = pthread_mutex_init(mutexp, NULL);
102 		_spinunlock(&static_init_lock);
103 		if (ret != 0)
104 			return (EINVAL);
105 	}
106 	mutex = (struct pthread_mutex *)*mutexp;
107 
108 	_rthread_debug(5, "%p: mutex_lock %p\n", (void *)self, (void *)mutex);
109 	_spinlock(&mutex->lock);
110 	if (mutex->owner == NULL && TAILQ_EMPTY(&mutex->lockers)) {
111 		assert(mutex->count == 0);
112 		mutex->owner = self;
113 	} else if (mutex->owner == self) {
114 		assert(mutex->count > 0);
115 
116 		/* already owner?  handle recursive behavior */
117 		if (mutex->type != PTHREAD_MUTEX_RECURSIVE)
118 		{
119 			if (trywait ||
120 			    mutex->type == PTHREAD_MUTEX_ERRORCHECK) {
121 				_spinunlock(&mutex->lock);
122 				return (trywait ? EBUSY : EDEADLK);
123 			}
124 
125 			/* self-deadlock is disallowed by strict */
126 			if (mutex->type == PTHREAD_MUTEX_STRICT_NP &&
127 			    abstime == NULL)
128 				abort();
129 
130 			/* self-deadlock, possibly until timeout */
131 			while (__thrsleep(self, CLOCK_REALTIME, abstime,
132 			    &mutex->lock, NULL) != EWOULDBLOCK)
133 				_spinlock(&mutex->lock);
134 			return (ETIMEDOUT);
135 		}
136 		if (mutex->count == INT_MAX) {
137 			_spinunlock(&mutex->lock);
138 			return (EAGAIN);
139 		}
140 	} else if (trywait) {
141 		/* try failed */
142 		_spinunlock(&mutex->lock);
143 		return (EBUSY);
144 	} else {
145 		/* add to the wait queue and block until at the head */
146 		TAILQ_INSERT_TAIL(&mutex->lockers, self, waiting);
147 		while (mutex->owner != self) {
148 			ret = __thrsleep(self, CLOCK_REALTIME, abstime,
149 			    &mutex->lock, NULL);
150 			_spinlock(&mutex->lock);
151 			assert(mutex->owner != NULL);
152 			if (ret == EWOULDBLOCK) {
153 				if (mutex->owner == self)
154 					break;
155 				TAILQ_REMOVE(&mutex->lockers, self, waiting);
156 				_spinunlock(&mutex->lock);
157 				return (ETIMEDOUT);
158 			}
159 		}
160 	}
161 
162 	mutex->count++;
163 	_spinunlock(&mutex->lock);
164 
165 	return (0);
166 }
167 
168 int
pthread_mutex_lock(pthread_mutex_t * p)169 pthread_mutex_lock(pthread_mutex_t *p)
170 {
171 	return (_rthread_mutex_lock(p, 0, NULL));
172 }
173 DEF_STRONG(pthread_mutex_lock);
174 
175 int
pthread_mutex_trylock(pthread_mutex_t * p)176 pthread_mutex_trylock(pthread_mutex_t *p)
177 {
178 	return (_rthread_mutex_lock(p, 1, NULL));
179 }
180 
181 int
pthread_mutex_timedlock(pthread_mutex_t * p,const struct timespec * abstime)182 pthread_mutex_timedlock(pthread_mutex_t *p, const struct timespec *abstime)
183 {
184 	return (_rthread_mutex_lock(p, 0, abstime));
185 }
186 
187 int
pthread_mutex_unlock(pthread_mutex_t * mutexp)188 pthread_mutex_unlock(pthread_mutex_t *mutexp)
189 {
190 	pthread_t self = pthread_self();
191 	struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp;
192 
193 	_rthread_debug(5, "%p: mutex_unlock %p\n", (void *)self,
194 	    (void *)mutex);
195 
196 	if (mutex == NULL)
197 #if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_ERRORCHECK
198 		return (EPERM);
199 #elif PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL
200 		return(0);
201 #else
202 		abort();
203 #endif
204 
205 	if (mutex->owner != self) {
206 		if (mutex->type == PTHREAD_MUTEX_ERRORCHECK ||
207 		    mutex->type == PTHREAD_MUTEX_RECURSIVE)
208 			return (EPERM);
209 		else {
210 			/*
211 			 * For mutex type NORMAL our undefined behavior for
212 			 * unlocking an unlocked mutex is to succeed without
213 			 * error.  All other undefined behaviors are to
214 			 * abort() immediately.
215 			 */
216 			if (mutex->owner == NULL &&
217 			    mutex->type == PTHREAD_MUTEX_NORMAL)
218 				return (0);
219 			else
220 				abort();
221 		}
222 	}
223 
224 	if (--mutex->count == 0) {
225 		pthread_t next;
226 
227 		_spinlock(&mutex->lock);
228 		mutex->owner = next = TAILQ_FIRST(&mutex->lockers);
229 		if (next != NULL)
230 			TAILQ_REMOVE(&mutex->lockers, next, waiting);
231 		_spinunlock(&mutex->lock);
232 		if (next != NULL)
233 			__thrwakeup(next, 1);
234 	}
235 
236 	return (0);
237 }
238 DEF_STRONG(pthread_mutex_unlock);
239 
240 /*
241  * condition variables
242  */
243 int
pthread_cond_init(pthread_cond_t * condp,const pthread_condattr_t * attr)244 pthread_cond_init(pthread_cond_t *condp, const pthread_condattr_t *attr)
245 {
246 	pthread_cond_t cond;
247 
248 	cond = calloc(1, sizeof(*cond));
249 	if (!cond)
250 		return (errno);
251 	cond->lock = _SPINLOCK_UNLOCKED;
252 	TAILQ_INIT(&cond->waiters);
253 	if (attr == NULL)
254 		cond->clock = CLOCK_REALTIME;
255 	else
256 		cond->clock = (*attr)->ca_clock;
257 	*condp = cond;
258 
259 	return (0);
260 }
261 DEF_STRONG(pthread_cond_init);
262 
263 int
pthread_cond_destroy(pthread_cond_t * condp)264 pthread_cond_destroy(pthread_cond_t *condp)
265 {
266 	pthread_cond_t cond;
267 
268 	assert(condp);
269 	cond = *condp;
270 	if (cond) {
271 		if (!TAILQ_EMPTY(&cond->waiters)) {
272 #define MSG "pthread_cond_destroy on condvar with waiters!\n"
273 			write(2, MSG, sizeof(MSG) - 1);
274 #undef MSG
275 			return (EBUSY);
276 		}
277 		free(cond);
278 	}
279 	*condp = NULL;
280 
281 	return (0);
282 }
283 
284 int
pthread_cond_timedwait(pthread_cond_t * condp,pthread_mutex_t * mutexp,const struct timespec * abstime)285 pthread_cond_timedwait(pthread_cond_t *condp, pthread_mutex_t *mutexp,
286     const struct timespec *abstime)
287 {
288 	pthread_cond_t cond;
289 	struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp;
290 	struct tib *tib = TIB_GET();
291 	pthread_t self = tib->tib_thread;
292 	pthread_t next;
293 	int mutex_count;
294 	int canceled = 0;
295 	int rv = 0;
296 	int error;
297 	PREP_CANCEL_POINT(tib);
298 
299 	if (!*condp)
300 		if ((error = pthread_cond_init(condp, NULL)))
301 			return (error);
302 	cond = *condp;
303 	_rthread_debug(5, "%p: cond_timed %p,%p\n", (void *)self,
304 	    (void *)cond, (void *)mutex);
305 
306 	if (mutex == NULL)
307 #if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_ERRORCHECK
308 		return (EPERM);
309 #else
310 		abort();
311 #endif
312 
313 	if (mutex->owner != self) {
314 		if (mutex->type == PTHREAD_MUTEX_ERRORCHECK)
315 			return (EPERM);
316 		else
317 			abort();
318 	}
319 
320 	if (abstime == NULL || abstime->tv_nsec < 0 ||
321 	    abstime->tv_nsec >= 1000000000)
322 		return (EINVAL);
323 
324 	ENTER_DELAYED_CANCEL_POINT(tib, self);
325 
326 	_spinlock(&cond->lock);
327 
328 	/* mark the condvar as being associated with this mutex */
329 	if (cond->mutex == NULL) {
330 		cond->mutex = mutex;
331 		assert(TAILQ_EMPTY(&cond->waiters));
332 	} else if (cond->mutex != mutex) {
333 		assert(cond->mutex == mutex);
334 		_spinunlock(&cond->lock);
335 		LEAVE_CANCEL_POINT_INNER(tib, 1);
336 		return (EINVAL);
337 	} else
338 		assert(! TAILQ_EMPTY(&cond->waiters));
339 
340 	/* snag the count in case this is a recursive mutex */
341 	mutex_count = mutex->count;
342 
343 	/* transfer from the mutex queue to the condvar queue */
344 	_spinlock(&mutex->lock);
345 	self->blocking_cond = cond;
346 	TAILQ_INSERT_TAIL(&cond->waiters, self, waiting);
347 	_spinunlock(&cond->lock);
348 
349 	/* wake the next guy blocked on the mutex */
350 	mutex->count = 0;
351 	mutex->owner = next = TAILQ_FIRST(&mutex->lockers);
352 	if (next != NULL) {
353 		TAILQ_REMOVE(&mutex->lockers, next, waiting);
354 		__thrwakeup(next, 1);
355 	}
356 
357 	/* wait until we're the owner of the mutex again */
358 	while (mutex->owner != self) {
359 		error = __thrsleep(self, cond->clock, abstime,
360 		    &mutex->lock, &self->delayed_cancel);
361 
362 		/*
363 		 * If abstime == NULL, then we're definitely waiting
364 		 * on the mutex instead of the condvar, and are
365 		 * just waiting for mutex ownership, regardless of
366 		 * why we woke up.
367 		 */
368 		if (abstime == NULL) {
369 			_spinlock(&mutex->lock);
370 			continue;
371 		}
372 
373 		/*
374 		 * If we took a normal signal (not from
375 		 * cancellation) then we should just go back to
376 		 * sleep without changing state (timeouts, etc).
377 		 */
378 		if ((error == EINTR || error == ECANCELED) &&
379 		    (tib->tib_canceled == 0 ||
380 		    (tib->tib_cantcancel & CANCEL_DISABLED))) {
381 			_spinlock(&mutex->lock);
382 			continue;
383 		}
384 
385 		/*
386 		 * The remaining reasons for waking up (normal
387 		 * wakeup, timeout, and cancellation) all mean that
388 		 * we won't be staying in the condvar queue and
389 		 * we'll no longer time out or be cancelable.
390 		 */
391 		abstime = NULL;
392 		LEAVE_CANCEL_POINT_INNER(tib, 0);
393 
394 		/*
395 		 * If we're no longer in the condvar's queue then
396 		 * we're just waiting for mutex ownership.  Need
397 		 * cond->lock here to prevent race with cond_signal().
398 		 */
399 		_spinlock(&cond->lock);
400 		if (self->blocking_cond == NULL) {
401 			_spinunlock(&cond->lock);
402 			_spinlock(&mutex->lock);
403 			continue;
404 		}
405 		assert(self->blocking_cond == cond);
406 
407 		/* if timeout or canceled, make note of that */
408 		if (error == EWOULDBLOCK)
409 			rv = ETIMEDOUT;
410 		else if (error == EINTR)
411 			canceled = 1;
412 
413 		/* transfer between the queues */
414 		TAILQ_REMOVE(&cond->waiters, self, waiting);
415 		assert(mutex == cond->mutex);
416 		if (TAILQ_EMPTY(&cond->waiters))
417 			cond->mutex = NULL;
418 		self->blocking_cond = NULL;
419 		_spinunlock(&cond->lock);
420 		_spinlock(&mutex->lock);
421 
422 		/* mutex unlocked right now? */
423 		if (mutex->owner == NULL &&
424 		    TAILQ_EMPTY(&mutex->lockers)) {
425 			assert(mutex->count == 0);
426 			mutex->owner = self;
427 			break;
428 		}
429 		TAILQ_INSERT_TAIL(&mutex->lockers, self, waiting);
430 	}
431 
432 	/* restore the mutex's count */
433 	mutex->count = mutex_count;
434 	_spinunlock(&mutex->lock);
435 
436 	LEAVE_CANCEL_POINT_INNER(tib, canceled);
437 
438 	return (rv);
439 }
440 
441 int
pthread_cond_wait(pthread_cond_t * condp,pthread_mutex_t * mutexp)442 pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp)
443 {
444 	pthread_cond_t cond;
445 	struct pthread_mutex *mutex = (struct pthread_mutex *)*mutexp;
446 	struct tib *tib = TIB_GET();
447 	pthread_t self = tib->tib_thread;
448 	pthread_t next;
449 	int mutex_count;
450 	int canceled = 0;
451 	int error;
452 	PREP_CANCEL_POINT(tib);
453 
454 	if (!*condp)
455 		if ((error = pthread_cond_init(condp, NULL)))
456 			return (error);
457 	cond = *condp;
458 	_rthread_debug(5, "%p: cond_wait %p,%p\n", (void *)self,
459 	    (void *)cond, (void *)mutex);
460 
461 	if (mutex == NULL)
462 #if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_ERRORCHECK
463 		return (EPERM);
464 #else
465 		abort();
466 #endif
467 
468 	if (mutex->owner != self) {
469 		if (mutex->type == PTHREAD_MUTEX_ERRORCHECK)
470 			return (EPERM);
471 		else
472 			abort();
473 	}
474 
475 	ENTER_DELAYED_CANCEL_POINT(tib, self);
476 
477 	_spinlock(&cond->lock);
478 
479 	/* mark the condvar as being associated with this mutex */
480 	if (cond->mutex == NULL) {
481 		cond->mutex = mutex;
482 		assert(TAILQ_EMPTY(&cond->waiters));
483 	} else if (cond->mutex != mutex) {
484 		assert(cond->mutex == mutex);
485 		_spinunlock(&cond->lock);
486 		LEAVE_CANCEL_POINT_INNER(tib, 1);
487 		return (EINVAL);
488 	} else
489 		assert(! TAILQ_EMPTY(&cond->waiters));
490 
491 	/* snag the count in case this is a recursive mutex */
492 	mutex_count = mutex->count;
493 
494 	/* transfer from the mutex queue to the condvar queue */
495 	_spinlock(&mutex->lock);
496 	self->blocking_cond = cond;
497 	TAILQ_INSERT_TAIL(&cond->waiters, self, waiting);
498 	_spinunlock(&cond->lock);
499 
500 	/* wake the next guy blocked on the mutex */
501 	mutex->count = 0;
502 	mutex->owner = next = TAILQ_FIRST(&mutex->lockers);
503 	if (next != NULL) {
504 		TAILQ_REMOVE(&mutex->lockers, next, waiting);
505 		__thrwakeup(next, 1);
506 	}
507 
508 	/* wait until we're the owner of the mutex again */
509 	while (mutex->owner != self) {
510 		error = __thrsleep(self, 0, NULL, &mutex->lock,
511 		    &self->delayed_cancel);
512 
513 		/*
514 		 * If we took a normal signal (not from
515 		 * cancellation) then we should just go back to
516 		 * sleep without changing state (timeouts, etc).
517 		 */
518 		if ((error == EINTR || error == ECANCELED) &&
519 		    (tib->tib_canceled == 0 ||
520 		    (tib->tib_cantcancel & CANCEL_DISABLED))) {
521 			_spinlock(&mutex->lock);
522 			continue;
523 		}
524 
525 		/*
526 		 * The remaining reasons for waking up (normal
527 		 * wakeup and cancellation) all mean that we won't
528 		 * be staying in the condvar queue and we'll no
529 		 * longer be cancelable.
530 		 */
531 		LEAVE_CANCEL_POINT_INNER(tib, 0);
532 
533 		/*
534 		 * If we're no longer in the condvar's queue then
535 		 * we're just waiting for mutex ownership.  Need
536 		 * cond->lock here to prevent race with cond_signal().
537 		 */
538 		_spinlock(&cond->lock);
539 		if (self->blocking_cond == NULL) {
540 			_spinunlock(&cond->lock);
541 			_spinlock(&mutex->lock);
542 			continue;
543 		}
544 		assert(self->blocking_cond == cond);
545 
546 		/* if canceled, make note of that */
547 		if (error == EINTR)
548 			canceled = 1;
549 
550 		/* transfer between the queues */
551 		TAILQ_REMOVE(&cond->waiters, self, waiting);
552 		assert(mutex == cond->mutex);
553 		if (TAILQ_EMPTY(&cond->waiters))
554 			cond->mutex = NULL;
555 		self->blocking_cond = NULL;
556 		_spinunlock(&cond->lock);
557 		_spinlock(&mutex->lock);
558 
559 		/* mutex unlocked right now? */
560 		if (mutex->owner == NULL &&
561 		    TAILQ_EMPTY(&mutex->lockers)) {
562 			assert(mutex->count == 0);
563 			mutex->owner = self;
564 			break;
565 		}
566 		TAILQ_INSERT_TAIL(&mutex->lockers, self, waiting);
567 	}
568 
569 	/* restore the mutex's count */
570 	mutex->count = mutex_count;
571 	_spinunlock(&mutex->lock);
572 
573 	LEAVE_CANCEL_POINT_INNER(tib, canceled);
574 
575 	return (0);
576 }
577 
578 
579 int
pthread_cond_signal(pthread_cond_t * condp)580 pthread_cond_signal(pthread_cond_t *condp)
581 {
582 	pthread_cond_t cond;
583 	struct pthread_mutex *mutex;
584 	pthread_t thread;
585 	int wakeup;
586 
587 	/* uninitialized?  Then there's obviously no one waiting! */
588 	if (!*condp)
589 		return 0;
590 
591 	cond = *condp;
592 	_rthread_debug(5, "%p: cond_signal %p,%p\n", (void *)pthread_self(),
593 	    (void *)cond, (void *)cond->mutex);
594 	_spinlock(&cond->lock);
595 	thread = TAILQ_FIRST(&cond->waiters);
596 	if (thread == NULL) {
597 		assert(cond->mutex == NULL);
598 		_spinunlock(&cond->lock);
599 		return (0);
600 	}
601 
602 	assert(thread->blocking_cond == cond);
603 	TAILQ_REMOVE(&cond->waiters, thread, waiting);
604 	thread->blocking_cond = NULL;
605 
606 	mutex = cond->mutex;
607 	assert(mutex != NULL);
608 	if (TAILQ_EMPTY(&cond->waiters))
609 		cond->mutex = NULL;
610 
611 	/* link locks to prevent race with timedwait */
612 	_spinlock(&mutex->lock);
613 	_spinunlock(&cond->lock);
614 
615 	wakeup = mutex->owner == NULL && TAILQ_EMPTY(&mutex->lockers);
616 	if (wakeup)
617 		mutex->owner = thread;
618 	else
619 		TAILQ_INSERT_TAIL(&mutex->lockers, thread, waiting);
620 	_spinunlock(&mutex->lock);
621 	if (wakeup)
622 		__thrwakeup(thread, 1);
623 
624 	return (0);
625 }
626 
627 int
pthread_cond_broadcast(pthread_cond_t * condp)628 pthread_cond_broadcast(pthread_cond_t *condp)
629 {
630 	pthread_cond_t cond;
631 	struct pthread_mutex *mutex;
632 	pthread_t thread;
633 	pthread_t p;
634 	int wakeup;
635 
636 	/* uninitialized?  Then there's obviously no one waiting! */
637 	if (!*condp)
638 		return 0;
639 
640 	cond = *condp;
641 	_rthread_debug(5, "%p: cond_broadcast %p,%p\n", (void *)pthread_self(),
642 	    (void *)cond, (void *)cond->mutex);
643 	_spinlock(&cond->lock);
644 	thread = TAILQ_FIRST(&cond->waiters);
645 	if (thread == NULL) {
646 		assert(cond->mutex == NULL);
647 		_spinunlock(&cond->lock);
648 		return (0);
649 	}
650 
651 	mutex = cond->mutex;
652 	assert(mutex != NULL);
653 
654 	/* walk the list, clearing the "blocked on condvar" pointer */
655 	p = thread;
656 	do
657 		p->blocking_cond = NULL;
658 	while ((p = TAILQ_NEXT(p, waiting)) != NULL);
659 
660 	/*
661 	 * We want to transfer all the threads from the condvar's list
662 	 * to the mutex's list.  The TAILQ_* macros don't let us do that
663 	 * efficiently, so this is direct list surgery.  Pay attention!
664 	 */
665 
666 	/* 1) attach the first thread to the end of the mutex's list */
667 	_spinlock(&mutex->lock);
668 	wakeup = mutex->owner == NULL && TAILQ_EMPTY(&mutex->lockers);
669 	thread->waiting.tqe_prev = mutex->lockers.tqh_last;
670 	*(mutex->lockers.tqh_last) = thread;
671 
672 	/* 2) fix up the end pointer for the mutex's list */
673 	mutex->lockers.tqh_last = cond->waiters.tqh_last;
674 
675 	if (wakeup) {
676 		TAILQ_REMOVE(&mutex->lockers, thread, waiting);
677 		mutex->owner = thread;
678 		_spinunlock(&mutex->lock);
679 		__thrwakeup(thread, 1);
680 	} else
681 		_spinunlock(&mutex->lock);
682 
683 	/* 3) reset the condvar's list and mutex pointer */
684 	TAILQ_INIT(&cond->waiters);
685 	assert(cond->mutex != NULL);
686 	cond->mutex = NULL;
687 	_spinunlock(&cond->lock);
688 
689 	return (0);
690 }
691