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 */