pthread: General pre-cleanup (style, typos etc)
[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 #if defined(_PTHREADS_INVARIANTS)
47 #define MUTEX_INIT_LINK(m)              do {            \
48         (m)->m_qe.tqe_prev = NULL;                      \
49         (m)->m_qe.tqe_next = NULL;                      \
50 } while (0)
51 #define MUTEX_ASSERT_IS_OWNED(m)        do {            \
52         if ((m)->m_qe.tqe_prev == NULL)                 \
53                 PANIC("mutex is not on list");          \
54 } while (0)
55 #define MUTEX_ASSERT_NOT_OWNED(m)       do {            \
56         if (((m)->m_qe.tqe_prev != NULL) ||             \
57             ((m)->m_qe.tqe_next != NULL))               \
58                 PANIC("mutex is on list");              \
59 } while (0)
60 #define THR_ASSERT_NOT_IN_SYNCQ(thr)    do {            \
61         THR_ASSERT(((thr)->sflags & THR_FLAGS_IN_SYNCQ) == 0, \
62             "thread in syncq when it shouldn't be.");   \
63 } while (0);
64 #else
65 #define MUTEX_INIT_LINK(m)
66 #define MUTEX_ASSERT_IS_OWNED(m)
67 #define MUTEX_ASSERT_NOT_OWNED(m)
68 #define THR_ASSERT_NOT_IN_SYNCQ(thr)
69 #endif
70
71 #define THR_IN_MUTEXQ(thr)      (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
72 #define MUTEX_DESTROY(m) do {           \
73         free(m);                        \
74 } while (0)
75
76 umtx_t  _mutex_static_lock;
77
78 /*
79  * Prototypes
80  */
81 static int      mutex_self_trylock(pthread_mutex_t);
82 static int      mutex_self_lock(pthread_mutex_t,
83                         const struct timespec *abstime);
84 static int      mutex_unlock_common(pthread_mutex_t *);
85
86 int __pthread_mutex_init(pthread_mutex_t *mutex,
87         const pthread_mutexattr_t *mutex_attr);
88 int __pthread_mutex_trylock(pthread_mutex_t *mutex);
89 int __pthread_mutex_lock(pthread_mutex_t *mutex);
90 int __pthread_mutex_timedlock(pthread_mutex_t *mutex,
91         const struct timespec *abs_timeout);
92
93 static int
94 mutex_init(pthread_mutex_t *mutex,
95     const pthread_mutexattr_t *mutex_attr, int private)
96 {
97         const struct pthread_mutex_attr *attr;
98         struct pthread_mutex *pmutex;
99
100         if (mutex_attr == NULL) {
101                 attr = &_pthread_mutexattr_default;
102         } else {
103                 attr = *mutex_attr;
104                 if (attr->m_type < PTHREAD_MUTEX_ERRORCHECK ||
105                     attr->m_type >= PTHREAD_MUTEX_TYPE_MAX)
106                         return (EINVAL);
107                 if (attr->m_protocol < PTHREAD_PRIO_NONE ||
108                     attr->m_protocol > PTHREAD_PRIO_PROTECT)
109                         return (EINVAL);
110         }
111
112         if ((pmutex = (pthread_mutex_t)
113                 malloc(sizeof(struct pthread_mutex))) == NULL)
114                 return (ENOMEM);
115
116         _thr_umtx_init(&pmutex->m_lock);
117         pmutex->m_type = attr->m_type;
118         pmutex->m_protocol = attr->m_protocol;
119         TAILQ_INIT(&pmutex->m_queue);
120         pmutex->m_owner = NULL;
121         pmutex->m_flags = attr->m_flags | MUTEX_FLAGS_INITED;
122         if (private)
123                 pmutex->m_flags |= MUTEX_FLAGS_PRIVATE;
124         pmutex->m_count = 0;
125         pmutex->m_refcount = 0;
126         if (attr->m_protocol == PTHREAD_PRIO_PROTECT)
127                 pmutex->m_prio = attr->m_ceiling;
128         else
129                 pmutex->m_prio = -1;
130         pmutex->m_saved_prio = 0;
131         MUTEX_INIT_LINK(pmutex);
132         *mutex = pmutex;
133         return (0);
134 }
135
136 static int
137 init_static(struct pthread *thread, pthread_mutex_t *mutex)
138 {
139         int ret;
140
141         THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
142
143         if (*mutex == NULL)
144                 ret = mutex_init(mutex, NULL, 0);
145         else
146                 ret = 0;
147
148         THR_LOCK_RELEASE(thread, &_mutex_static_lock);
149
150         return (ret);
151 }
152
153 static int
154 init_static_private(struct pthread *thread, pthread_mutex_t *mutex)
155 {
156         int ret;
157
158         THR_LOCK_ACQUIRE(thread, &_mutex_static_lock);
159
160         if (*mutex == NULL)
161                 ret = mutex_init(mutex, NULL, 1);
162         else
163                 ret = 0;
164
165         THR_LOCK_RELEASE(thread, &_mutex_static_lock);
166
167         return (ret);
168 }
169
170 int
171 _pthread_mutex_init(pthread_mutex_t *mutex,
172     const pthread_mutexattr_t *mutex_attr)
173 {
174         return mutex_init(mutex, mutex_attr, 1);
175 }
176
177 int
178 __pthread_mutex_init(pthread_mutex_t *mutex,
179     const pthread_mutexattr_t *mutex_attr)
180 {
181         return mutex_init(mutex, mutex_attr, 0);
182 }
183
184 int
185 _mutex_reinit(pthread_mutex_t *mutex)
186 {
187         _thr_umtx_init(&(*mutex)->m_lock);
188         TAILQ_INIT(&(*mutex)->m_queue);
189         MUTEX_INIT_LINK(*mutex);
190         (*mutex)->m_owner = NULL;
191         (*mutex)->m_count = 0;
192         (*mutex)->m_refcount = 0;
193         (*mutex)->m_prio = 0;
194         (*mutex)->m_saved_prio = 0;
195         return (0);
196 }
197
198 void
199 _mutex_fork(struct pthread *curthread)
200 {
201         struct pthread_mutex *m;
202
203         TAILQ_FOREACH(m, &curthread->mutexq, m_qe)
204                 m->m_lock = UMTX_LOCKED;
205 }
206
207 int
208 _pthread_mutex_destroy(pthread_mutex_t *mutex)
209 {
210         struct pthread *curthread = tls_get_curthread();
211         pthread_mutex_t m;
212         int ret = 0;
213
214         if (mutex == NULL)
215                 ret = EINVAL;
216         else if (*mutex == NULL)
217                 ret = 0;
218         else {
219                 /*
220                  * Try to lock the mutex structure, we only need to
221                  * try once, if failed, the mutex is in used.
222                  */
223                 ret = THR_UMTX_TRYLOCK(curthread, &(*mutex)->m_lock);
224                 if (ret)
225                         return (ret);
226
227                 /*
228                  * Check mutex other fields to see if this mutex is
229                  * in use. Mostly for prority mutex types, or there
230                  * are condition variables referencing it.
231                  */
232                 if (((*mutex)->m_owner != NULL) ||
233                     (TAILQ_FIRST(&(*mutex)->m_queue) != NULL) ||
234                     ((*mutex)->m_refcount != 0)) {
235                         THR_UMTX_UNLOCK(curthread, &(*mutex)->m_lock);
236                         ret = EBUSY;
237                 } else {
238                         /*
239                          * Save a pointer to the mutex so it can be free'd
240                          * and set the caller's pointer to NULL:
241                          */
242                         m = *mutex;
243                         *mutex = NULL;
244
245                         /* Unlock the mutex structure: */
246                         THR_UMTX_UNLOCK(curthread, &m->m_lock);
247
248                         /*
249                          * Free the memory allocated for the mutex
250                          * structure:
251                          */
252                         MUTEX_ASSERT_NOT_OWNED(m);
253                         MUTEX_DESTROY(m);
254                 }
255         }
256
257         /* Return the completion status: */
258         return (ret);
259 }
260
261 static int
262 mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
263 {
264         struct pthread_mutex *m;
265         int ret;
266
267         m = *mutex;
268         ret = THR_UMTX_TRYLOCK(curthread, &m->m_lock);
269         if (ret == 0) {
270                 m->m_owner = curthread;
271                 /* Add to the list of owned mutexes: */
272                 MUTEX_ASSERT_NOT_OWNED(m);
273                 TAILQ_INSERT_TAIL(&curthread->mutexq,
274                     m, m_qe);
275         } else if (m->m_owner == curthread) {
276                 ret = mutex_self_trylock(m);
277         } /* else {} */
278
279         return (ret);
280 }
281
282 int
283 __pthread_mutex_trylock(pthread_mutex_t *m)
284 {
285         struct pthread *curthread = tls_get_curthread();
286         int ret;
287
288         if (__predict_false(m == NULL))
289                 return(EINVAL);
290         /*
291          * If the mutex is statically initialized, perform the dynamic
292          * initialization:
293          */
294         if (__predict_false(*m == NULL)) {
295                 ret = init_static(curthread, m);
296                 if (__predict_false(ret != 0))
297                         return (ret);
298         }
299         return (mutex_trylock_common(curthread, m));
300 }
301
302 int
303 _pthread_mutex_trylock(pthread_mutex_t *m)
304 {
305         struct pthread  *curthread = tls_get_curthread();
306         int     ret = 0;
307
308         /*
309          * If the mutex is statically initialized, perform the dynamic
310          * initialization marking the mutex private (delete safe):
311          */
312         if (__predict_false(*m == NULL)) {
313                 ret = init_static_private(curthread, m);
314                 if (__predict_false(ret != 0))
315                         return (ret);
316         }
317         return (mutex_trylock_common(curthread, m));
318 }
319
320 static int
321 mutex_lock_common(struct pthread *curthread, pthread_mutex_t *mutex,
322         const struct timespec * abstime)
323 {
324         struct  timespec ts, ts2;
325         struct  pthread_mutex *m;
326         int     ret = 0;
327
328         m = *mutex;
329         ret = THR_UMTX_TRYLOCK(curthread, &m->m_lock);
330         if (ret == 0) {
331                 m->m_owner = curthread;
332                 /* Add to the list of owned mutexes: */
333                 MUTEX_ASSERT_NOT_OWNED(m);
334                 TAILQ_INSERT_TAIL(&curthread->mutexq,
335                     m, m_qe);
336         } else if (m->m_owner == curthread) {
337                 ret = mutex_self_lock(m, abstime);
338         } else {
339                 if (abstime == NULL) {
340                         THR_UMTX_LOCK(curthread, &m->m_lock);
341                         ret = 0;
342                 } else if (__predict_false(
343                         abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
344                         abstime->tv_nsec >= 1000000000)) {
345                                 ret = EINVAL;
346                 } else {
347                         clock_gettime(CLOCK_REALTIME, &ts);
348                         TIMESPEC_SUB(&ts2, abstime, &ts);
349                         ret = THR_UMTX_TIMEDLOCK(curthread,
350                                 &m->m_lock, &ts2);
351                         /*
352                          * Timed out wait is not restarted if
353                          * it was interrupted, not worth to do it.
354                          */
355                         if (ret == EINTR)
356                                 ret = ETIMEDOUT;
357                 }
358                 if (ret == 0) {
359                         m->m_owner = curthread;
360                         /* Add to the list of owned mutexes: */
361                         MUTEX_ASSERT_NOT_OWNED(m);
362                         TAILQ_INSERT_TAIL(&curthread->mutexq,
363                             m, m_qe);
364                 }
365         }
366         return (ret);
367 }
368
369 int
370 __pthread_mutex_lock(pthread_mutex_t *m)
371 {
372         struct pthread *curthread;
373         int     ret;
374
375         if (__predict_false(m == NULL))
376                 return(EINVAL);
377
378         /*
379          * If the mutex is statically initialized, perform the dynamic
380          * initialization:
381          */
382         curthread = tls_get_curthread();
383         if (__predict_false(*m == NULL)) {
384                 ret = init_static(curthread, m);
385                 if (__predict_false(ret))
386                         return (ret);
387         }
388         return (mutex_lock_common(curthread, m, NULL));
389 }
390
391 int
392 _pthread_mutex_lock(pthread_mutex_t *m)
393 {
394         struct pthread *curthread;
395         int     ret;
396
397         if (__predict_false(m == NULL))
398                 return(EINVAL);
399
400         /*
401          * If the mutex is statically initialized, perform the dynamic
402          * initialization marking it private (delete safe):
403          */
404         curthread = tls_get_curthread();
405         if (__predict_false(*m == NULL)) {
406                 ret = init_static_private(curthread, m);
407                 if (__predict_false(ret))
408                         return (ret);
409         }
410         return (mutex_lock_common(curthread, m, NULL));
411 }
412
413 int
414 __pthread_mutex_timedlock(pthread_mutex_t *m,
415         const struct timespec *abs_timeout)
416 {
417         struct pthread *curthread;
418         int     ret;
419
420         if (__predict_false(m == NULL))
421                 return(EINVAL);
422
423         /*
424          * If the mutex is statically initialized, perform the dynamic
425          * initialization:
426          */
427         curthread = tls_get_curthread();
428         if (__predict_false(*m == NULL)) {
429                 ret = init_static(curthread, m);
430                 if (__predict_false(ret))
431                         return (ret);
432         }
433         return (mutex_lock_common(curthread, m, abs_timeout));
434 }
435
436 int
437 _pthread_mutex_timedlock(pthread_mutex_t *m,
438         const struct timespec *abs_timeout)
439 {
440         struct pthread *curthread;
441         int     ret;
442
443         if (__predict_false(m == NULL))
444                 return(EINVAL);
445
446         curthread = tls_get_curthread();
447
448         /*
449          * If the mutex is statically initialized, perform the dynamic
450          * initialization marking it private (delete safe):
451          */
452         if (__predict_false(*m == NULL)) {
453                 ret = init_static_private(curthread, m);
454                 if (__predict_false(ret))
455                         return (ret);
456         }
457         return (mutex_lock_common(curthread, m, abs_timeout));
458 }
459
460 int
461 _pthread_mutex_unlock(pthread_mutex_t *m)
462 {
463         if (__predict_false(m == NULL))
464                 return(EINVAL);
465         return (mutex_unlock_common(m));
466 }
467
468 static int
469 mutex_self_trylock(pthread_mutex_t m)
470 {
471         int     ret;
472
473         switch (m->m_type) {
474         /* case PTHREAD_MUTEX_DEFAULT: */
475         case PTHREAD_MUTEX_ERRORCHECK:
476         case PTHREAD_MUTEX_NORMAL:
477                 ret = EBUSY;
478                 break;
479
480         case PTHREAD_MUTEX_RECURSIVE:
481                 /* Increment the lock count: */
482                 if (m->m_count + 1 > 0) {
483                         m->m_count++;
484                         ret = 0;
485                 } else
486                         ret = EAGAIN;
487                 break;
488
489         default:
490                 /* Trap invalid mutex types; */
491                 ret = EINVAL;
492         }
493
494         return (ret);
495 }
496
497 static int
498 mutex_self_lock(pthread_mutex_t m, const struct timespec *abstime)
499 {
500         struct timespec ts1, ts2;
501         int ret;
502
503         switch (m->m_type) {
504         /* case PTHREAD_MUTEX_DEFAULT: */
505         case PTHREAD_MUTEX_ERRORCHECK:
506                 if (abstime) {
507                         clock_gettime(CLOCK_REALTIME, &ts1);
508                         TIMESPEC_SUB(&ts2, abstime, &ts1);
509                         __sys_nanosleep(&ts2, NULL);
510                         ret = ETIMEDOUT;
511                 } else {
512                         /*
513                          * POSIX specifies that mutexes should return
514                          * EDEADLK if a recursive lock is detected.
515                          */
516                         ret = EDEADLK;
517                 }
518                 break;
519
520         case PTHREAD_MUTEX_NORMAL:
521                 /*
522                  * What SS2 define as a 'normal' mutex.  Intentionally
523                  * deadlock on attempts to get a lock you already own.
524                  */
525                 ret = 0;
526                 if (abstime) {
527                         clock_gettime(CLOCK_REALTIME, &ts1);
528                         TIMESPEC_SUB(&ts2, abstime, &ts1);
529                         __sys_nanosleep(&ts2, NULL);
530                         ret = ETIMEDOUT;
531                 } else {
532                         ts1.tv_sec = 30;
533                         ts1.tv_nsec = 0;
534                         for (;;)
535                                 __sys_nanosleep(&ts1, NULL);
536                 }
537                 break;
538
539         case PTHREAD_MUTEX_RECURSIVE:
540                 /* Increment the lock count: */
541                 if (m->m_count + 1 > 0) {
542                         m->m_count++;
543                         ret = 0;
544                 } else
545                         ret = EAGAIN;
546                 break;
547
548         default:
549                 /* Trap invalid mutex types; */
550                 ret = EINVAL;
551         }
552
553         return (ret);
554 }
555
556 static int
557 mutex_unlock_common(pthread_mutex_t *mutex)
558 {
559         struct pthread *curthread = tls_get_curthread();
560         struct pthread_mutex *m;
561
562         if (__predict_false((m = *mutex)== NULL))
563                 return (EINVAL);
564         if (__predict_false(m->m_owner != curthread))
565                 return (EPERM);
566
567         if (__predict_false(
568                 m->m_type == PTHREAD_MUTEX_RECURSIVE &&
569                 m->m_count > 0)) {
570                 m->m_count--;
571         } else {
572                 /*
573                  * Clear the count in case this is a recursive mutex.
574                  */
575                 m->m_count = 0;
576                 m->m_owner = NULL;
577                 /* Remove the mutex from the threads queue. */
578                 MUTEX_ASSERT_IS_OWNED(m);
579                 TAILQ_REMOVE(&curthread->mutexq, m, m_qe);
580                 MUTEX_INIT_LINK(m);
581                 /*
582                  * Hand off the mutex to the next waiting thread.
583                  */
584                 THR_UMTX_UNLOCK(curthread, &m->m_lock);
585         }
586         return (0);
587 }
588
589 int
590 _mutex_cv_lock(pthread_mutex_t *m, int count)
591 {
592         int     ret;
593
594         if ((ret = _pthread_mutex_lock(m)) == 0) {
595                 (*m)->m_refcount--;
596                 (*m)->m_count += count;
597         }
598         return (ret);
599 }
600
601 int
602 _mutex_cv_unlock(pthread_mutex_t *mutex, int *count)
603 {
604         struct pthread *curthread = tls_get_curthread();
605         struct pthread_mutex *m;
606
607         if (__predict_false(mutex == NULL))
608                 return (EINVAL);
609         if (__predict_false((m = *mutex) == NULL))
610                 return (EINVAL);
611         if (__predict_false(m->m_owner != curthread))
612                 return (EPERM);
613
614         *count = m->m_count;
615         m->m_count = 0;
616         m->m_refcount++;
617         m->m_owner = NULL;
618         /* Remove the mutex from the threads queue. */
619         MUTEX_ASSERT_IS_OWNED(m);
620         TAILQ_REMOVE(&curthread->mutexq, m, m_qe);
621         MUTEX_INIT_LINK(m);
622         THR_UMTX_UNLOCK(curthread, &m->m_lock);
623         return (0);
624 }
625
626 void
627 _mutex_unlock_private(pthread_t pthread)
628 {
629         struct pthread_mutex    *m, *m_next;
630
631         for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) {
632                 m_next = TAILQ_NEXT(m, m_qe);
633                 if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0)
634                         _pthread_mutex_unlock(&m);
635         }
636 }
637
638 __strong_reference(__pthread_mutex_init, pthread_mutex_init);
639 __strong_reference(__pthread_mutex_lock, pthread_mutex_lock);
640 __strong_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
641 __strong_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
642
643 /* Single underscore versions provided for libc internal usage: */
644 /* No difference between libc and application usage of these: */
645 __strong_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
646 __strong_reference(_pthread_mutex_unlock, pthread_mutex_unlock);