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
[] = {
40 static_assert (VLC_MAX_MUTEX
== (sizeof (locks
) / sizeof (locks
[0])),
41 "Wrong number of global mutexes");
42 assert (n
< (sizeof (locks
) / sizeof (locks
[0])));
44 vlc_mutex_t
*lock
= locks
+ n
;
46 vlc_mutex_lock (lock
);
48 vlc_mutex_unlock (lock
);
51 #ifdef LIBVLC_NEED_RWLOCK
52 /*** Generic read/write locks ***/
56 * lock->state is a signed long integer:
57 * - The sign bit is set when the lock is held for writing.
58 * - The other bits code the number of times the lock is held for reading.
60 * - The value is negative if and only if the lock is held for writing.
61 * - The value is zero if and only if the lock is not held at all.
63 #define READER_MASK LONG_MAX
64 #define WRITER_BIT LONG_MIN
66 void vlc_rwlock_init (vlc_rwlock_t
*lock
)
68 vlc_mutex_init (&lock
->mutex
);
69 vlc_cond_init (&lock
->wait
);
73 void vlc_rwlock_destroy (vlc_rwlock_t
*lock
)
75 vlc_cond_destroy (&lock
->wait
);
76 vlc_mutex_destroy (&lock
->mutex
);
79 void vlc_rwlock_rdlock (vlc_rwlock_t
*lock
)
81 vlc_mutex_lock (&lock
->mutex
);
82 /* Recursive read-locking is allowed.
83 * Ensure that there is no active writer. */
84 while (lock
->state
< 0)
86 assert (lock
->state
== WRITER_BIT
);
87 mutex_cleanup_push (&lock
->mutex
);
88 vlc_cond_wait (&lock
->wait
, &lock
->mutex
);
91 if (unlikely(lock
->state
>= READER_MASK
))
92 abort (); /* An overflow is certainly a recursion bug. */
94 vlc_mutex_unlock (&lock
->mutex
);
97 void vlc_rwlock_wrlock (vlc_rwlock_t
*lock
)
99 vlc_mutex_lock (&lock
->mutex
);
100 /* Wait until nobody owns the lock in any way. */
101 while (lock
->state
!= 0)
103 mutex_cleanup_push (&lock
->mutex
);
104 vlc_cond_wait (&lock
->wait
, &lock
->mutex
);
107 lock
->state
= WRITER_BIT
;
108 vlc_mutex_unlock (&lock
->mutex
);
111 void vlc_rwlock_unlock (vlc_rwlock_t
*lock
)
113 vlc_mutex_lock (&lock
->mutex
);
116 assert (lock
->state
== WRITER_BIT
);
117 /* Let reader and writer compete. OS scheduler decides who wins. */
119 vlc_cond_broadcast (&lock
->wait
);
123 assert (lock
->state
> 0);
124 /* If there are no readers left, wake up one pending writer. */
125 if (--lock
->state
== 0)
126 vlc_cond_signal (&lock
->wait
);
128 vlc_mutex_unlock (&lock
->mutex
);
130 #endif /* LIBVLC_NEED_RWLOCK */
132 #ifdef LIBVLC_NEED_SEMAPHORE
133 /*** Generic semaphores ***/
137 void vlc_sem_init (vlc_sem_t
*sem
, unsigned value
)
139 vlc_mutex_init (&sem
->lock
);
140 vlc_cond_init (&sem
->wait
);
144 void vlc_sem_destroy (vlc_sem_t
*sem
)
146 vlc_cond_destroy (&sem
->wait
);
147 vlc_mutex_destroy (&sem
->lock
);
150 int vlc_sem_post (vlc_sem_t
*sem
)
154 vlc_mutex_lock (&sem
->lock
);
155 if (likely(sem
->value
!= UINT_MAX
))
159 vlc_mutex_unlock (&sem
->lock
);
160 vlc_cond_signal (&sem
->wait
);
165 void vlc_sem_wait (vlc_sem_t
*sem
)
167 vlc_mutex_lock (&sem
->lock
);
168 mutex_cleanup_push (&sem
->lock
);
170 vlc_cond_wait (&sem
->wait
, &sem
->lock
);
173 vlc_mutex_unlock (&sem
->lock
);
175 #endif /* LIBVLC_NEED_SEMAPHORE */