1 /*	$OpenBSD: uthread_mutex.c,v 1.17 2003/01/31 04:46:17 marc Exp $	*/
2 /*
3  * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by John Birrell.
17  * 4. Neither the name of the author nor the names of any co-contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: uthread_mutex.c,v 1.16 1999/08/28 00:03:40 peter Exp $
34  */
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <sys/param.h>
39 #include <sys/queue.h>
40 #ifdef _THREAD_SAFE
41 #include <pthread.h>
42 #include "pthread_private.h"
43 
44 #if defined(_PTHREADS_INVARIANTS)
45 #define _MUTEX_INIT_LINK(m) 		do {		\
46 	(m)->m_qe.tqe_prev = NULL;			\
47 	(m)->m_qe.tqe_next = NULL;			\
48 } while (0)
49 #define _MUTEX_ASSERT_IS_OWNED(m)	do {		\
50 	if ((m)->m_qe.tqe_prev == NULL)			\
51 		PANIC("mutex is not on list");		\
52 } while (0)
53 #define _MUTEX_ASSERT_NOT_OWNED(m)	do {		\
54 	if (((m)->m_qe.tqe_prev != NULL) ||		\
55 	    ((m)->m_qe.tqe_next != NULL))		\
56 		PANIC("mutex is on list");		\
57 } while (0)
58 #else
59 #define _MUTEX_INIT_LINK(m)
60 #define _MUTEX_ASSERT_IS_OWNED(m)
61 #define _MUTEX_ASSERT_NOT_OWNED(m)
62 #endif
63 
64 /*
65  * Prototypes
66  */
67 static inline int	mutex_self_trylock(pthread_mutex_t);
68 static inline int	mutex_self_lock(pthread_mutex_t);
69 static inline int	mutex_unlock_common(pthread_mutex_t *, int);
70 static void		mutex_priority_adjust(pthread_mutex_t);
71 static void		mutex_rescan_owned (pthread_t, pthread_mutex_t);
72 static inline pthread_t	mutex_queue_deq(pthread_mutex_t);
73 static inline void	mutex_queue_remove(pthread_mutex_t, pthread_t);
74 static inline void	mutex_queue_enq(pthread_mutex_t, pthread_t);
75 
76 
77 static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER;
78 
79 /* Reinitialize a mutex to defaults. */
80 int
_mutex_reinit(pthread_mutex_t * mutex)81 _mutex_reinit(pthread_mutex_t * mutex)
82 {
83 	int	ret = 0;
84 
85 	if (mutex == NULL)
86 		ret = EINVAL;
87 	else if (*mutex == NULL)
88 		ret = pthread_mutex_init(mutex, NULL);
89 	else {
90 		/*
91 		 * Initialize the mutex structure:
92 		 */
93 		(*mutex)->m_type = PTHREAD_MUTEX_DEFAULT;
94 		(*mutex)->m_protocol = PTHREAD_PRIO_NONE;
95 		TAILQ_INIT(&(*mutex)->m_queue);
96 		(*mutex)->m_owner = NULL;
97 		(*mutex)->m_data.m_count = 0;
98 		(*mutex)->m_flags &= MUTEX_FLAGS_PRIVATE;
99 		(*mutex)->m_flags |= MUTEX_FLAGS_INITED;
100 		(*mutex)->m_refcount = 0;
101 		(*mutex)->m_prio = 0;
102 		(*mutex)->m_saved_prio = 0;
103 		_MUTEX_INIT_LINK(*mutex);
104 		_SPINLOCK_INIT(&(*mutex)->lock);
105 	}
106 	return (ret);
107 }
108 
109 int
pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t * mutex_attr)110 pthread_mutex_init(pthread_mutex_t * mutex,
111 		   const pthread_mutexattr_t * mutex_attr)
112 {
113 	pthread_mutex_t	pmutex;
114 	enum pthread_mutextype	type = PTHREAD_MUTEX_ERRORCHECK;
115 	int		protocol = PTHREAD_PRIO_NONE;
116 	int		ceiling = PTHREAD_MAX_PRIORITY;
117 	int		flags = 0;
118 	int		ret = 0;
119 
120 	if (mutex == NULL)
121 		ret = EINVAL;
122 
123 	/* Check if default mutex attributes: */
124 	else if (mutex_attr == NULL || *mutex_attr == NULL) {
125 		/* Default to a (error checking) POSIX mutex: */
126 		/***type = PTHREAD_MUTEX_ERRORCHECK;
127 		protocol = PTHREAD_PRIO_NONE;
128 		ceiling = PTHREAD_MAX_PRIORITY;
129 		flags = 0;***/
130 	}
131 
132 	/* Check mutex type: */
133 	else if (((*mutex_attr)->m_type < PTHREAD_MUTEX_ERRORCHECK) ||
134 	    ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX))
135 		/* Return an invalid argument error: */
136 		ret = EINVAL;
137 
138 	/* Check mutex protocol: */
139 	else if (((*mutex_attr)->m_protocol < PTHREAD_PRIO_NONE) ||
140 	    ((*mutex_attr)->m_protocol > PTHREAD_PRIO_PROTECT))
141 		/* Return an invalid argument error: */
142 		ret = EINVAL;
143 
144 	else {
145 		/* Use the requested mutex type and protocol: */
146 		type = (*mutex_attr)->m_type;
147 		protocol = (*mutex_attr)->m_protocol;
148 		ceiling = (*mutex_attr)->m_ceiling;
149 		flags = (*mutex_attr)->m_flags;
150 	}
151 
152 	/* Check no errors so far: */
153 	if (ret == 0) {
154 		if ((pmutex = (pthread_mutex_t)
155 		    malloc(sizeof(struct pthread_mutex))) == NULL)
156 			ret = ENOMEM;
157 		else {
158 			/* Set the mutex flags: */
159 			pmutex->m_flags = flags;
160 
161 			/* Process according to mutex type: */
162 			switch (type) {
163 			/* case PTHREAD_MUTEX_DEFAULT: */
164 			case PTHREAD_MUTEX_ERRORCHECK:
165 			case PTHREAD_MUTEX_NORMAL:
166 				/* Nothing to do here. */
167 				break;
168 
169 			/* Single UNIX Spec 2 recursive mutex: */
170 			case PTHREAD_MUTEX_RECURSIVE:
171 				/* Reset the mutex count: */
172 				pmutex->m_data.m_count = 0;
173 				break;
174 
175 			/* Trap invalid mutex types: */
176 			default:
177 				/* Return an invalid argument error: */
178 				ret = EINVAL;
179 				break;
180 			}
181 			if (ret == 0) {
182 				/* Initialise the rest of the mutex: */
183 				TAILQ_INIT(&pmutex->m_queue);
184 				pmutex->m_flags |= MUTEX_FLAGS_INITED;
185 				pmutex->m_owner = NULL;
186 				pmutex->m_type = type;
187 				pmutex->m_protocol = protocol;
188 				pmutex->m_refcount = 0;
189 				if (protocol == PTHREAD_PRIO_PROTECT)
190 					pmutex->m_prio = ceiling;
191 				else
192 					pmutex->m_prio = 0;
193 				pmutex->m_saved_prio = 0;
194 				_MUTEX_INIT_LINK(pmutex);
195 				_SPINLOCK_INIT(&pmutex->lock);
196 				*mutex = pmutex;
197 			} else {
198 				free((void *)pmutex);
199 				*mutex = NULL;
200 			}
201 		}
202 	}
203 	/* Return the completion status: */
204 	return(ret);
205 }
206 
207 int
pthread_mutex_destroy(pthread_mutex_t * mutex)208 pthread_mutex_destroy(pthread_mutex_t * mutex)
209 {
210 	int	ret = 0;
211 
212 	if (mutex == NULL || *mutex == NULL)
213 		ret = EINVAL;
214 	else {
215 		/* Lock the mutex structure: */
216 		_SPINLOCK(&(*mutex)->lock);
217 
218 		/*
219 		 * Check to see if this mutex is in use:
220 		 */
221 		if (((*mutex)->m_owner != NULL) ||
222 		    (TAILQ_FIRST(&(*mutex)->m_queue) != NULL) ||
223 		    ((*mutex)->m_refcount != 0)) {
224 			ret = EBUSY;
225 
226 			/* Unlock the mutex structure: */
227 			_SPINUNLOCK(&(*mutex)->lock);
228 		}
229 		else {
230 			/*
231 			 * Free the memory allocated for the mutex
232 			 * structure:
233 			 */
234 			_MUTEX_ASSERT_NOT_OWNED(*mutex);
235 			free((void *)*mutex);
236 
237 			/*
238 			 * Leave the caller's pointer NULL now that
239 			 * the mutex has been destroyed:
240 			 */
241 			*mutex = NULL;
242 		}
243 	}
244 
245 	/* Return the completion status: */
246 	return (ret);
247 }
248 
249 static int
init_static(pthread_mutex_t * mutex)250 init_static(pthread_mutex_t *mutex)
251 {
252 	int	ret;
253 
254 	_SPINLOCK(&static_init_lock);
255 
256 	if (*mutex == NULL)
257 		ret = pthread_mutex_init(mutex, NULL);
258 	else
259 		ret = 0;
260 
261 	_SPINUNLOCK(&static_init_lock);
262 
263 	return(ret);
264 }
265 
266 static int
mutex_trylock_common(pthread_mutex_t * mutex)267 mutex_trylock_common(pthread_mutex_t *mutex)
268 {
269 	struct pthread	*curthread = _get_curthread();
270 	int	ret = 0;
271 
272 	PTHREAD_ASSERT((mutex != NULL) && (*mutex != NULL),
273 	    "Uninitialized mutex in mutex_trylock_common");
274 
275 	/*
276 	 * Defer signals to protect the scheduling queues from
277 	 * access by the signal handler:
278 	 */
279 	_thread_kern_sig_defer();
280 
281 	/* Lock the mutex structure: */
282 	_SPINLOCK(&(*mutex)->lock);
283 
284 	/*
285 	 * If the mutex was statically allocated, properly
286 	 * initialize the tail queue.
287 	 */
288 	if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
289 		TAILQ_INIT(&(*mutex)->m_queue);
290 		_MUTEX_INIT_LINK(*mutex);
291 		(*mutex)->m_flags |= MUTEX_FLAGS_INITED;
292 	}
293 
294 	/* Process according to mutex type: */
295 	switch ((*mutex)->m_protocol) {
296 	/* Default POSIX mutex: */
297 	case PTHREAD_PRIO_NONE:
298 		/* Check if this mutex is not locked: */
299 		if ((*mutex)->m_owner == NULL) {
300 			/* Lock the mutex for the running thread: */
301 			(*mutex)->m_owner = curthread;
302 
303 			/* Add to the list of owned mutexes: */
304 			_MUTEX_ASSERT_NOT_OWNED(*mutex);
305 			TAILQ_INSERT_TAIL(&curthread->mutexq,
306 			    (*mutex), m_qe);
307 		} else if ((*mutex)->m_owner == curthread)
308 			ret = mutex_self_trylock(*mutex);
309 		else
310 			/* Return a busy error: */
311 			ret = EBUSY;
312 		break;
313 
314 	/* POSIX priority inheritence mutex: */
315 	case PTHREAD_PRIO_INHERIT:
316 		/* Check if this mutex is not locked: */
317 		if ((*mutex)->m_owner == NULL) {
318 			/* Lock the mutex for the running thread: */
319 			(*mutex)->m_owner = curthread;
320 
321 			/* Track number of priority mutexes owned: */
322 			curthread->priority_mutex_count++;
323 
324 			/*
325 			 * The mutex takes on the attributes of the
326 			 * running thread when there are no waiters.
327 			 */
328 			(*mutex)->m_prio = curthread->active_priority;
329 			(*mutex)->m_saved_prio =
330 			    curthread->inherited_priority;
331 
332 			/* Add to the list of owned mutexes: */
333 			_MUTEX_ASSERT_NOT_OWNED(*mutex);
334 			TAILQ_INSERT_TAIL(&curthread->mutexq,
335 			    (*mutex), m_qe);
336 		} else if ((*mutex)->m_owner == curthread)
337 			ret = mutex_self_trylock(*mutex);
338 		else
339 			/* Return a busy error: */
340 			ret = EBUSY;
341 		break;
342 
343 	/* POSIX priority protection mutex: */
344 	case PTHREAD_PRIO_PROTECT:
345 		/* Check for a priority ceiling violation: */
346 		if (curthread->active_priority > (*mutex)->m_prio)
347 			ret = EINVAL;
348 
349 		/* Check if this mutex is not locked: */
350 		else if ((*mutex)->m_owner == NULL) {
351 			/* Lock the mutex for the running thread: */
352 			(*mutex)->m_owner = curthread;
353 
354 			/* Track number of priority mutexes owned: */
355 			curthread->priority_mutex_count++;
356 
357 			/*
358 			 * The running thread inherits the ceiling
359 			 * priority of the mutex and executes at that
360 			 * priority.
361 			 */
362 			curthread->active_priority = (*mutex)->m_prio;
363 			(*mutex)->m_saved_prio =
364 			    curthread->inherited_priority;
365 			curthread->inherited_priority =
366 			    (*mutex)->m_prio;
367 
368 			/* Add to the list of owned mutexes: */
369 			_MUTEX_ASSERT_NOT_OWNED(*mutex);
370 			TAILQ_INSERT_TAIL(&curthread->mutexq,
371 			    (*mutex), m_qe);
372 		} else if ((*mutex)->m_owner == curthread)
373 			ret = mutex_self_trylock(*mutex);
374 		else
375 			/* Return a busy error: */
376 			ret = EBUSY;
377 		break;
378 
379 	/* Trap invalid mutex types: */
380 	default:
381 		/* Return an invalid argument error: */
382 		ret = EINVAL;
383 		break;
384 	}
385 
386 	/* Unlock the mutex structure: */
387 	_SPINUNLOCK(&(*mutex)->lock);
388 
389 	/*
390 	 * Undefer and handle pending signals, yielding if
391 	 * necessary:
392 	 */
393 	_thread_kern_sig_undefer();
394 
395 	/* Return the completion status: */
396 	return (ret);
397 }
398 
399 int
pthread_mutex_trylock(pthread_mutex_t * mutex)400 pthread_mutex_trylock(pthread_mutex_t *mutex)
401 {
402 	int	ret = 0;
403 
404 	if (mutex == NULL)
405 		ret = EINVAL;
406 
407 	/*
408 	 * If the mutex is statically initialized, perform the dynamic
409 	 * initialization:
410 	 */
411 	else if ((*mutex != NULL) || (ret = init_static(mutex)) == 0)
412 		ret = mutex_trylock_common(mutex);
413 
414 	return (ret);
415 }
416 
417 static int
mutex_lock_common(pthread_mutex_t * mutex)418 mutex_lock_common(pthread_mutex_t * mutex)
419 {
420 	struct pthread	*curthread = _get_curthread();
421 	int	ret = 0;
422 
423 	PTHREAD_ASSERT((mutex != NULL) && (*mutex != NULL),
424 	    "Uninitialized mutex in mutex_lock_common");
425 
426 	/* Reset the interrupted flag: */
427 	curthread->interrupted = 0;
428 
429 	/*
430 	 * Enter a loop waiting to become the mutex owner.  We need a
431 	 * loop in case the waiting thread is interrupted by a signal
432 	 * to execute a signal handler.  It is not (currently) possible
433 	 * to remain in the waiting queue while running a handler.
434 	 * Instead, the thread is interrupted and backed out of the
435 	 * waiting queue prior to executing the signal handler.
436 	 */
437 	do {
438 		/*
439 		 * Defer signals to protect the scheduling queues from
440 		 * access by the signal handler:
441 		 */
442 		_thread_kern_sig_defer();
443 
444 		/* Lock the mutex structure: */
445 		_SPINLOCK(&(*mutex)->lock);
446 
447 		/*
448 		 * If the mutex was statically allocated, properly
449 		 * initialize the tail queue.
450 		 */
451 		if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
452 			TAILQ_INIT(&(*mutex)->m_queue);
453 			(*mutex)->m_flags |= MUTEX_FLAGS_INITED;
454 			_MUTEX_INIT_LINK(*mutex);
455 		}
456 
457 		/* Process according to mutex type: */
458 		switch ((*mutex)->m_protocol) {
459 		/* Default POSIX mutex: */
460 		case PTHREAD_PRIO_NONE:
461 			if ((*mutex)->m_owner == NULL) {
462 				/* Lock the mutex for this thread: */
463 				(*mutex)->m_owner = curthread;
464 
465 				/* Add to the list of owned mutexes: */
466 				_MUTEX_ASSERT_NOT_OWNED(*mutex);
467 				TAILQ_INSERT_TAIL(&curthread->mutexq,
468 				    (*mutex), m_qe);
469 
470 			} else if ((*mutex)->m_owner == curthread)
471 				ret = mutex_self_lock(*mutex);
472 			else {
473 				/*
474 				 * Join the queue of threads waiting to lock
475 				 * the mutex:
476 				 */
477 				mutex_queue_enq(*mutex, curthread);
478 
479 				/*
480 				 * Keep a pointer to the mutex this thread
481 				 * is waiting on:
482 				 */
483 				curthread->data.mutex = *mutex;
484 
485 				/*
486 				 * Unlock the mutex structure and schedule the
487 				 * next thread:
488 				 */
489 				_thread_kern_sched_state_unlock(PS_MUTEX_WAIT,
490 				    &(*mutex)->lock, __FILE__, __LINE__);
491 
492 				/* Lock the mutex structure again: */
493 				_SPINLOCK(&(*mutex)->lock);
494 			}
495 			break;
496 
497 		/* POSIX priority inheritence mutex: */
498 		case PTHREAD_PRIO_INHERIT:
499 			/* Check if this mutex is not locked: */
500 			if ((*mutex)->m_owner == NULL) {
501 				/* Lock the mutex for this thread: */
502 				(*mutex)->m_owner = curthread;
503 
504 				/* Track number of priority mutexes owned: */
505 				curthread->priority_mutex_count++;
506 
507 				/*
508 				 * The mutex takes on attributes of the
509 				 * running thread when there are no waiters.
510 				 */
511 				(*mutex)->m_prio = curthread->active_priority;
512 				(*mutex)->m_saved_prio =
513 				    curthread->inherited_priority;
514 				curthread->inherited_priority =
515 				    (*mutex)->m_prio;
516 
517 				/* Add to the list of owned mutexes: */
518 				_MUTEX_ASSERT_NOT_OWNED(*mutex);
519 				TAILQ_INSERT_TAIL(&curthread->mutexq,
520 				    (*mutex), m_qe);
521 
522 			} else if ((*mutex)->m_owner == curthread)
523 				ret = mutex_self_lock(*mutex);
524 			else {
525 				/*
526 				 * Join the queue of threads waiting to lock
527 				 * the mutex:
528 				 */
529 				mutex_queue_enq(*mutex, curthread);
530 
531 				/*
532 				 * Keep a pointer to the mutex this thread
533 				 * is waiting on:
534 				 */
535 				curthread->data.mutex = *mutex;
536 
537 				if (curthread->active_priority >
538 				    (*mutex)->m_prio)
539 					/* Adjust priorities: */
540 					mutex_priority_adjust(*mutex);
541 
542 				/*
543 				 * Unlock the mutex structure and schedule the
544 				 * next thread:
545 				 */
546 				_thread_kern_sched_state_unlock(PS_MUTEX_WAIT,
547 				    &(*mutex)->lock, __FILE__, __LINE__);
548 
549 				/* Lock the mutex structure again: */
550 				_SPINLOCK(&(*mutex)->lock);
551 			}
552 			break;
553 
554 		/* POSIX priority protection mutex: */
555 		case PTHREAD_PRIO_PROTECT:
556 			/* Check for a priority ceiling violation: */
557 			if (curthread->active_priority > (*mutex)->m_prio)
558 				ret = EINVAL;
559 
560 			/* Check if this mutex is not locked: */
561 			else if ((*mutex)->m_owner == NULL) {
562 				/*
563 				 * Lock the mutex for the running
564 				 * thread:
565 				 */
566 				(*mutex)->m_owner = curthread;
567 
568 				/* Track number of priority mutexes owned: */
569 				curthread->priority_mutex_count++;
570 
571 				/*
572 				 * The running thread inherits the ceiling
573 				 * priority of the mutex and executes at that
574 				 * priority:
575 				 */
576 				curthread->active_priority = (*mutex)->m_prio;
577 				(*mutex)->m_saved_prio =
578 				    curthread->inherited_priority;
579 				curthread->inherited_priority =
580 				    (*mutex)->m_prio;
581 
582 				/* Add to the list of owned mutexes: */
583 				_MUTEX_ASSERT_NOT_OWNED(*mutex);
584 				TAILQ_INSERT_TAIL(&curthread->mutexq,
585 				    (*mutex), m_qe);
586 			} else if ((*mutex)->m_owner == curthread)
587 				ret = mutex_self_lock(*mutex);
588 			else {
589 				/*
590 				 * Join the queue of threads waiting to lock
591 				 * the mutex:
592 				 */
593 				mutex_queue_enq(*mutex, curthread);
594 
595 				/*
596 				 * Keep a pointer to the mutex this thread
597 				 * is waiting on:
598 				 */
599 				curthread->data.mutex = *mutex;
600 
601 				/* Clear any previous error: */
602 				curthread->error = 0;
603 
604 				/*
605 				 * Unlock the mutex structure and schedule the
606 				 * next thread:
607 				 */
608 				_thread_kern_sched_state_unlock(PS_MUTEX_WAIT,
609 				    &(*mutex)->lock, __FILE__, __LINE__);
610 
611 				/* Lock the mutex structure again: */
612 				_SPINLOCK(&(*mutex)->lock);
613 
614 				/*
615 				 * The threads priority may have changed while
616 				 * waiting for the mutex causing a ceiling
617 				 * violation.
618 				 */
619 				ret = curthread->error;
620 				curthread->error = 0;
621 			}
622 			break;
623 
624 		/* Trap invalid mutex types: */
625 		default:
626 			/* Return an invalid argument error: */
627 			ret = EINVAL;
628 			break;
629 		}
630 
631 		/*
632 		 * Check to see if this thread was interrupted and
633 		 * is still in the mutex queue of waiting threads:
634 		 */
635 		if (curthread->interrupted != 0)
636 			mutex_queue_remove(*mutex, curthread);
637 
638 		/* Unlock the mutex structure: */
639 		_SPINUNLOCK(&(*mutex)->lock);
640 
641 		/*
642 		 * Undefer and handle pending signals, yielding if
643 		 * necessary:
644 		 */
645 		_thread_kern_sig_undefer();
646 	} while (((*mutex)->m_owner != curthread) && (ret == 0) &&
647 	    (curthread->interrupted == 0));
648 
649 	if (curthread->interrupted != 0 &&
650 	    curthread->continuation != NULL)
651 		curthread->continuation((void *) curthread);
652 
653 	/* Return the completion status: */
654 	return (ret);
655 }
656 
657 int
pthread_mutex_lock(pthread_mutex_t * mutex)658 pthread_mutex_lock(pthread_mutex_t *mutex)
659 {
660 	int	ret = 0;
661 
662 	if (_thread_initial == NULL)
663 		_thread_init();
664 
665 	if (mutex == NULL)
666 		ret = EINVAL;
667 
668 	/*
669 	 * If the mutex is statically initialized, perform the dynamic
670 	 * initialization:
671 	 */
672 	else if ((*mutex != NULL) || ((ret = init_static(mutex)) == 0))
673 		ret = mutex_lock_common(mutex);
674 
675 	return (ret);
676 }
677 
678 int
pthread_mutex_unlock(pthread_mutex_t * mutex)679 pthread_mutex_unlock(pthread_mutex_t * mutex)
680 {
681 	return (mutex_unlock_common(mutex, /* add reference */ 0));
682 }
683 
684 int
_mutex_cv_unlock(pthread_mutex_t * mutex)685 _mutex_cv_unlock(pthread_mutex_t * mutex)
686 {
687 	return (mutex_unlock_common(mutex, /* add reference */ 1));
688 }
689 
690 int
_mutex_cv_lock(pthread_mutex_t * mutex)691 _mutex_cv_lock(pthread_mutex_t * mutex)
692 {
693 	int	ret;
694 	if ((ret = pthread_mutex_lock(mutex)) == 0)
695 		(*mutex)->m_refcount--;
696 	return (ret);
697 }
698 
699 static inline int
mutex_self_trylock(pthread_mutex_t mutex)700 mutex_self_trylock(pthread_mutex_t mutex)
701 {
702 	int	ret = 0;
703 
704 	switch (mutex->m_type) {
705 
706 	/* case PTHREAD_MUTEX_DEFAULT: */
707 	case PTHREAD_MUTEX_ERRORCHECK:
708 	case PTHREAD_MUTEX_NORMAL:
709 		/*
710 		 * POSIX specifies that mutexes should return EDEADLK if a
711 		 * recursive lock is detected.
712 		 */
713 		ret = EBUSY;
714 		break;
715 
716 	case PTHREAD_MUTEX_RECURSIVE:
717 		/* Increment the lock count: */
718 		mutex->m_data.m_count++;
719 		break;
720 
721 	default:
722 		/* Trap invalid mutex types; */
723 		ret = EINVAL;
724 	}
725 
726 	return(ret);
727 }
728 
729 static inline int
mutex_self_lock(pthread_mutex_t mutex)730 mutex_self_lock(pthread_mutex_t mutex)
731 {
732 	int ret = 0;
733 
734 	switch (mutex->m_type) {
735 	/* case PTHREAD_MUTEX_DEFAULT: */
736 	case PTHREAD_MUTEX_ERRORCHECK:
737 		/*
738 		 * POSIX specifies that mutexes should return EDEADLK if a
739 		 * recursive lock is detected.
740 		 */
741 		ret = EDEADLK;
742 		break;
743 
744 	case PTHREAD_MUTEX_NORMAL:
745 		/*
746 		 * What SS2 define as a 'normal' mutex.  Intentionally
747 		 * deadlock on attempts to get a lock you already own.
748 		 */
749 		_thread_kern_sched_state_unlock(PS_DEADLOCK,
750 		    &mutex->lock, __FILE__, __LINE__);
751 		break;
752 
753 	case PTHREAD_MUTEX_RECURSIVE:
754 		/* Increment the lock count: */
755 		mutex->m_data.m_count++;
756 		break;
757 
758 	default:
759 		/* Trap invalid mutex types; */
760 		ret = EINVAL;
761 	}
762 
763 	return(ret);
764 }
765 
766 static inline int
mutex_unlock_common(pthread_mutex_t * mutex,int add_reference)767 mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
768 {
769 	struct pthread	*curthread = _get_curthread();
770 	int	ret = 0;
771 
772 	if (mutex == NULL || *mutex == NULL) {
773 		ret = EINVAL;
774 	} else {
775 		/*
776 		 * Defer signals to protect the scheduling queues from
777 		 * access by the signal handler:
778 		 */
779 		_thread_kern_sig_defer();
780 
781 		/* Lock the mutex structure: */
782 		_SPINLOCK(&(*mutex)->lock);
783 
784 		/* Process according to mutex type: */
785 		switch ((*mutex)->m_protocol) {
786 		/* Default POSIX mutex: */
787 		case PTHREAD_PRIO_NONE:
788 			/*
789 			 * Check if the running thread is not the owner of the
790 			 * mutex:
791 			 */
792 			if ((*mutex)->m_owner != curthread) {
793 				/*
794 				 * Return an invalid argument error for no
795 				 * owner and a permission error otherwise:
796 				 */
797 				ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM;
798 			}
799 			else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
800 			    ((*mutex)->m_data.m_count > 0)) {
801 				/* Decrement the count: */
802 				(*mutex)->m_data.m_count--;
803 			} else {
804 				/*
805 				 * Clear the count in case this is recursive
806 				 * mutex.
807 				 */
808 				(*mutex)->m_data.m_count = 0;
809 
810 				/* Remove the mutex from the threads queue. */
811 				_MUTEX_ASSERT_IS_OWNED(*mutex);
812 				TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
813 				    (*mutex), m_qe);
814 				_MUTEX_INIT_LINK(*mutex);
815 
816 				/*
817 				 * Get the next thread from the queue of
818 				 * threads waiting on the mutex:
819 				 */
820 				if (((*mutex)->m_owner =
821 			  	    mutex_queue_deq(*mutex)) != NULL) {
822 					/*
823 					 * Unless the new owner of the mutex is
824 					 * currently suspended, allow the owner
825 					 * to run.  If the thread is suspended,
826 					 * make a note that the thread isn't in
827 					 * a wait queue any more.
828 					 */
829 					if (((*mutex)->m_owner->state !=
830 					    PS_SUSPENDED)) {
831 						PTHREAD_NEW_STATE((*mutex)->m_owner,
832 						    PS_RUNNING);
833 					} else {
834 						(*mutex)->m_owner->suspended =
835 						    SUSP_NOWAIT;
836 					}
837 
838 					/*
839 					 * Add the mutex to the threads list of
840 					 * owned mutexes:
841 					 */
842 					TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
843 					    (*mutex), m_qe);
844 
845 					/*
846 					 * The owner is no longer waiting for
847 					 * this mutex:
848 					 */
849 					(*mutex)->m_owner->data.mutex = NULL;
850 				}
851 			}
852 			break;
853 
854 		/* POSIX priority inheritence mutex: */
855 		case PTHREAD_PRIO_INHERIT:
856 			/*
857 			 * Check if the running thread is not the owner of the
858 			 * mutex:
859 			 */
860 			if ((*mutex)->m_owner != curthread) {
861 				/*
862 				 * Return an invalid argument error for no
863 				 * owner and a permission error otherwise:
864 				 */
865 				ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM;
866 			}
867 			else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
868 			    ((*mutex)->m_data.m_count > 0)) {
869 				/* Decrement the count: */
870 				(*mutex)->m_data.m_count--;
871 			} else {
872 				/*
873 				 * Clear the count in case this is recursive
874 				 * mutex.
875 				 */
876 				(*mutex)->m_data.m_count = 0;
877 
878 				/*
879 				 * Restore the threads inherited priority and
880 				 * recompute the active priority (being careful
881 				 * not to override changes in the threads base
882 				 * priority subsequent to locking the mutex).
883 				 */
884 				curthread->inherited_priority =
885 					(*mutex)->m_saved_prio;
886 				curthread->active_priority =
887 				    MAX(curthread->inherited_priority,
888 				    curthread->base_priority);
889 
890 				/*
891 				 * This thread now owns one less priority mutex.
892 				 */
893 				curthread->priority_mutex_count--;
894 
895 				/* Remove the mutex from the threads queue. */
896 				_MUTEX_ASSERT_IS_OWNED(*mutex);
897 				TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
898 				    (*mutex), m_qe);
899 				_MUTEX_INIT_LINK(*mutex);
900 
901 				/*
902 				 * Get the next thread from the queue of threads
903 				 * waiting on the mutex:
904 				 */
905 				if (((*mutex)->m_owner =
906 				    mutex_queue_deq(*mutex)) == NULL)
907 					/* This mutex has no priority. */
908 					(*mutex)->m_prio = 0;
909 				else {
910 					/*
911 					 * Track number of priority mutexes owned:
912 					 */
913 					(*mutex)->m_owner->priority_mutex_count++;
914 
915 					/*
916 					 * Add the mutex to the threads list
917 					 * of owned mutexes:
918 					 */
919 					TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
920 					    (*mutex), m_qe);
921 
922 					/*
923 					 * The owner is no longer waiting for
924 					 * this mutex:
925 					 */
926 					(*mutex)->m_owner->data.mutex = NULL;
927 
928 					/*
929 					 * Set the priority of the mutex.  Since
930 					 * our waiting threads are in descending
931 					 * priority order, the priority of the
932 					 * mutex becomes the active priority of
933 					 * the thread we just dequeued.
934 					 */
935 					(*mutex)->m_prio =
936 					    (*mutex)->m_owner->active_priority;
937 
938 					/*
939 					 * Save the owning threads inherited
940 					 * priority:
941 					 */
942 					(*mutex)->m_saved_prio =
943 						(*mutex)->m_owner->inherited_priority;
944 
945 					/*
946 					 * The owning threads inherited priority
947 					 * now becomes his active priority (the
948 					 * priority of the mutex).
949 					 */
950 					(*mutex)->m_owner->inherited_priority =
951 						(*mutex)->m_prio;
952 
953 					/*
954 					 * Unless the new owner of the mutex is
955 					 * currently suspended, allow the owner
956 					 * to run.  If the thread is suspended,
957 					 * make a note that the thread isn't in
958 					 * a wait queue any more.
959 					 */
960 					if (((*mutex)->m_owner->state !=
961 					    PS_SUSPENDED)) {
962 						PTHREAD_NEW_STATE((*mutex)->m_owner,
963 						    PS_RUNNING);
964 					} else {
965 						(*mutex)->m_owner->suspended =
966 						    SUSP_NOWAIT;
967 					}
968 				}
969 			}
970 			break;
971 
972 		/* POSIX priority ceiling mutex: */
973 		case PTHREAD_PRIO_PROTECT:
974 			/*
975 			 * Check if the running thread is not the owner of the
976 			 * mutex:
977 			 */
978 			if ((*mutex)->m_owner != curthread) {
979 				/*
980 				 * Return an invalid argument error for no
981 				 * owner and a permission error otherwise:
982 				 */
983 				ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM;
984 			}
985 			else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
986 			    ((*mutex)->m_data.m_count > 0)) {
987 				/* Decrement the count: */
988 				(*mutex)->m_data.m_count--;
989 			} else {
990 				/*
991 				 * Clear the count in case this is recursive
992 				 * mutex.
993 				 */
994 				(*mutex)->m_data.m_count = 0;
995 
996 				/*
997 				 * Restore the threads inherited priority and
998 				 * recompute the active priority (being careful
999 				 * not to override changes in the threads base
1000 				 * priority subsequent to locking the mutex).
1001 				 */
1002 				curthread->inherited_priority =
1003 					(*mutex)->m_saved_prio;
1004 				curthread->active_priority =
1005 				    MAX(curthread->inherited_priority,
1006 				    curthread->base_priority);
1007 
1008 				/*
1009 				 * This thread now owns one less priority mutex.
1010 				 */
1011 				curthread->priority_mutex_count--;
1012 
1013 				/* Remove the mutex from the threads queue. */
1014 				_MUTEX_ASSERT_IS_OWNED(*mutex);
1015 				TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
1016 				    (*mutex), m_qe);
1017 				_MUTEX_INIT_LINK(*mutex);
1018 
1019 				/*
1020 				 * Enter a loop to find a waiting thread whose
1021 				 * active priority will not cause a ceiling
1022 				 * violation:
1023 				 */
1024 				while ((((*mutex)->m_owner =
1025 				    mutex_queue_deq(*mutex)) != NULL) &&
1026 				    ((*mutex)->m_owner->active_priority >
1027 				     (*mutex)->m_prio)) {
1028 					/*
1029 					 * Either the mutex ceiling priority
1030 					 * been lowered and/or this threads
1031 					 * priority has been raised subsequent
1032 					 * to this thread being queued on the
1033 					 * waiting list.
1034 					 */
1035 					(*mutex)->m_owner->error = EINVAL;
1036 					PTHREAD_NEW_STATE((*mutex)->m_owner,
1037 					    PS_RUNNING);
1038 					/*
1039 					 * The thread is no longer waiting for
1040 					 * this mutex:
1041 					 */
1042 					(*mutex)->m_owner->data.mutex = NULL;
1043 				}
1044 
1045 				/* Check for a new owner: */
1046 				if ((*mutex)->m_owner != NULL) {
1047 					/*
1048 					 * Track number of priority mutexes owned:
1049 					 */
1050 					(*mutex)->m_owner->priority_mutex_count++;
1051 
1052 					/*
1053 					 * Add the mutex to the threads list
1054 					 * of owned mutexes:
1055 					 */
1056 					TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
1057 					    (*mutex), m_qe);
1058 
1059 					/*
1060 					 * The owner is no longer waiting for
1061 					 * this mutex:
1062 					 */
1063 					(*mutex)->m_owner->data.mutex = NULL;
1064 
1065 					/*
1066 					 * Save the owning threads inherited
1067 					 * priority:
1068 					 */
1069 					(*mutex)->m_saved_prio =
1070 						(*mutex)->m_owner->inherited_priority;
1071 
1072 					/*
1073 					 * The owning thread inherits the
1074 					 * ceiling priority of the mutex and
1075 					 * executes at that priority:
1076 					 */
1077 					(*mutex)->m_owner->inherited_priority =
1078 					    (*mutex)->m_prio;
1079 					(*mutex)->m_owner->active_priority =
1080 					    (*mutex)->m_prio;
1081 
1082 					/*
1083 					 * Unless the new owner of the mutex is
1084 					 * currently suspended, allow the owner
1085 					 * to run.  If the thread is suspended,
1086 					 * make a note that the thread isn't in
1087 					 * a wait queue any more.
1088 					 */
1089 					if (((*mutex)->m_owner->state !=
1090 					    PS_SUSPENDED)) {
1091 						PTHREAD_NEW_STATE((*mutex)->m_owner,
1092 						    PS_RUNNING);
1093 					} else {
1094 						(*mutex)->m_owner->suspended =
1095 						    SUSP_NOWAIT;
1096 					}
1097 				}
1098 			}
1099 			break;
1100 
1101 		/* Trap invalid mutex types: */
1102 		default:
1103 			/* Return an invalid argument error: */
1104 			ret = EINVAL;
1105 			break;
1106 		}
1107 
1108 		if ((ret == 0) && (add_reference != 0)) {
1109 			/* Increment the reference count: */
1110 			(*mutex)->m_refcount++;
1111 		}
1112 
1113 		/* Unlock the mutex structure: */
1114 		_SPINUNLOCK(&(*mutex)->lock);
1115 
1116 		/*
1117 		 * Undefer and handle pending signals, yielding if
1118 		 * necessary:
1119 		 */
1120 		_thread_kern_sig_undefer();
1121 	}
1122 
1123 	/* Return the completion status: */
1124 	return (ret);
1125 }
1126 
1127 
1128 /*
1129  * This function is called when a change in base priority occurs for
1130  * a thread that is holding or waiting for a priority protection or
1131  * inheritence mutex.  A change in a threads base priority can effect
1132  * changes to active priorities of other threads and to the ordering
1133  * of mutex locking by waiting threads.
1134  *
1135  * This must be called while thread scheduling is deferred.
1136  */
1137 void
_mutex_notify_priochange(pthread_t pthread)1138 _mutex_notify_priochange(pthread_t pthread)
1139 {
1140 	/* Adjust the priorites of any owned priority mutexes: */
1141 	if (pthread->priority_mutex_count > 0) {
1142 		/*
1143 		 * Rescan the mutexes owned by this thread and correct
1144 		 * their priorities to account for this threads change
1145 		 * in priority.  This has the side effect of changing
1146 		 * the threads active priority.
1147 		 */
1148 		mutex_rescan_owned(pthread, /* rescan all owned */ NULL);
1149 	}
1150 
1151 	/*
1152 	 * If this thread is waiting on a priority inheritence mutex,
1153 	 * check for priority adjustments.  A change in priority can
1154 	 * also effect a ceiling violation(*) for a thread waiting on
1155 	 * a priority protection mutex; we don't perform the check here
1156 	 * as it is done in pthread_mutex_unlock.
1157 	 *
1158 	 * (*) It should be noted that a priority change to a thread
1159 	 *     _after_ taking and owning a priority ceiling mutex
1160 	 *     does not affect ownership of that mutex; the ceiling
1161 	 *     priority is only checked before mutex ownership occurs.
1162 	 */
1163 	if (pthread->state == PS_MUTEX_WAIT) {
1164 		/* Lock the mutex structure: */
1165 		_SPINLOCK(&pthread->data.mutex->lock);
1166 
1167 		/*
1168 		 * Check to make sure this thread is still in the same state
1169 		 * (the spinlock above can yield the CPU to another thread):
1170 		 */
1171 		if (pthread->state == PS_MUTEX_WAIT) {
1172 			/*
1173 			 * Remove and reinsert this thread into the list of
1174 			 * waiting threads to preserve decreasing priority
1175 			 * order.
1176 			 */
1177 			mutex_queue_remove(pthread->data.mutex, pthread);
1178 			mutex_queue_enq(pthread->data.mutex, pthread);
1179 
1180 			if (pthread->data.mutex->m_protocol ==
1181 			     PTHREAD_PRIO_INHERIT) {
1182 				/* Adjust priorities: */
1183 				mutex_priority_adjust(pthread->data.mutex);
1184 			}
1185 		}
1186 
1187 		/* Unlock the mutex structure: */
1188 		_SPINUNLOCK(&pthread->data.mutex->lock);
1189 	}
1190 }
1191 
1192 /*
1193  * Called when a new thread is added to the mutex waiting queue or
1194  * when a threads priority changes that is already in the mutex
1195  * waiting queue.
1196  */
1197 static void
mutex_priority_adjust(pthread_mutex_t mutex)1198 mutex_priority_adjust(pthread_mutex_t mutex)
1199 {
1200 	pthread_t	pthread_next, pthread = mutex->m_owner;
1201 	int		temp_prio;
1202 	pthread_mutex_t	m = mutex;
1203 
1204 	/*
1205 	 * Calculate the mutex priority as the maximum of the highest
1206 	 * active priority of any waiting threads and the owning threads
1207 	 * active priority(*).
1208 	 *
1209 	 * (*) Because the owning threads current active priority may
1210 	 *     reflect priority inherited from this mutex (and the mutex
1211 	 *     priority may have changed) we must recalculate the active
1212 	 *     priority based on the threads saved inherited priority
1213 	 *     and its base priority.
1214 	 */
1215 	pthread_next = TAILQ_FIRST(&m->m_queue);  /* should never be NULL */
1216 	temp_prio = MAX(pthread_next->active_priority,
1217 	    MAX(m->m_saved_prio, pthread->base_priority));
1218 
1219 	/* See if this mutex really needs adjusting: */
1220 	if (temp_prio == m->m_prio)
1221 		/* No need to propagate the priority: */
1222 		return;
1223 
1224 	/* Set new priority of the mutex: */
1225 	m->m_prio = temp_prio;
1226 
1227 	while (m != NULL) {
1228 		/*
1229 		 * Save the threads priority before rescanning the
1230 		 * owned mutexes:
1231 		 */
1232 		temp_prio = pthread->active_priority;
1233 
1234 		/*
1235 		 * Fix the priorities for all the mutexes this thread has
1236 		 * locked since taking this mutex.  This also has a
1237 		 * potential side-effect of changing the threads priority.
1238 		 */
1239 		mutex_rescan_owned(pthread, m);
1240 
1241 		/*
1242 		 * If the thread is currently waiting on a mutex, check
1243 		 * to see if the threads new priority has affected the
1244 		 * priority of the mutex.
1245 		 */
1246 		if ((temp_prio != pthread->active_priority) &&
1247 		    (pthread->state == PS_MUTEX_WAIT) &&
1248 		    (pthread->data.mutex->m_protocol == PTHREAD_PRIO_INHERIT)) {
1249 			/* Grab the mutex this thread is waiting on: */
1250 			m = pthread->data.mutex;
1251 
1252 			/*
1253 			 * The priority for this thread has changed.  Remove
1254 			 * and reinsert this thread into the list of waiting
1255 			 * threads to preserve decreasing priority order.
1256 			 */
1257 			mutex_queue_remove(m, pthread);
1258 			mutex_queue_enq(m, pthread);
1259 
1260 			/* Grab the waiting thread with highest priority: */
1261 			pthread_next = TAILQ_FIRST(&m->m_queue);
1262 
1263 			/*
1264 			 * Calculate the mutex priority as the maximum of the
1265 			 * highest active priority of any waiting threads and
1266 			 * the owning threads active priority.
1267 			 */
1268 			temp_prio = MAX(pthread_next->active_priority,
1269 			    MAX(m->m_saved_prio, m->m_owner->base_priority));
1270 
1271 			if (temp_prio != m->m_prio) {
1272 				/*
1273 				 * The priority needs to be propagated to the
1274 				 * mutex this thread is waiting on and up to
1275 				 * the owner of that mutex.
1276 				 */
1277 				m->m_prio = temp_prio;
1278 				pthread = m->m_owner;
1279 			}
1280 			else
1281 				/* We're done: */
1282 				m = NULL;
1283 
1284 		}
1285 		else
1286 			/* We're done: */
1287 			m = NULL;
1288 	}
1289 }
1290 
1291 static void
mutex_rescan_owned(pthread_t pthread,pthread_mutex_t mutex)1292 mutex_rescan_owned(pthread_t pthread, pthread_mutex_t mutex)
1293 {
1294 	int		active_prio, inherited_prio;
1295 	pthread_mutex_t	m;
1296 	pthread_t	pthread_next;
1297 
1298 	/*
1299 	 * Start walking the mutexes the thread has taken since
1300 	 * taking this mutex.
1301 	 */
1302 	if (mutex == NULL) {
1303 		/*
1304 		 * A null mutex means start at the beginning of the owned
1305 		 * mutex list.
1306 		 */
1307 		m = TAILQ_FIRST(&pthread->mutexq);
1308 
1309 		/* There is no inherited priority yet. */
1310 		inherited_prio = 0;
1311 	}
1312 	else {
1313 		/*
1314 		 * The caller wants to start after a specific mutex.  It
1315 		 * is assumed that this mutex is a priority inheritence
1316 		 * mutex and that its priority has been correctly
1317 		 * calculated.
1318 		 */
1319 		m = TAILQ_NEXT(mutex, m_qe);
1320 
1321 		/* Start inheriting priority from the specified mutex. */
1322 		inherited_prio = mutex->m_prio;
1323 	}
1324 	active_prio = MAX(inherited_prio, pthread->base_priority);
1325 
1326 	while (m != NULL) {
1327 		/*
1328 		 * We only want to deal with priority inheritence
1329 		 * mutexes.  This might be optimized by only placing
1330 		 * priority inheritence mutexes into the owned mutex
1331 		 * list, but it may prove to be useful having all
1332 		 * owned mutexes in this list.  Consider a thread
1333 		 * exiting while holding mutexes...
1334 		 */
1335 		if (m->m_protocol == PTHREAD_PRIO_INHERIT) {
1336 			/*
1337 			 * Fix the owners saved (inherited) priority to
1338 			 * reflect the priority of the previous mutex.
1339 			 */
1340 			m->m_saved_prio = inherited_prio;
1341 
1342 			if ((pthread_next = TAILQ_FIRST(&m->m_queue)) != NULL)
1343 				/* Recalculate the priority of the mutex: */
1344 				m->m_prio = MAX(active_prio,
1345 				     pthread_next->active_priority);
1346 			else
1347 				m->m_prio = active_prio;
1348 
1349 			/* Recalculate new inherited and active priorities: */
1350 			inherited_prio = m->m_prio;
1351 			active_prio = MAX(m->m_prio, pthread->base_priority);
1352 		}
1353 
1354 		/* Advance to the next mutex owned by this thread: */
1355 		m = TAILQ_NEXT(m, m_qe);
1356 	}
1357 
1358 	/*
1359 	 * Fix the threads inherited priority and recalculate its
1360 	 * active priority.
1361 	 */
1362 	pthread->inherited_priority = inherited_prio;
1363 	active_prio = MAX(inherited_prio, pthread->base_priority);
1364 
1365 	if (active_prio != pthread->active_priority) {
1366 		/*
1367 		 * If this thread is in the priority queue, it must be
1368 		 * removed and reinserted for its new priority.
1369 	 	 */
1370 		if (pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) {
1371 			/*
1372 			 * Remove the thread from the priority queue
1373 			 * before changing its priority:
1374 			 */
1375 			PTHREAD_PRIOQ_REMOVE(pthread);
1376 
1377 			/*
1378 			 * POSIX states that if the priority is being
1379 			 * lowered, the thread must be inserted at the
1380 			 * head of the queue for its priority if it owns
1381 			 * any priority protection or inheritence mutexes.
1382 			 */
1383 			if ((active_prio < pthread->active_priority) &&
1384 			    (pthread->priority_mutex_count > 0)) {
1385 				/* Set the new active priority. */
1386 				pthread->active_priority = active_prio;
1387 
1388 				PTHREAD_PRIOQ_INSERT_HEAD(pthread);
1389 			}
1390 			else {
1391 				/* Set the new active priority. */
1392 				pthread->active_priority = active_prio;
1393 
1394 				PTHREAD_PRIOQ_INSERT_TAIL(pthread);
1395 			}
1396 		}
1397 		else {
1398 			/* Set the new active priority. */
1399 			pthread->active_priority = active_prio;
1400 		}
1401 	}
1402 }
1403 
1404 /*
1405  * Dequeue a waiting thread from the head of a mutex queue in descending
1406  * priority order.
1407  */
1408 static inline pthread_t
mutex_queue_deq(pthread_mutex_t mutex)1409 mutex_queue_deq(pthread_mutex_t mutex)
1410 {
1411 	pthread_t pthread;
1412 
1413 	while ((pthread = TAILQ_FIRST(&mutex->m_queue)) != NULL) {
1414 		TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
1415 		pthread->flags &= ~PTHREAD_FLAGS_IN_MUTEXQ;
1416 
1417 		/*
1418 		 * Only exit the loop if the thread hasn't been
1419 		 * cancelled.
1420 		 */
1421 		if (pthread->interrupted == 0)
1422 			break;
1423 	}
1424 
1425 	return(pthread);
1426 }
1427 
1428 /*
1429  * Remove a waiting thread from a mutex queue in descending priority order.
1430  */
1431 static inline void
mutex_queue_remove(pthread_mutex_t mutex,pthread_t pthread)1432 mutex_queue_remove(pthread_mutex_t mutex, pthread_t pthread)
1433 {
1434 	if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) {
1435 		TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
1436 		pthread->flags &= ~PTHREAD_FLAGS_IN_MUTEXQ;
1437 	}
1438 }
1439 
1440 /*
1441  * Enqueue a waiting thread to a queue in descending priority order.
1442  */
1443 static inline void
mutex_queue_enq(pthread_mutex_t mutex,pthread_t pthread)1444 mutex_queue_enq(pthread_mutex_t mutex, pthread_t pthread)
1445 {
1446 	pthread_t tid = TAILQ_LAST(&mutex->m_queue, mutex_head);
1447 
1448 	PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread);
1449 	/*
1450 	 * For the common case of all threads having equal priority,
1451 	 * we perform a quick check against the priority of the thread
1452 	 * at the tail of the queue.
1453 	 */
1454 	if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
1455 		TAILQ_INSERT_TAIL(&mutex->m_queue, pthread, sqe);
1456 	else {
1457 		tid = TAILQ_FIRST(&mutex->m_queue);
1458 		while (pthread->active_priority <= tid->active_priority)
1459 			tid = TAILQ_NEXT(tid, sqe);
1460 		TAILQ_INSERT_BEFORE(tid, pthread, sqe);
1461 	}
1462 	pthread->flags |= PTHREAD_FLAGS_IN_MUTEXQ;
1463 }
1464 
1465 #endif
1466