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