dvbpsi: add sys/types.h as appropriate
[vlc.git] / src / misc / threads.c
blob01e1d976d0cedbe13e9de81e1d840d6bbd093429
1 /*****************************************************************************
2 * threads.c: LibVLC generic thread support
3 *****************************************************************************
4 * Copyright (C) 2009-2012 RĂ©mi Denis-Courmont
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include <assert.h>
27 #include <vlc_common.h>
29 /*** Global locks ***/
31 void vlc_global_mutex (unsigned n, bool acquire)
33 static vlc_mutex_t locks[] = {
34 VLC_STATIC_MUTEX,
35 VLC_STATIC_MUTEX,
36 VLC_STATIC_MUTEX,
37 VLC_STATIC_MUTEX,
38 VLC_STATIC_MUTEX,
39 VLC_STATIC_MUTEX,
41 static_assert (VLC_MAX_MUTEX == (sizeof (locks) / sizeof (locks[0])),
42 "Wrong number of global mutexes");
43 assert (n < (sizeof (locks) / sizeof (locks[0])));
45 vlc_mutex_t *lock = locks + n;
46 if (acquire)
47 vlc_mutex_lock (lock);
48 else
49 vlc_mutex_unlock (lock);
52 #ifdef LIBVLC_NEED_RWLOCK
53 /*** Generic read/write locks ***/
54 #include <stdlib.h>
55 #include <limits.h>
56 /* NOTE:
57 * lock->state is a signed long integer:
58 * - The sign bit is set when the lock is held for writing.
59 * - The other bits code the number of times the lock is held for reading.
60 * Consequently:
61 * - The value is negative if and only if the lock is held for writing.
62 * - The value is zero if and only if the lock is not held at all.
64 #define READER_MASK LONG_MAX
65 #define WRITER_BIT LONG_MIN
67 void vlc_rwlock_init (vlc_rwlock_t *lock)
69 vlc_mutex_init (&lock->mutex);
70 vlc_cond_init (&lock->wait);
71 lock->state = 0;
74 void vlc_rwlock_destroy (vlc_rwlock_t *lock)
76 vlc_cond_destroy (&lock->wait);
77 vlc_mutex_destroy (&lock->mutex);
80 void vlc_rwlock_rdlock (vlc_rwlock_t *lock)
82 vlc_mutex_lock (&lock->mutex);
83 /* Recursive read-locking is allowed.
84 * Ensure that there is no active writer. */
85 while (lock->state < 0)
87 assert (lock->state == WRITER_BIT);
88 mutex_cleanup_push (&lock->mutex);
89 vlc_cond_wait (&lock->wait, &lock->mutex);
90 vlc_cleanup_pop ();
92 if (unlikely(lock->state >= READER_MASK))
93 abort (); /* An overflow is certainly a recursion bug. */
94 lock->state++;
95 vlc_mutex_unlock (&lock->mutex);
98 void vlc_rwlock_wrlock (vlc_rwlock_t *lock)
100 vlc_mutex_lock (&lock->mutex);
101 /* Wait until nobody owns the lock in any way. */
102 while (lock->state != 0)
104 mutex_cleanup_push (&lock->mutex);
105 vlc_cond_wait (&lock->wait, &lock->mutex);
106 vlc_cleanup_pop ();
108 lock->state = WRITER_BIT;
109 vlc_mutex_unlock (&lock->mutex);
112 void vlc_rwlock_unlock (vlc_rwlock_t *lock)
114 vlc_mutex_lock (&lock->mutex);
115 if (lock->state < 0)
116 { /* Write unlock */
117 assert (lock->state == WRITER_BIT);
118 /* Let reader and writer compete. OS scheduler decides who wins. */
119 lock->state = 0;
120 vlc_cond_broadcast (&lock->wait);
122 else
123 { /* Read unlock */
124 assert (lock->state > 0);
125 /* If there are no readers left, wake up one pending writer. */
126 if (--lock->state == 0)
127 vlc_cond_signal (&lock->wait);
129 vlc_mutex_unlock (&lock->mutex);
131 #endif /* LIBVLC_NEED_RWLOCK */
133 #ifdef LIBVLC_NEED_SEMAPHORE
134 /*** Generic semaphores ***/
135 #include <limits.h>
136 #include <errno.h>
138 void vlc_sem_init (vlc_sem_t *sem, unsigned value)
140 vlc_mutex_init (&sem->lock);
141 vlc_cond_init (&sem->wait);
142 sem->value = value;
145 void vlc_sem_destroy (vlc_sem_t *sem)
147 vlc_cond_destroy (&sem->wait);
148 vlc_mutex_destroy (&sem->lock);
151 int vlc_sem_post (vlc_sem_t *sem)
153 int ret = 0;
155 vlc_mutex_lock (&sem->lock);
156 if (likely(sem->value != UINT_MAX))
157 sem->value++;
158 else
159 ret = EOVERFLOW;
160 vlc_mutex_unlock (&sem->lock);
161 vlc_cond_signal (&sem->wait);
163 return ret;
166 void vlc_sem_wait (vlc_sem_t *sem)
168 vlc_mutex_lock (&sem->lock);
169 mutex_cleanup_push (&sem->lock);
170 while (!sem->value)
171 vlc_cond_wait (&sem->wait, &sem->lock);
172 sem->value--;
173 vlc_cleanup_run ();
175 #endif /* LIBVLC_NEED_SEMAPHORE */