1 | /***************************************************************************** |
2 | * vlc_threads.h : threads implementation for the VideoLAN client |
3 | * This header provides portable declarations for mutexes & conditions |
4 | ***************************************************************************** |
5 | * Copyright (C) 1999, 2002 VLC authors and VideoLAN |
6 | * Copyright © 2007-2016 Rémi Denis-Courmont |
7 | * |
8 | * Authors: Jean-Marc Dressler <polux@via.ecp.fr> |
9 | * Samuel Hocevar <sam@via.ecp.fr> |
10 | * Gildas Bazin <gbazin@netcourrier.com> |
11 | * Christophe Massiot <massiot@via.ecp.fr> |
12 | * |
13 | * This program is free software; you can redistribute it and/or modify it |
14 | * under the terms of the GNU Lesser General Public License as published by |
15 | * the Free Software Foundation; either version 2.1 of the License, or |
16 | * (at your option) any later version. |
17 | * |
18 | * This program is distributed in the hope that it will be useful, |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | * GNU Lesser General Public License for more details. |
22 | * |
23 | * You should have received a copy of the GNU Lesser General Public License |
24 | * along with this program; if not, write to the Free Software Foundation, |
25 | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
26 | *****************************************************************************/ |
27 | |
28 | #ifndef VLC_THREADS_H_ |
29 | #define VLC_THREADS_H_ |
30 | |
31 | /** |
32 | * \ingroup os |
33 | * \defgroup thread Threads and synchronization primitives |
34 | * @{ |
35 | * \file |
36 | * Thread primitive declarations |
37 | */ |
38 | |
39 | /** |
40 | * Issues an explicit deferred cancellation point. |
41 | * |
42 | * This has no effects if thread cancellation is disabled. |
43 | * This can be called when there is a rather slow non-sleeping operation. |
44 | * This is also used to force a cancellation point in a function that would |
45 | * otherwise <em>not always</em> be one (block_FifoGet() is an example). |
46 | */ |
47 | VLC_API void vlc_testcancel(void); |
48 | |
49 | #if defined (_WIN32) |
50 | # include <process.h> |
51 | # ifndef ETIMEDOUT |
52 | # define ETIMEDOUT 10060 /* This is the value in winsock.h. */ |
53 | # endif |
54 | |
55 | typedef struct vlc_thread *vlc_thread_t; |
56 | # define VLC_THREAD_CANCELED NULL |
57 | # define LIBVLC_NEED_SLEEP |
58 | typedef struct |
59 | { |
60 | bool dynamic; |
61 | union |
62 | { |
63 | struct |
64 | { |
65 | bool locked; |
66 | unsigned long contention; |
67 | }; |
68 | CRITICAL_SECTION mutex; |
69 | }; |
70 | } vlc_mutex_t; |
71 | #define VLC_STATIC_MUTEX { false, { { false, 0 } } } |
72 | #define LIBVLC_NEED_CONDVAR |
73 | #define LIBVLC_NEED_SEMAPHORE |
74 | #define LIBVLC_NEED_RWLOCK |
75 | typedef struct vlc_threadvar *vlc_threadvar_t; |
76 | typedef struct vlc_timer *vlc_timer_t; |
77 | |
78 | # define VLC_THREAD_PRIORITY_LOW 0 |
79 | # define VLC_THREAD_PRIORITY_INPUT THREAD_PRIORITY_ABOVE_NORMAL |
80 | # define VLC_THREAD_PRIORITY_AUDIO THREAD_PRIORITY_HIGHEST |
81 | # define VLC_THREAD_PRIORITY_VIDEO 0 |
82 | # define VLC_THREAD_PRIORITY_OUTPUT THREAD_PRIORITY_ABOVE_NORMAL |
83 | # define VLC_THREAD_PRIORITY_HIGHEST THREAD_PRIORITY_TIME_CRITICAL |
84 | |
85 | static inline int vlc_poll(struct pollfd *fds, unsigned nfds, int timeout) |
86 | { |
87 | int val; |
88 | |
89 | vlc_testcancel(); |
90 | val = poll(fds, nfds, timeout); |
91 | if (val < 0) |
92 | vlc_testcancel(); |
93 | return val; |
94 | } |
95 | # define poll(u,n,t) vlc_poll(u, n, t) |
96 | |
97 | #elif defined (__OS2__) |
98 | # include <errno.h> |
99 | |
100 | typedef struct vlc_thread *vlc_thread_t; |
101 | #define VLC_THREAD_CANCELED NULL |
102 | typedef struct |
103 | { |
104 | bool dynamic; |
105 | union |
106 | { |
107 | struct |
108 | { |
109 | bool locked; |
110 | unsigned long contention; |
111 | }; |
112 | HMTX hmtx; |
113 | }; |
114 | } vlc_mutex_t; |
115 | #define VLC_STATIC_MUTEX { false, { { false, 0 } } } |
116 | typedef struct |
117 | { |
118 | HEV hev; |
119 | unsigned waiters; |
120 | HEV hevAck; |
121 | unsigned signaled; |
122 | } vlc_cond_t; |
123 | #define VLC_STATIC_COND { NULLHANDLE, 0, NULLHANDLE, 0 } |
124 | #define LIBVLC_NEED_SEMAPHORE |
125 | #define LIBVLC_NEED_RWLOCK |
126 | typedef struct vlc_threadvar *vlc_threadvar_t; |
127 | typedef struct vlc_timer *vlc_timer_t; |
128 | |
129 | # define VLC_THREAD_PRIORITY_LOW 0 |
130 | # define VLC_THREAD_PRIORITY_INPUT \ |
131 | MAKESHORT(PRTYD_MAXIMUM / 2, PRTYC_REGULAR) |
132 | # define VLC_THREAD_PRIORITY_AUDIO MAKESHORT(PRTYD_MAXIMUM, PRTYC_REGULAR) |
133 | # define VLC_THREAD_PRIORITY_VIDEO 0 |
134 | # define VLC_THREAD_PRIORITY_OUTPUT \ |
135 | MAKESHORT(PRTYD_MAXIMUM / 2, PRTYC_REGULAR) |
136 | # define VLC_THREAD_PRIORITY_HIGHEST MAKESHORT(0, PRTYC_TIMECRITICAL) |
137 | |
138 | # define pthread_sigmask sigprocmask |
139 | |
140 | static inline int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout) |
141 | { |
142 | static int (*vlc_poll_os2)(struct pollfd *, unsigned, int) = NULL; |
143 | |
144 | if (!vlc_poll_os2) |
145 | { |
146 | HMODULE hmod; |
147 | CHAR szFailed[CCHMAXPATH]; |
148 | |
149 | if (DosLoadModule(szFailed, sizeof(szFailed), "vlccore" , &hmod)) |
150 | return -1; |
151 | |
152 | if (DosQueryProcAddr(hmod, 0, "_vlc_poll_os2" , (PFN *)&vlc_poll_os2)) |
153 | return -1; |
154 | } |
155 | |
156 | return (*vlc_poll_os2)(fds, nfds, timeout); |
157 | } |
158 | # define poll(u,n,t) vlc_poll(u, n, t) |
159 | |
160 | #elif defined (__ANDROID__) /* pthreads subset without pthread_cancel() */ |
161 | # include <unistd.h> |
162 | # include <pthread.h> |
163 | # include <poll.h> |
164 | # define LIBVLC_USE_PTHREAD_CLEANUP 1 |
165 | # define LIBVLC_NEED_SLEEP |
166 | # define LIBVLC_NEED_CONDVAR |
167 | # define LIBVLC_NEED_SEMAPHORE |
168 | # define LIBVLC_NEED_RWLOCK |
169 | |
170 | typedef struct vlc_thread *vlc_thread_t; |
171 | #define VLC_THREAD_CANCELED NULL |
172 | typedef pthread_mutex_t vlc_mutex_t; |
173 | #define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER |
174 | |
175 | typedef pthread_key_t vlc_threadvar_t; |
176 | typedef struct vlc_timer *vlc_timer_t; |
177 | |
178 | # define VLC_THREAD_PRIORITY_LOW 0 |
179 | # define VLC_THREAD_PRIORITY_INPUT 0 |
180 | # define VLC_THREAD_PRIORITY_AUDIO 0 |
181 | # define VLC_THREAD_PRIORITY_VIDEO 0 |
182 | # define VLC_THREAD_PRIORITY_OUTPUT 0 |
183 | # define VLC_THREAD_PRIORITY_HIGHEST 0 |
184 | |
185 | static inline int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout) |
186 | { |
187 | int val; |
188 | |
189 | do |
190 | { |
191 | int ugly_timeout = ((unsigned)timeout >= 50) ? 50 : timeout; |
192 | if (timeout >= 0) |
193 | timeout -= ugly_timeout; |
194 | |
195 | vlc_testcancel (); |
196 | val = poll (fds, nfds, ugly_timeout); |
197 | } |
198 | while (val == 0 && timeout != 0); |
199 | |
200 | return val; |
201 | } |
202 | |
203 | # define poll(u,n,t) vlc_poll(u, n, t) |
204 | |
205 | #elif defined (__APPLE__) |
206 | # define _APPLE_C_SOURCE 1 /* Proper pthread semantics on OSX */ |
207 | # include <unistd.h> |
208 | # include <pthread.h> |
209 | /* Unnamed POSIX semaphores not supported on Mac OS X */ |
210 | # include <mach/semaphore.h> |
211 | # include <mach/task.h> |
212 | # define LIBVLC_USE_PTHREAD 1 |
213 | # define LIBVLC_USE_PTHREAD_CLEANUP 1 |
214 | |
215 | typedef pthread_t vlc_thread_t; |
216 | #define VLC_THREAD_CANCELED PTHREAD_CANCELED |
217 | typedef pthread_mutex_t vlc_mutex_t; |
218 | #define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER |
219 | typedef pthread_cond_t vlc_cond_t; |
220 | #define VLC_STATIC_COND PTHREAD_COND_INITIALIZER |
221 | typedef semaphore_t vlc_sem_t; |
222 | typedef pthread_rwlock_t vlc_rwlock_t; |
223 | #define VLC_STATIC_RWLOCK PTHREAD_RWLOCK_INITIALIZER |
224 | typedef pthread_key_t vlc_threadvar_t; |
225 | typedef struct vlc_timer *vlc_timer_t; |
226 | |
227 | # define VLC_THREAD_PRIORITY_LOW 0 |
228 | # define VLC_THREAD_PRIORITY_INPUT 22 |
229 | # define VLC_THREAD_PRIORITY_AUDIO 22 |
230 | # define VLC_THREAD_PRIORITY_VIDEO 0 |
231 | # define VLC_THREAD_PRIORITY_OUTPUT 22 |
232 | # define VLC_THREAD_PRIORITY_HIGHEST 22 |
233 | |
234 | #else /* POSIX threads */ |
235 | # include <unistd.h> /* _POSIX_SPIN_LOCKS */ |
236 | # include <pthread.h> |
237 | # include <semaphore.h> |
238 | |
239 | /** |
240 | * Whether LibVLC threads are based on POSIX threads. |
241 | */ |
242 | # define LIBVLC_USE_PTHREAD 1 |
243 | |
244 | /** |
245 | * Whether LibVLC thread cancellation is based on POSIX threads. |
246 | */ |
247 | # define LIBVLC_USE_PTHREAD_CLEANUP 1 |
248 | |
249 | /** |
250 | * Thread handle. |
251 | */ |
252 | typedef struct |
253 | { |
254 | pthread_t handle; |
255 | } vlc_thread_t; |
256 | |
257 | /** |
258 | * Return value of a canceled thread. |
259 | */ |
260 | #define VLC_THREAD_CANCELED PTHREAD_CANCELED |
261 | |
262 | /** |
263 | * Mutex. |
264 | * |
265 | * Storage space for a mutual exclusion lock. |
266 | */ |
267 | typedef pthread_mutex_t vlc_mutex_t; |
268 | |
269 | /** |
270 | * Static initializer for (static) mutex. |
271 | */ |
272 | #define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER |
273 | |
274 | /** |
275 | * Condition variable. |
276 | * |
277 | * Storage space for a thread condition variable. |
278 | */ |
279 | typedef pthread_cond_t vlc_cond_t; |
280 | |
281 | /** |
282 | * Static initializer for (static) condition variable. |
283 | * |
284 | * \note |
285 | * The condition variable will use the default clock, which is OS-dependent. |
286 | * Therefore, where timed waits are necessary the condition variable should |
287 | * always be initialized dynamically explicit instead of using this |
288 | * initializer. |
289 | */ |
290 | #define VLC_STATIC_COND PTHREAD_COND_INITIALIZER |
291 | |
292 | /** |
293 | * Semaphore. |
294 | * |
295 | * Storage space for a thread-safe semaphore. |
296 | */ |
297 | typedef sem_t vlc_sem_t; |
298 | |
299 | /** |
300 | * Read/write lock. |
301 | * |
302 | * Storage space for a slim reader/writer lock. |
303 | */ |
304 | typedef pthread_rwlock_t vlc_rwlock_t; |
305 | |
306 | /** |
307 | * Static initializer for (static) read/write lock. |
308 | */ |
309 | #define VLC_STATIC_RWLOCK PTHREAD_RWLOCK_INITIALIZER |
310 | |
311 | /** |
312 | * Thread-local key handle. |
313 | */ |
314 | typedef pthread_key_t vlc_threadvar_t; |
315 | |
316 | /** |
317 | * Threaded timer handle. |
318 | */ |
319 | typedef struct vlc_timer *vlc_timer_t; |
320 | |
321 | # define VLC_THREAD_PRIORITY_LOW 0 |
322 | # define VLC_THREAD_PRIORITY_INPUT 10 |
323 | # define VLC_THREAD_PRIORITY_AUDIO 5 |
324 | # define VLC_THREAD_PRIORITY_VIDEO 0 |
325 | # define VLC_THREAD_PRIORITY_OUTPUT 15 |
326 | # define VLC_THREAD_PRIORITY_HIGHEST 20 |
327 | |
328 | #endif |
329 | |
330 | #ifdef LIBVLC_NEED_CONDVAR |
331 | typedef struct |
332 | { |
333 | unsigned value; |
334 | } vlc_cond_t; |
335 | # define VLC_STATIC_COND { 0 } |
336 | #endif |
337 | |
338 | #ifdef LIBVLC_NEED_SEMAPHORE |
339 | typedef struct vlc_sem |
340 | { |
341 | vlc_mutex_t lock; |
342 | vlc_cond_t wait; |
343 | unsigned value; |
344 | } vlc_sem_t; |
345 | #endif |
346 | |
347 | #ifdef LIBVLC_NEED_RWLOCK |
348 | typedef struct vlc_rwlock |
349 | { |
350 | vlc_mutex_t mutex; |
351 | vlc_cond_t wait; |
352 | long state; |
353 | } vlc_rwlock_t; |
354 | # define VLC_STATIC_RWLOCK { VLC_STATIC_MUTEX, VLC_STATIC_COND, 0 } |
355 | #endif |
356 | |
357 | /** |
358 | * Initializes a fast mutex. |
359 | * |
360 | * Recursive locking of a fast mutex is undefined behaviour. (In debug builds, |
361 | * recursive locking will cause an assertion failure.) |
362 | */ |
363 | VLC_API void vlc_mutex_init(vlc_mutex_t *); |
364 | |
365 | /** |
366 | * Initializes a recursive mutex. |
367 | * \warning This is strongly discouraged. Please use normal mutexes. |
368 | */ |
369 | VLC_API void vlc_mutex_init_recursive(vlc_mutex_t *); |
370 | |
371 | /** |
372 | * Deinitializes a mutex. |
373 | * |
374 | * The mutex must not be locked, otherwise behaviour is undefined. |
375 | */ |
376 | VLC_API void vlc_mutex_destroy(vlc_mutex_t *); |
377 | |
378 | /** |
379 | * Acquires a mutex. |
380 | * |
381 | * If needed, this waits for any other thread to release it. |
382 | * |
383 | * \warning Beware of deadlocks when locking multiple mutexes at the same time, |
384 | * or when using mutexes from callbacks. |
385 | * |
386 | * \note This function is not a cancellation point. |
387 | */ |
388 | VLC_API void vlc_mutex_lock(vlc_mutex_t *); |
389 | |
390 | /** |
391 | * Tries to acquire a mutex. |
392 | * |
393 | * This function acquires the mutex if and only if it is not currently held by |
394 | * another thread. This function never sleeps and can be used in delay-critical |
395 | * code paths. |
396 | * |
397 | * \note This function is not a cancellation point. |
398 | * |
399 | * \warning If this function fails, then the mutex is held... by another |
400 | * thread. The calling thread must deal with the error appropriately. That |
401 | * typically implies postponing the operations that would have required the |
402 | * mutex. If the thread cannot defer those operations, then it must use |
403 | * vlc_mutex_lock(). If in doubt, use vlc_mutex_lock() instead. |
404 | * |
405 | * @return 0 if the mutex could be acquired, an error code otherwise. |
406 | */ |
407 | VLC_API int vlc_mutex_trylock( vlc_mutex_t * ) VLC_USED; |
408 | |
409 | /** |
410 | * Releases a mutex. |
411 | * |
412 | * If the mutex is not held by the calling thread, the behaviour is undefined. |
413 | * |
414 | * \note This function is not a cancellation point. |
415 | */ |
416 | VLC_API void vlc_mutex_unlock(vlc_mutex_t *); |
417 | |
418 | /** |
419 | * Initializes a condition variable. |
420 | */ |
421 | VLC_API void vlc_cond_init(vlc_cond_t *); |
422 | |
423 | /** |
424 | * Initializes a condition variable (wall clock). |
425 | * |
426 | * This function initializes a condition variable for timed waiting using the |
427 | * UTC wall clock time. The time reference is the same as with time() and with |
428 | * timespec_get() and TIME_UTC. |
429 | * vlc_cond_timedwait_daytime() must be instead of |
430 | * vlc_cond_timedwait() for actual waiting. |
431 | */ |
432 | void vlc_cond_init_daytime(vlc_cond_t *); |
433 | |
434 | /** |
435 | * Deinitializes a condition variable. |
436 | * |
437 | * No threads shall be waiting or signaling the condition, otherwise the |
438 | * behavior is undefined. |
439 | */ |
440 | VLC_API void vlc_cond_destroy(vlc_cond_t *); |
441 | |
442 | /** |
443 | * Wakes up one thread waiting on a condition variable. |
444 | * |
445 | * If any thread is currently waiting on the condition variable, at least one |
446 | * of those threads will be woken up. Otherwise, this function has no effects. |
447 | * |
448 | * \note This function is not a cancellation point. |
449 | */ |
450 | VLC_API void vlc_cond_signal(vlc_cond_t *); |
451 | |
452 | /** |
453 | * Wakes up all threads waiting on a condition variable. |
454 | * |
455 | * \note This function is not a cancellation point. |
456 | */ |
457 | VLC_API void vlc_cond_broadcast(vlc_cond_t *); |
458 | |
459 | /** |
460 | * Waits on a condition variable. |
461 | * |
462 | * The calling thread will be suspended until another thread calls |
463 | * vlc_cond_signal() or vlc_cond_broadcast() on the same condition variable, |
464 | * the thread is cancelled with vlc_cancel(), or the system causes a |
465 | * <em>spurious</em> unsolicited wake-up. |
466 | * |
467 | * A mutex is needed to wait on a condition variable. It must <b>not</b> be |
468 | * a recursive mutex. Although it is possible to use the same mutex for |
469 | * multiple condition, it is not valid to use different mutexes for the same |
470 | * condition variable at the same time from different threads. |
471 | * |
472 | * The canonical way to use a condition variable to wait for event foobar is: |
473 | @code |
474 | vlc_mutex_lock(&lock); |
475 | mutex_cleanup_push(&lock); // release the mutex in case of cancellation |
476 | |
477 | while (!foobar) |
478 | vlc_cond_wait(&wait, &lock); |
479 | |
480 | // -- foobar is now true, do something about it here -- |
481 | |
482 | vlc_cleanup_pop(); |
483 | vlc_mutex_unlock(&lock); |
484 | @endcode |
485 | * |
486 | * \note This function is a cancellation point. In case of thread cancellation, |
487 | * the mutex is always locked before cancellation proceeds. |
488 | * |
489 | * \param cond condition variable to wait on |
490 | * \param mutex mutex which is unlocked while waiting, |
491 | * then locked again when waking up. |
492 | */ |
493 | VLC_API void vlc_cond_wait(vlc_cond_t *cond, vlc_mutex_t *mutex); |
494 | |
495 | /** |
496 | * Waits on a condition variable up to a certain date. |
497 | * |
498 | * This works like vlc_cond_wait() but with an additional time-out. |
499 | * The time-out is expressed as an absolute timestamp using the same arbitrary |
500 | * time reference as the mdate() and mwait() functions. |
501 | * |
502 | * \note This function is a cancellation point. In case of thread cancellation, |
503 | * the mutex is always locked before cancellation proceeds. |
504 | * |
505 | * \param cond condition variable to wait on |
506 | * \param mutex mutex which is unlocked while waiting, |
507 | * then locked again when waking up |
508 | * \param deadline <b>absolute</b> timeout |
509 | * |
510 | * \warning If the variable was initialized with vlc_cond_init_daytime(), or |
511 | * was statically initialized with \ref VLC_STATIC_COND, the time reference |
512 | * used by this function is unspecified (depending on the implementation, it |
513 | * might be the Unix epoch or the mdate() clock). |
514 | * |
515 | * \return 0 if the condition was signaled, an error code in case of timeout. |
516 | */ |
517 | VLC_API int vlc_cond_timedwait(vlc_cond_t *cond, vlc_mutex_t *mutex, |
518 | mtime_t deadline); |
519 | |
520 | int vlc_cond_timedwait_daytime(vlc_cond_t *, vlc_mutex_t *, time_t); |
521 | |
522 | /** |
523 | * Initializes a semaphore. |
524 | * |
525 | * @param count initial semaphore value (typically 0) |
526 | */ |
527 | VLC_API void vlc_sem_init(vlc_sem_t *, unsigned count); |
528 | |
529 | /** |
530 | * Deinitializes a semaphore. |
531 | */ |
532 | VLC_API void vlc_sem_destroy(vlc_sem_t *); |
533 | |
534 | /** |
535 | * Increments the value of a semaphore. |
536 | * |
537 | * \note This function is not a cancellation point. |
538 | * |
539 | * \return 0 on success, EOVERFLOW in case of integer overflow. |
540 | */ |
541 | VLC_API int vlc_sem_post(vlc_sem_t *); |
542 | |
543 | /** |
544 | * Waits on a semaphore. |
545 | * |
546 | * This function atomically waits for the semaphore to become non-zero then |
547 | * decrements it, and returns. If the semaphore is non-zero on entry, it is |
548 | * immediately decremented. |
549 | * |
550 | * \note This function may be a point of cancellation. |
551 | */ |
552 | VLC_API void vlc_sem_wait(vlc_sem_t *); |
553 | |
554 | /** |
555 | * Initializes a read/write lock. |
556 | */ |
557 | VLC_API void vlc_rwlock_init(vlc_rwlock_t *); |
558 | |
559 | /** |
560 | * Destroys an initialized unused read/write lock. |
561 | */ |
562 | VLC_API void vlc_rwlock_destroy(vlc_rwlock_t *); |
563 | |
564 | /** |
565 | * Acquires a read/write lock for reading. |
566 | * |
567 | * \note Recursion is allowed. |
568 | * \note This function may be a point of cancellation. |
569 | */ |
570 | VLC_API void vlc_rwlock_rdlock(vlc_rwlock_t *); |
571 | |
572 | /** |
573 | * Acquires a read/write lock for writing. Recursion is not allowed. |
574 | * \note This function may be a point of cancellation. |
575 | */ |
576 | VLC_API void vlc_rwlock_wrlock(vlc_rwlock_t *); |
577 | |
578 | /** |
579 | * Releases a read/write lock. |
580 | * |
581 | * The calling thread must hold the lock. Otherwise behaviour is undefined. |
582 | * |
583 | * \note This function is not a cancellation point. |
584 | */ |
585 | VLC_API void vlc_rwlock_unlock(vlc_rwlock_t *); |
586 | |
587 | /** |
588 | * Allocates a thread-specific variable. |
589 | * |
590 | * @param key where to store the thread-specific variable handle |
591 | * @param destr a destruction callback. It is called whenever a thread exits |
592 | * and the thread-specific variable has a non-NULL value. |
593 | * |
594 | * @return 0 on success, a system error code otherwise. |
595 | * This function can actually fail: on most systems, there is a fixed limit to |
596 | * the number of thread-specific variables in a given process. |
597 | */ |
598 | VLC_API int vlc_threadvar_create(vlc_threadvar_t *key, void (*destr) (void *)); |
599 | |
600 | /** |
601 | * Deallocates a thread-specific variable. |
602 | */ |
603 | VLC_API void vlc_threadvar_delete(vlc_threadvar_t *); |
604 | |
605 | /** |
606 | * Sets a thread-specific variable. |
607 | |
608 | * \param key thread-local variable key (created with vlc_threadvar_create()) |
609 | * \param value new value for the variable for the calling thread |
610 | * \return 0 on success, a system error code otherwise. |
611 | */ |
612 | VLC_API int vlc_threadvar_set(vlc_threadvar_t key, void *value); |
613 | |
614 | /** |
615 | * Gets the value of a thread-local variable for the calling thread. |
616 | * This function cannot fail. |
617 | * |
618 | * \return the value associated with the given variable for the calling |
619 | * or NULL if no value was set. |
620 | */ |
621 | VLC_API void *vlc_threadvar_get(vlc_threadvar_t); |
622 | |
623 | /** |
624 | * Waits on an address. |
625 | * |
626 | * Puts the calling thread to sleep if a specific value is stored at a |
627 | * specified address. The thread will sleep until it is woken up by a call to |
628 | * vlc_addr_signal() or vlc_addr_broadcast() in another thread, or spuriously. |
629 | * |
630 | * If the value does not match, do nothing and return immediately. |
631 | * |
632 | * \param addr address to check for |
633 | * \param val value to match at the address |
634 | */ |
635 | void vlc_addr_wait(void *addr, unsigned val); |
636 | |
637 | /** |
638 | * Waits on an address with a time-out. |
639 | * |
640 | * This function operates as vlc_addr_wait() but provides an additional |
641 | * time-out. If the time-out elapses, the thread resumes and the function |
642 | * returns. |
643 | * |
644 | * \param addr address to check for |
645 | * \param val value to match at the address |
646 | * \param delay time-out duration |
647 | * |
648 | * \return true if the function was woken up before the time-out, |
649 | * false if the time-out elapsed. |
650 | */ |
651 | bool vlc_addr_timedwait(void *addr, unsigned val, mtime_t delay); |
652 | |
653 | /** |
654 | * Wakes up one thread on an address. |
655 | * |
656 | * Wakes up (at least) one of the thread sleeping on the specified address. |
657 | * The address must be equal to the first parameter given by at least one |
658 | * thread sleeping within the vlc_addr_wait() or vlc_addr_timedwait() |
659 | * functions. If no threads are found, this function does nothing. |
660 | * |
661 | * \param addr address identifying which threads may be woken up |
662 | */ |
663 | void vlc_addr_signal(void *addr); |
664 | |
665 | /** |
666 | * Wakes up all thread on an address. |
667 | * |
668 | * Wakes up all threads sleeping on the specified address (if any). |
669 | * Any thread sleeping within a call to vlc_addr_wait() or vlc_addr_timedwait() |
670 | * with the specified address as first call parameter will be woken up. |
671 | * |
672 | * \param addr address identifying which threads to wake up |
673 | */ |
674 | void vlc_addr_broadcast(void *addr); |
675 | |
676 | /** |
677 | * Creates and starts a new thread. |
678 | * |
679 | * The thread must be <i>joined</i> with vlc_join() to reclaim resources |
680 | * when it is not needed anymore. |
681 | * |
682 | * @param th storage space for the handle of the new thread (cannot be NULL) |
683 | * [OUT] |
684 | * @param entry entry point for the thread |
685 | * @param data data parameter given to the entry point |
686 | * @param priority thread priority value |
687 | * @return 0 on success, a standard error code on error. |
688 | * @note In case of error, the value of *th is undefined. |
689 | */ |
690 | VLC_API int vlc_clone(vlc_thread_t *th, void *(*entry)(void *), void *data, |
691 | int priority) VLC_USED; |
692 | |
693 | /** |
694 | * Marks a thread as cancelled. |
695 | * |
696 | * Next time the target thread reaches a cancellation point (while not having |
697 | * disabled cancellation), it will run its cancellation cleanup handler, the |
698 | * thread variable destructors, and terminate. |
699 | * |
700 | * vlc_join() must be used regardless of a thread being cancelled or not, to |
701 | * avoid leaking resources. |
702 | */ |
703 | VLC_API void vlc_cancel(vlc_thread_t); |
704 | |
705 | /** |
706 | * Waits for a thread to complete (if needed), then destroys it. |
707 | * |
708 | * \note This is a cancellation point. In case of cancellation, the thread is |
709 | * <b>not</b> joined. |
710 | |
711 | * \warning A thread cannot join itself (normally VLC will abort if this is |
712 | * attempted). Also a detached thread <b>cannot</b> be joined. |
713 | * |
714 | * @param th thread handle |
715 | * @param result [OUT] pointer to write the thread return value or NULL |
716 | */ |
717 | VLC_API void vlc_join(vlc_thread_t th, void **result); |
718 | |
719 | /** |
720 | * Disables thread cancellation. |
721 | * |
722 | * This functions saves the current cancellation state (enabled or disabled), |
723 | * then disables cancellation for the calling thread. It must be called before |
724 | * entering a piece of code that is not cancellation-safe, unless it can be |
725 | * proven that the calling thread will not be cancelled. |
726 | * |
727 | * \note This function is not a cancellation point. |
728 | * |
729 | * \return Previous cancellation state (opaque value for vlc_restorecancel()). |
730 | */ |
731 | VLC_API int vlc_savecancel(void); |
732 | |
733 | /** |
734 | * Restores the cancellation state. |
735 | * |
736 | * This function restores the cancellation state of the calling thread to |
737 | * a state previously saved by vlc_savecancel(). |
738 | * |
739 | * \note This function is not a cancellation point. |
740 | * |
741 | * \param state previous state as returned by vlc_savecancel(). |
742 | */ |
743 | VLC_API void vlc_restorecancel(int state); |
744 | |
745 | /** |
746 | * Internal handler for thread cancellation. |
747 | * |
748 | * Do not call this function directly. Use wrapper macros instead: |
749 | * vlc_cleanup_push(), vlc_cleanup_pop(). |
750 | */ |
751 | VLC_API void vlc_control_cancel(int cmd, ...); |
752 | |
753 | /** |
754 | * Thread handle. |
755 | * |
756 | * This function returns the thread handle of the calling thread. |
757 | * |
758 | * \note The exact type of the thread handle depends on the platform, |
759 | * including an integer type, a pointer type or a compound type of any size. |
760 | * If you need an integer identifier, use vlc_thread_id() instead. |
761 | * |
762 | * \note vlc_join(vlc_thread_self(), NULL) is undefined, |
763 | * as it obviously does not make any sense (it might result in a deadlock, but |
764 | * there are no warranties that it will). |
765 | * |
766 | * \return the thread handle |
767 | */ |
768 | VLC_API vlc_thread_t vlc_thread_self(void) VLC_USED; |
769 | |
770 | /** |
771 | * Thread identifier. |
772 | * |
773 | * This function returns the identifier of the calling thread. The identifier |
774 | * cannot change for the entire duration of the thread, and no other thread can |
775 | * have the same identifier at the same time in the same process. Typically, |
776 | * the identifier is also unique across all running threads of all existing |
777 | * processes, but that depends on the operating system. |
778 | * |
779 | * There are no particular semantics to the thread ID with LibVLC. |
780 | * It is provided mainly for tracing and debugging. |
781 | * |
782 | * \warning This function is not currently implemented on all supported |
783 | * platforms. Where not implemented, it returns (unsigned long)-1. |
784 | * |
785 | * \return the thread identifier (or -1 if unimplemented) |
786 | */ |
787 | VLC_API unsigned long vlc_thread_id(void) VLC_USED; |
788 | |
789 | /** |
790 | * Precision monotonic clock. |
791 | * |
792 | * In principles, the clock has a precision of 1 MHz. But the actual resolution |
793 | * may be much lower, especially when it comes to sleeping with mwait() or |
794 | * msleep(). Most general-purpose operating systems provide a resolution of |
795 | * only 100 to 1000 Hz. |
796 | * |
797 | * \warning The origin date (time value "zero") is not specified. It is |
798 | * typically the time the kernel started, but this is platform-dependent. |
799 | * If you need wall clock time, use gettimeofday() instead. |
800 | * |
801 | * \return a timestamp in microseconds. |
802 | */ |
803 | VLC_API mtime_t mdate(void); |
804 | |
805 | /** |
806 | * Waits until a deadline. |
807 | * |
808 | * \param deadline timestamp to wait for (\ref mdate()) |
809 | * |
810 | * \note The deadline may be exceeded due to OS scheduling. |
811 | * \note This function is a cancellation point. |
812 | */ |
813 | VLC_API void mwait(mtime_t deadline); |
814 | |
815 | /** |
816 | * Waits for an interval of time. |
817 | * |
818 | * \param delay how long to wait (in microseconds) |
819 | * |
820 | * \note The delay may be exceeded due to OS scheduling. |
821 | * \note This function is a cancellation point. |
822 | */ |
823 | VLC_API void msleep(mtime_t delay); |
824 | |
825 | #define VLC_HARD_MIN_SLEEP 10000 /* 10 milliseconds = 1 tick at 100Hz */ |
826 | #define VLC_SOFT_MIN_SLEEP 9000000 /* 9 seconds */ |
827 | |
828 | #if defined (__GNUC__) && !defined (__clang__) |
829 | /* Linux has 100, 250, 300 or 1000Hz |
830 | * |
831 | * HZ=100 by default on FreeBSD, but some architectures use a 1000Hz timer |
832 | */ |
833 | |
834 | static |
835 | __attribute__((unused)) |
836 | __attribute__((noinline)) |
837 | __attribute__((error("sorry, cannot sleep for such short a time" ))) |
838 | mtime_t impossible_delay( mtime_t delay ) |
839 | { |
840 | (void) delay; |
841 | return VLC_HARD_MIN_SLEEP; |
842 | } |
843 | |
844 | static |
845 | __attribute__((unused)) |
846 | __attribute__((noinline)) |
847 | __attribute__((warning("use proper event handling instead of short delay" ))) |
848 | mtime_t harmful_delay( mtime_t delay ) |
849 | { |
850 | return delay; |
851 | } |
852 | |
853 | # define check_delay( d ) \ |
854 | ((__builtin_constant_p(d < VLC_HARD_MIN_SLEEP) \ |
855 | && (d < VLC_HARD_MIN_SLEEP)) \ |
856 | ? impossible_delay(d) \ |
857 | : ((__builtin_constant_p(d < VLC_SOFT_MIN_SLEEP) \ |
858 | && (d < VLC_SOFT_MIN_SLEEP)) \ |
859 | ? harmful_delay(d) \ |
860 | : d)) |
861 | |
862 | static |
863 | __attribute__((unused)) |
864 | __attribute__((noinline)) |
865 | __attribute__((error("deadlines can not be constant" ))) |
866 | mtime_t impossible_deadline( mtime_t deadline ) |
867 | { |
868 | return deadline; |
869 | } |
870 | |
871 | # define check_deadline( d ) \ |
872 | (__builtin_constant_p(d) ? impossible_deadline(d) : d) |
873 | #else |
874 | # define check_delay(d) (d) |
875 | # define check_deadline(d) (d) |
876 | #endif |
877 | |
878 | #define msleep(d) msleep(check_delay(d)) |
879 | #define mwait(d) mwait(check_deadline(d)) |
880 | |
881 | /** |
882 | * Initializes an asynchronous timer. |
883 | * |
884 | * \param id pointer to timer to be initialized |
885 | * \param func function that the timer will call |
886 | * \param data parameter for the timer function |
887 | * \return 0 on success, a system error code otherwise. |
888 | * |
889 | * \warning Asynchronous timers are processed from an unspecified thread. |
890 | * \note Multiple occurrences of a single interval timer are serialized: |
891 | * they cannot run concurrently. |
892 | */ |
893 | VLC_API int vlc_timer_create(vlc_timer_t *id, void (*func)(void *), void *data) |
894 | VLC_USED; |
895 | |
896 | /** |
897 | * Destroys an initialized timer. |
898 | * |
899 | * If needed, the timer is first disarmed. Behaviour is undefined if the |
900 | * specified timer is not initialized. |
901 | * |
902 | * \warning This function <b>must</b> be called before the timer data can be |
903 | * freed and before the timer callback function can be unmapped/unloaded. |
904 | * |
905 | * \param timer timer to destroy |
906 | */ |
907 | VLC_API void vlc_timer_destroy(vlc_timer_t timer); |
908 | |
909 | /** |
910 | * Arms or disarms an initialized timer. |
911 | * |
912 | * This functions overrides any previous call to itself. |
913 | * |
914 | * \note A timer can fire later than requested due to system scheduling |
915 | * limitations. An interval timer can fail to trigger sometimes, either because |
916 | * the system is busy or suspended, or because a previous iteration of the |
917 | * timer is still running. See also vlc_timer_getoverrun(). |
918 | * |
919 | * \param timer initialized timer |
920 | * \param absolute the timer value origin is the same as mdate() if true, |
921 | * the timer value is relative to now if false. |
922 | * \param value zero to disarm the timer, otherwise the initial time to wait |
923 | * before firing the timer. |
924 | * \param interval zero to fire the timer just once, otherwise the timer |
925 | * repetition interval. |
926 | */ |
927 | VLC_API void vlc_timer_schedule(vlc_timer_t timer, bool absolute, |
928 | mtime_t value, mtime_t interval); |
929 | |
930 | /** |
931 | * Fetches and resets the overrun counter for a timer. |
932 | * |
933 | * This functions returns the number of times that the interval timer should |
934 | * have fired, but the callback was not invoked due to scheduling problems. |
935 | * The call resets the counter to zero. |
936 | * |
937 | * \param timer initialized timer |
938 | * \return the timer overrun counter (typically zero) |
939 | */ |
940 | VLC_API unsigned vlc_timer_getoverrun(vlc_timer_t) VLC_USED; |
941 | |
942 | /** |
943 | * Count CPUs. |
944 | * |
945 | * \return number of available (logical) CPUs. |
946 | */ |
947 | VLC_API unsigned vlc_GetCPUCount(void); |
948 | |
949 | enum |
950 | { |
951 | VLC_CLEANUP_PUSH, |
952 | VLC_CLEANUP_POP, |
953 | VLC_CANCEL_ADDR_SET, |
954 | VLC_CANCEL_ADDR_CLEAR, |
955 | }; |
956 | |
957 | #if defined (LIBVLC_USE_PTHREAD_CLEANUP) |
958 | /** |
959 | * Registers a thread cancellation handler. |
960 | * |
961 | * This pushes a function to run if the thread is cancelled (or otherwise |
962 | * exits prematurely). |
963 | * |
964 | * If multiple procedures are registered, |
965 | * they are handled in last-in first-out order. |
966 | * |
967 | * \note Any call to vlc_cleanup_push() <b>must</b> paired with a call to |
968 | * vlc_cleanup_pop(). |
969 | * \warning Branching into or out of the block between these two function calls |
970 | * is not allowed (read: it will likely crash the whole process). |
971 | * |
972 | * \param routine procedure to call if the thread ends |
973 | * \param arg argument for the procedure |
974 | */ |
975 | # define vlc_cleanup_push( routine, arg ) pthread_cleanup_push (routine, arg) |
976 | |
977 | /** |
978 | * Unregisters the last cancellation handler. |
979 | * |
980 | * This pops the cancellation handler that was last pushed with |
981 | * vlc_cleanup_push() in the calling thread. |
982 | */ |
983 | # define vlc_cleanup_pop( ) pthread_cleanup_pop (0) |
984 | |
985 | #else |
986 | typedef struct vlc_cleanup_t vlc_cleanup_t; |
987 | |
988 | struct vlc_cleanup_t |
989 | { |
990 | vlc_cleanup_t *next; |
991 | void (*proc) (void *); |
992 | void *data; |
993 | }; |
994 | |
995 | /* This macros opens a code block on purpose. This is needed for multiple |
996 | * calls within a single function. This also prevent Win32 developers from |
997 | * writing code that would break on POSIX (POSIX opens a block as well). */ |
998 | # define vlc_cleanup_push( routine, arg ) \ |
999 | do { \ |
1000 | vlc_cleanup_t vlc_cleanup_data = { NULL, routine, arg, }; \ |
1001 | vlc_control_cancel (VLC_CLEANUP_PUSH, &vlc_cleanup_data) |
1002 | |
1003 | # define vlc_cleanup_pop( ) \ |
1004 | vlc_control_cancel (VLC_CLEANUP_POP); \ |
1005 | } while (0) |
1006 | |
1007 | #endif /* !LIBVLC_USE_PTHREAD_CLEANUP */ |
1008 | |
1009 | static inline void vlc_cleanup_lock (void *lock) |
1010 | { |
1011 | vlc_mutex_unlock ((vlc_mutex_t *)lock); |
1012 | } |
1013 | #define mutex_cleanup_push( lock ) vlc_cleanup_push (vlc_cleanup_lock, lock) |
1014 | |
1015 | static inline void vlc_cancel_addr_set(void *addr) |
1016 | { |
1017 | vlc_control_cancel(cmd: VLC_CANCEL_ADDR_SET, addr); |
1018 | } |
1019 | |
1020 | static inline void vlc_cancel_addr_clear(void *addr) |
1021 | { |
1022 | vlc_control_cancel(cmd: VLC_CANCEL_ADDR_CLEAR, addr); |
1023 | } |
1024 | |
1025 | #ifdef __cplusplus |
1026 | /** |
1027 | * Helper C++ class to lock a mutex. |
1028 | * |
1029 | * The mutex is locked when the object is created, and unlocked when the object |
1030 | * is destroyed. |
1031 | */ |
1032 | class vlc_mutex_locker |
1033 | { |
1034 | private: |
1035 | vlc_mutex_t *lock; |
1036 | public: |
1037 | vlc_mutex_locker (vlc_mutex_t *m) : lock (m) |
1038 | { |
1039 | vlc_mutex_lock (lock); |
1040 | } |
1041 | |
1042 | ~vlc_mutex_locker (void) |
1043 | { |
1044 | vlc_mutex_unlock (lock); |
1045 | } |
1046 | }; |
1047 | #endif |
1048 | |
1049 | enum |
1050 | { |
1051 | VLC_AVCODEC_MUTEX = 0, |
1052 | VLC_GCRYPT_MUTEX, |
1053 | VLC_XLIB_MUTEX, |
1054 | VLC_MOSAIC_MUTEX, |
1055 | VLC_HIGHLIGHT_MUTEX, |
1056 | #ifdef _WIN32 |
1057 | VLC_MTA_MUTEX, |
1058 | #endif |
1059 | /* Insert new entry HERE */ |
1060 | VLC_MAX_MUTEX |
1061 | }; |
1062 | |
1063 | /** |
1064 | * Internal handler for global mutexes. |
1065 | * |
1066 | * Do not use this function directly. Use helper macros instead: |
1067 | * vlc_global_lock(), vlc_global_unlock(). |
1068 | */ |
1069 | VLC_API void vlc_global_mutex(unsigned, bool); |
1070 | |
1071 | /** |
1072 | * Acquires a global mutex. |
1073 | */ |
1074 | #define vlc_global_lock( n ) vlc_global_mutex(n, true) |
1075 | |
1076 | /** |
1077 | * Releases a global mutex. |
1078 | */ |
1079 | #define vlc_global_unlock( n ) vlc_global_mutex(n, false) |
1080 | |
1081 | /** @} */ |
1082 | |
1083 | #endif /* !_VLC_THREADS_H */ |
1084 | |