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 *****************************************************************************/
27 #include <vlc_common.h>
29 /*** Global locks ***/
31 void vlc_global_mutex (unsigned n, bool acquire)
33 static vlc_mutex_t locks[] = {
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;
47 vlc_mutex_lock (lock);
49 vlc_mutex_unlock (lock);
52 #ifdef LIBVLC_NEED_RWLOCK
53 /*** Generic read/write locks ***/
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.
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);
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);
92 if (unlikely(lock->state >= READER_MASK))
93 abort (); /* An overflow is certainly a recursion bug. */
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);
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);
117 assert (lock->state == WRITER_BIT);
118 /* Let reader and writer compete. OS scheduler decides who wins. */
120 vlc_cond_broadcast (&lock->wait);
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 ***/
138 void vlc_sem_init (vlc_sem_t *sem, unsigned value)
140 vlc_mutex_init (&sem->lock);
141 vlc_cond_init (&sem->wait);
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)
155 vlc_mutex_lock (&sem->lock);
156 if (likely(sem->value != UINT_MAX))
160 vlc_mutex_unlock (&sem->lock);
161 vlc_cond_signal (&sem->wait);
166 void vlc_sem_wait (vlc_sem_t *sem)
168 vlc_mutex_lock (&sem->lock);
169 mutex_cleanup_push (&sem->lock);
171 vlc_cond_wait (&sem->wait, &sem->lock);
175 #endif /* LIBVLC_NEED_SEMAPHORE */