libc - Implement sigblockall() and sigunblockall()
[dragonfly.git] / lib / libthread_xu / thread / thr_mutex.c
1 /*
2  * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3  * Copyright (c) 2006 David Xu <davidxu@freebsd.org>.
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  */
34
35 #include "namespace.h"
36 #include <machine/tls.h>
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/queue.h>
41 #include <pthread.h>
42 #include "un-namespace.h"
43
44 #include "thr_private.h"
45
46 #ifdef _PTHREADS_DEBUGGING
47
48 #include <stdio.h>
49 #include <stdarg.h>
50 #include <sys/file.h>
51
52 #endif
53
54 #if defined(_PTHREADS_INVARIANTS)
55 #define MUTEX_INIT_LINK(m)              do {            \
56         (m)->m_qe.tqe_prev = NULL;                      \
57         (m)->m_qe.tqe_next = NULL;                      \
58 } while (0)
59 #define MUTEX_ASSERT_IS_OWNED(m)        do {            \
60         if ((m)->m_qe.tqe_prev == NULL)                 \
61                 PANIC("mutex is not on list");          \
62 } while (0)
63 #define MUTEX_ASSERT_NOT_OWNED(m)       do {            \
64         if (((m)->m_qe.tqe_prev != NULL) ||             \
65             ((m)->m_qe.tqe_next != NULL))               \
66                 PANIC("mutex is on list");              \
67 } while (0)
68 #define THR_ASSERT_NOT_IN_SYNCQ(thr)    do {            \
69         THR_ASSERT(((thr)->sflags & THR_FLAGS_IN_SYNCQ) == 0, \
70             "thread in syncq when it shouldn't be.");   \
71 } while (0);
72 #else
73 #define MUTEX_INIT_LINK(m)
74 #define MUTEX_ASSERT_IS_OWNED(m)
75 #define MUTEX_ASSERT_NOT_OWNED(m)
76 #define THR_ASSERT_NOT_IN_SYNCQ(thr)
77 #endif
78
79 #define THR_IN_MUTEXQ(thr)      (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
80 #define MUTEX_DESTROY(m) do {           \
81         __free(m);                      \
82 } while (0)
83
84 umtx_t  _mutex_static_lock;
85
86 #ifdef _PTHREADS_DEBUGGING
87
88 static
89 void
90 mutex_log(const char *ctl, ...)
91 {
92         char buf[256];
93         va_list va;
94         size_t len;
95
96         va_start(va, ctl);
97         len = vsnprintf(buf, sizeof(buf), ctl, va);
98         va_end(va);
99         _thr_log(buf, len);
100 }
101
102 #else
103
104 static __inline
105 void
106 mutex_log(const char *ctl __unused, ...)
107 {
108 }
109
110 #endif
111
112 #ifdef _PTHREADS_DEBUGGING2
113
114 static void
115 mutex_log2(struct pthread *curthread, struct pthread_mutex *m, int op)
116 {
117         if (curthread) {
118                 if (curthread->tid < 32)
119                         m->m_lastop[curthread->tid] =
120                                 (__sys_getpid() << 16) | op;
121         } else {
122                         m->m_lastop[0] =
123                                 (__sys_getpid() << 16) | op;
124         }
125 }
126
127 #else
128
129 static __inline
130 void
131 mutex_log2(struct pthread *curthread __unused,
132            struct pthread_mutex *m __unused, int op __unused)
133 {
134 }
135
136 #endif
137
138 /*
139  * Prototypes
140  */
141 static int      mutex_self_trylock(pthread_mutex_t);
142 static int      mutex_self_lock(pthread_mutex_t,
143                         const struct timespec *abstime);
144 static int      mutex_unlock_common(pthread_mutex_t *);
145
146 int __pthread_mutex_init(pthread_mutex_t *mutex,
147         const pthread_mutexattr_t *mutex_attr);
148 int __pthread_mutex_trylock(pthread_mutex_t *mutex);
149 int __pthread_mutex_lock(pthread_mutex_t *mutex);
150 int __pthread_mutex_timedlock(pthread_mutex_t *mutex,
151         const struct timespec *abs_timeout);
152
153 static int
154 mutex_check_attr(const struct pthread_mutex_attr *attr)
155 {
156         if (attr->m_type < PTHREAD_MUTEX_ERRORCHECK ||
157             attr->m_type >= PTHREAD_MUTEX_TYPE_MAX)
158                 return (EINVAL);
159         if (attr->m_protocol < PTHREAD_PRIO_NONE ||
160             attr->m_protocol > PTHREAD_PRIO_PROTECT)
161                 return (EINVAL);
162         return (0);
163 }
164
165 static void
166 mutex_init_body(struct pthread_mutex *pmutex,
167     const struct pthread_mutex_attr *attr, int private)
168 {
169         _thr_umtx_init(&pmutex->m_lock);
170         pmutex->m_type = attr->m_type;
171         pmutex->m_protocol = attr->m_protocol;
172         TAILQ_INIT(&pmutex->m_queue);
173         mutex_log2(tls_get_curthread(), pmutex, 32);
174         pmutex->m_owner = NULL;
175         pmutex->m_flags = attr->m_flags | MUTEX_FLAGS_INITED;
176         if (private)
177                 pmutex->m_flags |= MUTEX_FLAGS_PRIVATE;
178         pmutex->m_count = 0;
179         pmutex->m_refcount = 0;
180         if (attr->m_protocol == PTHREAD_PRIO_PROTECT)
181                 pmutex->m_prio = attr->m_ceiling;
182         else
183                 pmutex->m_prio = -1;
184         pmutex->m_saved_prio = 0;
185         MUTEX_INIT_LINK(pmutex);
186 }
187
188 static int
189 mutex_init(pthread_mutex_t *mutex,
190     const pthread_mutexattr_t *mutex_attr, int private)
191 {
192         const struct pthread_mutex_attr *attr;
193         struct pthread_mutex *pmutex;
194         int error;
195
196         if (mutex_attr == NULL) {
197                 attr = &_pthread_mutexattr_default;
198         } else {
199                 attr = *mutex_attr;
200                 error = mutex_check_attr(attr);
201                 if (error != 0)
202                         return (error);
203         }
204
205         pmutex = __malloc(sizeof(struct pthread_mutex));
206         if (pmutex == NULL)
207                 return (ENOMEM);
208         mutex_init_body(pmutex, attr, private);
209         *mutex = pmutex;
210         return (0);
211 }
212
213 static int
214 init_static(struct pthread *thread, pthread_mutex_t *mutex)
215 {
216         int ret;
217
218         THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
219
220         if (*mutex == NULL)
221                 ret = mutex_init(mutex, NULL, 0);
222         else
223                 ret = 0;
224         THR_LOCK_RELEASE(thread, &_mutex_static_lock);
225
226         return (ret);
227 }
228
229 static int
230 init_static_private(struct pthread *thread, pthread_mutex_t *mutex)
231 {
232         int ret;
233
234         THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
235
236         if (*mutex == NULL)
237                 ret = mutex_init(mutex, NULL, 1);
238         else
239                 ret = 0;
240
241         THR_LOCK_RELEASE(thread, &_mutex_static_lock);
242
243         return (ret);
244 }
245
246 int
247 _pthread_mutex_init(pthread_mutex_t * __restrict mutex,
248     const pthread_mutexattr_t * __restrict mutex_attr)
249 {
250         return mutex_init(mutex, mutex_attr, 1);
251 }
252
253 int
254 __pthread_mutex_init(pthread_mutex_t *mutex,
255     const pthread_mutexattr_t *mutex_attr)
256 {
257         return mutex_init(mutex, mutex_attr, 0);
258 }
259
260 #if 0
261 int
262 _mutex_reinit(pthread_mutex_t *mutexp)
263 {
264         pthread_mutex_t mutex = *mutexp;
265
266         _thr_umtx_init(&mutex->m_lock);
267         TAILQ_INIT(&mutex->m_queue);
268         MUTEX_INIT_LINK(mutex);
269         mutex_log2(tls_get_curthread(), mutex, 33);
270         mutex->m_owner = NULL;
271         mutex->m_count = 0;
272         mutex->m_refcount = 0;
273         mutex->m_prio = 0;
274         mutex->m_saved_prio = 0;
275
276         return (0);
277 }
278 #endif
279
280 void
281 _mutex_fork(struct pthread *curthread)
282 {
283         struct pthread_mutex *m;
284
285         TAILQ_FOREACH(m, &curthread->mutexq, m_qe)
286                 m->m_lock = UMTX_LOCKED;
287 }
288
289 int
290 _pthread_mutex_destroy(pthread_mutex_t *mutex)
291 {
292         struct pthread *curthread = tls_get_curthread();
293         pthread_mutex_t m;
294         int ret = 0;
295
296         if (mutex == NULL) {
297                 ret = EINVAL;
298         } else if (*mutex == NULL) {
299                 ret = 0;
300         } else {
301                 /*
302                  * Try to lock the mutex structure, we only need to
303                  * try once, if failed, the mutex is in use.
304                  */
305                 ret = THR_UMTX_TRYLOCK_PERSIST(curthread, &(*mutex)->m_lock);
306                 if (ret)
307                         return (ret);
308
309                 /*
310                  * Check mutex other fields to see if this mutex is
311                  * in use. Mostly for prority mutex types, or there
312                  * are condition variables referencing it.
313                  */
314                 if (((*mutex)->m_owner != NULL) ||
315                     (TAILQ_FIRST(&(*mutex)->m_queue) != NULL) ||
316                     ((*mutex)->m_refcount != 0)) {
317                         THR_UMTX_UNLOCK_PERSIST(curthread, &(*mutex)->m_lock);
318                         ret = EBUSY;
319                 } else {
320                         /*
321                          * Save a pointer to the mutex so it can be free'd
322                          * and set the caller's pointer to NULL:
323                          */
324                         m = *mutex;
325                         *mutex = NULL;
326
327                         /* Unlock the mutex structure: */
328                         THR_UMTX_UNLOCK_PERSIST(curthread, &m->m_lock);
329
330                         /*
331                          * Free the memory allocated for the mutex
332                          * structure:
333                          */
334                         MUTEX_ASSERT_NOT_OWNED(m);
335                         MUTEX_DESTROY(m);
336                 }
337         }
338
339         /* Return the completion status: */
340         return (ret);
341 }
342
343 static int
344 mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
345 {
346         struct pthread_mutex *m;
347         int ret;
348
349         m = *mutex;
350         mutex_log("mutex_lock_trylock_common %p\n", m);
351         ret = THR_UMTX_TRYLOCK_PERSIST(curthread, &m->m_lock);
352         if (ret == 0) {
353                 mutex_log2(curthread, m, 1);
354                 m->m_owner = curthread;
355                 /* Add to the list of owned mutexes: */
356                 MUTEX_ASSERT_NOT_OWNED(m);
357                 TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
358         } else if (m->m_owner == curthread) {
359                 mutex_log2(curthread, m, 2);
360                 ret = mutex_self_trylock(m);
361         } /* else {} */
362         mutex_log("mutex_lock_trylock_common %p (returns %d)\n", m, ret);
363
364         return (ret);
365 }
366
367 int
368 __pthread_mutex_trylock(pthread_mutex_t *m)
369 {
370         struct pthread *curthread = tls_get_curthread();
371         int ret;
372
373         if (__predict_false(m == NULL))
374                 return(EINVAL);
375         /*
376          * If the mutex is statically initialized, perform the dynamic
377          * initialization:
378          */
379         if (__predict_false(*m == NULL)) {
380                 ret = init_static(curthread, m);
381                 if (__predict_false(ret != 0))
382                         return (ret);
383         }
384         return (mutex_trylock_common(curthread, m));
385 }
386
387 int
388 _pthread_mutex_trylock(pthread_mutex_t *m)
389 {
390         struct pthread  *curthread = tls_get_curthread();
391         int     ret = 0;
392
393         /*
394          * If the mutex is statically initialized, perform the dynamic
395          * initialization marking the mutex private (delete safe):
396          */
397         if (__predict_false(*m == NULL)) {
398                 ret = init_static_private(curthread, m);
399                 if (__predict_false(ret != 0))
400                         return (ret);
401         }
402         return (mutex_trylock_common(curthread, m));
403 }
404
405 static int
406 mutex_lock_common(struct pthread *curthread, pthread_mutex_t *mutex,
407         const struct timespec * abstime)
408 {
409         struct  timespec ts, ts2;
410         struct  pthread_mutex *m;
411         int     ret = 0;
412
413         m = *mutex;
414         mutex_log("mutex_lock_common %p\n", m);
415         ret = THR_UMTX_TRYLOCK_PERSIST(curthread, &m->m_lock);
416         if (ret == 0) {
417                 mutex_log2(curthread, m, 3);
418                 m->m_owner = curthread;
419                 /* Add to the list of owned mutexes: */
420                 MUTEX_ASSERT_NOT_OWNED(m);
421                 TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
422         } else if (m->m_owner == curthread) {
423                 ret = mutex_self_lock(m, abstime);
424         } else {
425                 if (abstime == NULL) {
426                         THR_UMTX_LOCK_PERSIST(curthread, &m->m_lock);
427                         ret = 0;
428                 } else if (__predict_false(
429                         abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
430                         abstime->tv_nsec >= 1000000000)) {
431                                 ret = EINVAL;
432                 } else {
433                         clock_gettime(CLOCK_REALTIME, &ts);
434                         timespecsub(abstime, &ts, &ts2);
435                         ret = THR_UMTX_TIMEDLOCK_PERSIST(curthread,
436                                                          &m->m_lock, &ts2);
437                 }
438                 if (ret == 0) {
439                         mutex_log2(curthread, m, 4);
440                         m->m_owner = curthread;
441                         /* Add to the list of owned mutexes: */
442                         MUTEX_ASSERT_NOT_OWNED(m);
443                         TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
444                 }
445         }
446         mutex_log("mutex_lock_common %p (returns %d) lock %d,%d\n",
447                   m, ret, m->m_lock, m->m_count);
448         return (ret);
449 }
450
451 int
452 __pthread_mutex_lock(pthread_mutex_t *m)
453 {
454         struct pthread *curthread;
455         int     ret;
456
457         if (__predict_false(m == NULL))
458                 return(EINVAL);
459
460         /*
461          * If the mutex is statically initialized, perform the dynamic
462          * initialization:
463          */
464         curthread = tls_get_curthread();
465         if (__predict_false(*m == NULL)) {
466                 ret = init_static(curthread, m);
467                 if (__predict_false(ret))
468                         return (ret);
469         }
470         return (mutex_lock_common(curthread, m, NULL));
471 }
472
473 int
474 _pthread_mutex_lock(pthread_mutex_t *m)
475 {
476         struct pthread *curthread;
477         int     ret;
478
479         _thr_check_init();
480
481         if (__predict_false(m == NULL))
482                 return(EINVAL);
483
484         /*
485          * If the mutex is statically initialized, perform the dynamic
486          * initialization marking it private (delete safe):
487          */
488         curthread = tls_get_curthread();
489         if (__predict_false(*m == NULL)) {
490                 ret = init_static_private(curthread, m);
491                 if (__predict_false(ret))
492                         return (ret);
493         }
494         return (mutex_lock_common(curthread, m, NULL));
495 }
496
497 int
498 __pthread_mutex_timedlock(pthread_mutex_t * __restrict m,
499     const struct timespec * __restrict abs_timeout)
500 {
501         struct pthread *curthread;
502         int     ret;
503
504         _thr_check_init();
505
506         if (__predict_false(m == NULL))
507                 return(EINVAL);
508
509         /*
510          * If the mutex is statically initialized, perform the dynamic
511          * initialization:
512          */
513         curthread = tls_get_curthread();
514         if (__predict_false(*m == NULL)) {
515                 ret = init_static(curthread, m);
516                 if (__predict_false(ret))
517                         return (ret);
518         }
519         return (mutex_lock_common(curthread, m, abs_timeout));
520 }
521
522 int
523 _pthread_mutex_timedlock(pthread_mutex_t *m,
524         const struct timespec *abs_timeout)
525 {
526         struct pthread *curthread;
527         int     ret;
528
529         if (__predict_false(m == NULL))
530                 return(EINVAL);
531
532         curthread = tls_get_curthread();
533
534         /*
535          * If the mutex is statically initialized, perform the dynamic
536          * initialization marking it private (delete safe):
537          */
538         if (__predict_false(*m == NULL)) {
539                 ret = init_static_private(curthread, m);
540                 if (__predict_false(ret))
541                         return (ret);
542         }
543         return (mutex_lock_common(curthread, m, abs_timeout));
544 }
545
546 int
547 _pthread_mutex_unlock(pthread_mutex_t *m)
548 {
549         if (__predict_false(m == NULL))
550                 return(EINVAL);
551         return (mutex_unlock_common(m));
552 }
553
554 static int
555 mutex_self_trylock(pthread_mutex_t m)
556 {
557         int     ret;
558
559         switch (m->m_type) {
560         /* case PTHREAD_MUTEX_DEFAULT: */
561         case PTHREAD_MUTEX_ERRORCHECK:
562         case PTHREAD_MUTEX_NORMAL:
563                 ret = EBUSY;
564                 break;
565
566         case PTHREAD_MUTEX_RECURSIVE:
567                 /* Increment the lock count: */
568                 if (m->m_count + 1 > 0) {
569                         m->m_count++;
570                         ret = 0;
571                 } else
572                         ret = EAGAIN;
573                 break;
574
575         default:
576                 /* Trap invalid mutex types; */
577                 ret = EINVAL;
578         }
579
580         return (ret);
581 }
582
583 static int
584 mutex_self_lock(pthread_mutex_t m, const struct timespec *abstime)
585 {
586         struct timespec ts1, ts2;
587         int ret;
588
589         switch (m->m_type) {
590         /* case PTHREAD_MUTEX_DEFAULT: */
591         case PTHREAD_MUTEX_ERRORCHECK:
592                 if (abstime) {
593                         clock_gettime(CLOCK_REALTIME, &ts1);
594                         timespecsub(abstime, &ts1, &ts2);
595                         __sys_nanosleep(&ts2, NULL);
596                         ret = ETIMEDOUT;
597                 } else {
598                         /*
599                          * POSIX specifies that mutexes should return
600                          * EDEADLK if a recursive lock is detected.
601                          */
602                         ret = EDEADLK;
603                 }
604                 break;
605
606         case PTHREAD_MUTEX_NORMAL:
607                 /*
608                  * What SS2 define as a 'normal' mutex.  Intentionally
609                  * deadlock on attempts to get a lock you already own.
610                  */
611                 ret = 0;
612                 if (abstime) {
613                         clock_gettime(CLOCK_REALTIME, &ts1);
614                         timespecsub(abstime, &ts1, &ts2);
615                         __sys_nanosleep(&ts2, NULL);
616                         ret = ETIMEDOUT;
617                 } else {
618                         ts1.tv_sec = 30;
619                         ts1.tv_nsec = 0;
620                         for (;;)
621                                 __sys_nanosleep(&ts1, NULL);
622                 }
623                 break;
624
625         case PTHREAD_MUTEX_RECURSIVE:
626                 /* Increment the lock count: */
627                 if (m->m_count + 1 > 0) {
628                         m->m_count++;
629                         ret = 0;
630                 } else
631                         ret = EAGAIN;
632                 break;
633
634         default:
635                 /* Trap invalid mutex types; */
636                 ret = EINVAL;
637         }
638
639         return (ret);
640 }
641
642 static int
643 mutex_unlock_common(pthread_mutex_t *mutex)
644 {
645         struct pthread *curthread = tls_get_curthread();
646         struct pthread_mutex *m;
647
648         if (__predict_false((m = *mutex) == NULL)) {
649                 mutex_log2(curthread, m, 252);
650                 return (EINVAL);
651         }
652         mutex_log("mutex_unlock_common %p\n", m);
653         if (__predict_false(m->m_owner != curthread)) {
654                 mutex_log("mutex_unlock_common %p (failedA)\n", m);
655                 mutex_log2(curthread, m, 253);
656                 return (EPERM);
657         }
658
659         if (__predict_false(m->m_type == PTHREAD_MUTEX_RECURSIVE &&
660                             m->m_count > 0)) {
661                 m->m_count--;
662                 mutex_log("mutex_unlock_common %p (returns 0, partial)\n", m);
663                 mutex_log2(curthread, m, 254);
664         } else {
665                 /*
666                  * Clear the count in case this is a recursive mutex.
667                  */
668                 m->m_count = 0;
669                 m->m_owner = NULL;
670                 /* Remove the mutex from the threads queue. */
671                 MUTEX_ASSERT_IS_OWNED(m);
672                 TAILQ_REMOVE(&curthread->mutexq, m, m_qe);
673                 mutex_log2(tls_get_curthread(), m, 35);
674                 MUTEX_INIT_LINK(m);
675                 mutex_log2(tls_get_curthread(), m, 36);
676                 /*
677                  * Hand off the mutex to the next waiting thread.
678                  */
679                 mutex_log("mutex_unlock_common %p (returns 0) lock %d\n",
680                           m, m->m_lock);
681                 THR_UMTX_UNLOCK_PERSIST(curthread, &m->m_lock);
682                 mutex_log2(tls_get_curthread(), m, 37);
683                 mutex_log2(curthread, m, 255);
684         }
685         return (0);
686 }
687
688 int
689 _pthread_mutex_getprioceiling(const pthread_mutex_t * __restrict mutex,
690     int * __restrict prioceiling)
691 {
692         if ((mutex == NULL) || (*mutex == NULL))
693                 return (EINVAL);
694         if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
695                 return (EINVAL);
696         *prioceiling = (*mutex)->m_prio;
697         return (0);
698 }
699
700 int
701 _pthread_mutex_setprioceiling(pthread_mutex_t * __restrict mutex,
702     int prioceiling, int * __restrict old_ceiling)
703 {
704         int ret = 0;
705         int tmp;
706
707         if ((mutex == NULL) || (*mutex == NULL))
708                 ret = EINVAL;
709         else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
710                 ret = EINVAL;
711         else if ((ret = _pthread_mutex_lock(mutex)) == 0) {
712                 tmp = (*mutex)->m_prio;
713                 (*mutex)->m_prio = prioceiling;
714                 ret = _pthread_mutex_unlock(mutex);
715                 *old_ceiling = tmp;
716         }
717         return(ret);
718 }
719
720 int
721 _mutex_cv_lock(pthread_mutex_t *m, int count)
722 {
723         int     ret;
724
725         if ((ret = _pthread_mutex_lock(m)) == 0) {
726                 (*m)->m_refcount--;
727                 (*m)->m_count += count;
728         }
729         return (ret);
730 }
731
732 int
733 _mutex_cv_unlock(pthread_mutex_t *mutex, int *count)
734 {
735         struct pthread *curthread = tls_get_curthread();
736         struct pthread_mutex *m;
737
738         if (__predict_false(mutex == NULL))
739                 return (EINVAL);
740         if (__predict_false((m = *mutex) == NULL))
741                 return (EINVAL);
742         if (__predict_false(m->m_owner != curthread))
743                 return (EPERM);
744
745         *count = m->m_count;
746         m->m_count = 0;
747         m->m_refcount++;
748         mutex_log2(tls_get_curthread(), m, 45);
749         m->m_owner = NULL;
750         /* Remove the mutex from the threads queue. */
751         MUTEX_ASSERT_IS_OWNED(m);
752         TAILQ_REMOVE(&curthread->mutexq, m, m_qe);
753         MUTEX_INIT_LINK(m);
754         THR_UMTX_UNLOCK_PERSIST(curthread, &m->m_lock);
755         mutex_log2(curthread, m, 250);
756         return (0);
757 }
758
759 void
760 _mutex_unlock_private(pthread_t pthread)
761 {
762         struct pthread_mutex    *m, *m_next;
763
764         for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) {
765                 m_next = TAILQ_NEXT(m, m_qe);
766                 if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0)
767                         _pthread_mutex_unlock(&m);
768         }
769 }
770
771 __strong_reference(__pthread_mutex_init, pthread_mutex_init);
772 __strong_reference(__pthread_mutex_lock, pthread_mutex_lock);
773 __strong_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
774 __strong_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
775
776 /* Single underscore versions provided for libc internal usage: */
777 /* No difference between libc and application usage of these: */
778 __strong_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
779 __strong_reference(_pthread_mutex_unlock, pthread_mutex_unlock);
780 __strong_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling);
781 __strong_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling);