]> git.sesse.net Git - vlc/blob - include/vlc_threads.h
android: threads support
[vlc] / include / vlc_threads.h
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-2008 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  * \file
33  * This file defines structures and functions for handling threads in vlc
34  *
35  */
36
37 #if defined( WIN32 )
38 #   include <process.h>                                         /* Win32 API */
39
40 #elif defined( __OS2__ )                                        /* OS/2 API  */
41 #   include <errno.h>
42
43 #   define pthread_sigmask  sigprocmask
44
45 #elif defined( __ANDROID__ )      /* pthreads subset without pthread_cancel() */
46
47 #   define LIBVLC_NEED_SEMAPHORE
48 #   define LIBVLC_NEED_RWLOCK
49
50 #   include <unistd.h> /* _POSIX_SPIN_LOCKS */
51 #   include <pthread.h>
52 #   include <poll.h>
53
54 #else                                         /* pthreads (like Linux & BSD) */
55 #   define LIBVLC_USE_PTHREAD 1
56 #   define LIBVLC_USE_PTHREAD_CANCEL 1
57 #   define _APPLE_C_SOURCE    1 /* Proper pthread semantics on OSX */
58
59 #   include <unistd.h> /* _POSIX_SPIN_LOCKS */
60 #   include <pthread.h>
61
62 /* Unnamed POSIX semaphores not supported on Mac OS X, use Mach semaphores instead */
63 #   if defined (__APPLE__)
64 #      include <mach/semaphore.h>
65 #      include <mach/task.h>
66 #   else
67 #      include <semaphore.h>
68 #   endif
69
70 #endif
71
72 /*****************************************************************************
73  * Constants
74  *****************************************************************************/
75
76 /* Thread priorities */
77 #ifdef __APPLE__
78 #   define VLC_THREAD_PRIORITY_LOW      0
79 #   define VLC_THREAD_PRIORITY_INPUT   22
80 #   define VLC_THREAD_PRIORITY_AUDIO   22
81 #   define VLC_THREAD_PRIORITY_VIDEO    0
82 #   define VLC_THREAD_PRIORITY_OUTPUT  22
83 #   define VLC_THREAD_PRIORITY_HIGHEST 22
84
85 #elif defined(LIBVLC_USE_PTHREAD) || defined(__ANDROID__)
86 #   define VLC_THREAD_PRIORITY_LOW      0
87 #   define VLC_THREAD_PRIORITY_INPUT   10
88 #   define VLC_THREAD_PRIORITY_AUDIO    5
89 #   define VLC_THREAD_PRIORITY_VIDEO    0
90 #   define VLC_THREAD_PRIORITY_OUTPUT  15
91 #   define VLC_THREAD_PRIORITY_HIGHEST 20
92
93 #elif defined(WIN32)
94 /* Define different priorities for WinNT/2K/XP and Win9x/Me */
95 #   define VLC_THREAD_PRIORITY_LOW 0
96 #   define VLC_THREAD_PRIORITY_INPUT \
97         THREAD_PRIORITY_ABOVE_NORMAL
98 #   define VLC_THREAD_PRIORITY_AUDIO \
99         THREAD_PRIORITY_HIGHEST
100 #   define VLC_THREAD_PRIORITY_VIDEO 0
101 #   define VLC_THREAD_PRIORITY_OUTPUT \
102         THREAD_PRIORITY_ABOVE_NORMAL
103 #   define VLC_THREAD_PRIORITY_HIGHEST \
104         THREAD_PRIORITY_TIME_CRITICAL
105
106 #elif defined(__OS2__)
107 #   define VLC_THREAD_PRIORITY_LOW      0
108 #   define VLC_THREAD_PRIORITY_INPUT    MAKESHORT( PRTYD_MAXIMUM / 2, PRTYC_REGULAR )
109 #   define VLC_THREAD_PRIORITY_AUDIO    MAKESHORT( PRTYD_MAXIMUM, PRTYC_REGULAR )
110 #   define VLC_THREAD_PRIORITY_VIDEO    0
111 #   define VLC_THREAD_PRIORITY_OUTPUT   MAKESHORT( PRTYD_MAXIMUM / 2, PRTYC_REGULAR )
112 #   define VLC_THREAD_PRIORITY_HIGHEST  MAKESHORT( 0, PRTYC_TIMECRITICAL )
113
114 #else
115 #   define VLC_THREAD_PRIORITY_LOW 0
116 #   define VLC_THREAD_PRIORITY_INPUT 0
117 #   define VLC_THREAD_PRIORITY_AUDIO 0
118 #   define VLC_THREAD_PRIORITY_VIDEO 0
119 #   define VLC_THREAD_PRIORITY_OUTPUT 0
120 #   define VLC_THREAD_PRIORITY_HIGHEST 0
121
122 #endif
123
124 /*****************************************************************************
125  * Type definitions
126  *****************************************************************************/
127
128 #if defined (__ANDROID__)
129 typedef struct vlc_thread *vlc_thread_t;
130 typedef pthread_mutex_t vlc_mutex_t;
131 #define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER
132 typedef pthread_cond_t  vlc_cond_t;
133 #define VLC_STATIC_COND  PTHREAD_COND_INITIALIZER
134
135 typedef pthread_key_t   vlc_threadvar_t;
136 typedef struct vlc_timer *vlc_timer_t;
137
138 #elif defined (LIBVLC_USE_PTHREAD)
139 typedef pthread_t       vlc_thread_t;
140 typedef pthread_mutex_t vlc_mutex_t;
141 #define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER
142 typedef pthread_cond_t  vlc_cond_t;
143 #define VLC_STATIC_COND  PTHREAD_COND_INITIALIZER
144 typedef pthread_rwlock_t vlc_rwlock_t;
145 #define VLC_STATIC_RWLOCK PTHREAD_RWLOCK_INITIALIZER
146 typedef pthread_key_t   vlc_threadvar_t;
147 typedef struct vlc_timer *vlc_timer_t;
148
149 #if defined (__APPLE__)
150 typedef semaphore_t     vlc_sem_t;
151 #else
152 typedef sem_t           vlc_sem_t;
153 #endif
154
155 #elif defined( WIN32 )
156 typedef struct vlc_thread *vlc_thread_t;
157
158 typedef struct
159 {
160     bool dynamic;
161     union
162     {
163         struct
164         {
165             bool locked;
166             unsigned long contention;
167         };
168         CRITICAL_SECTION mutex;
169     };
170 } vlc_mutex_t;
171 #define VLC_STATIC_MUTEX { false, { { false, 0 } } }
172
173 typedef struct
174 {
175     HANDLE   handle;
176     unsigned clock;
177 } vlc_cond_t;
178 #define VLC_STATIC_COND { 0, 0 }
179
180 typedef HANDLE vlc_sem_t;
181 #define LIBVLC_NEED_RWLOCK
182 typedef struct vlc_threadvar *vlc_threadvar_t;
183 typedef struct vlc_timer *vlc_timer_t;
184
185 #elif defined( __OS2__ )
186 typedef struct vlc_thread *vlc_thread_t;
187
188 typedef struct
189 {
190     bool dynamic;
191     union
192     {
193         struct
194         {
195             bool locked;
196             unsigned long contention;
197         };
198         HMTX hmtx;
199     };
200 } vlc_mutex_t;
201 #define VLC_STATIC_MUTEX { false, { { false, 0 } } }
202
203 typedef struct
204 {
205     HEV      hev;
206     unsigned clock;
207 } vlc_cond_t;
208 #define VLC_STATIC_COND { 0, 0 }
209
210 #define LIBVLC_NEED_SEMAPHORE
211 #define LIBVLC_NEED_RWLOCK
212 typedef struct vlc_threadvar *vlc_threadvar_t;
213 typedef struct vlc_timer *vlc_timer_t;
214
215 #endif
216
217 #ifdef LIBVLC_NEED_SEMAPHORE
218 typedef struct vlc_sem
219 {
220     vlc_mutex_t lock;
221     vlc_cond_t  wait;
222     unsigned    value;
223 } vlc_sem_t;
224 #endif
225
226 #ifdef LIBVLC_NEED_RWLOCK
227 typedef struct vlc_rwlock
228 {
229     vlc_mutex_t   mutex;
230     vlc_cond_t    wait;
231     long          state;
232 } vlc_rwlock_t;
233 # define VLC_STATIC_RWLOCK { VLC_STATIC_MUTEX, VLC_STATIC_COND, 0 }
234 #endif
235
236 #if defined( WIN32 ) && !defined ETIMEDOUT
237 #  define ETIMEDOUT 10060 /* This is the value in winsock.h. */
238 #endif
239
240 /*****************************************************************************
241  * Function definitions
242  *****************************************************************************/
243 VLC_API void vlc_mutex_init( vlc_mutex_t * );
244 VLC_API void vlc_mutex_init_recursive( vlc_mutex_t * );
245 VLC_API void vlc_mutex_destroy( vlc_mutex_t * );
246 VLC_API void vlc_mutex_lock( vlc_mutex_t * );
247 VLC_API int vlc_mutex_trylock( vlc_mutex_t * ) VLC_USED;
248 VLC_API void vlc_mutex_unlock( vlc_mutex_t * );
249 VLC_API void vlc_cond_init( vlc_cond_t * );
250 VLC_API void vlc_cond_init_daytime( vlc_cond_t * );
251 VLC_API void vlc_cond_destroy( vlc_cond_t * );
252 VLC_API void vlc_cond_signal(vlc_cond_t *);
253 VLC_API void vlc_cond_broadcast(vlc_cond_t *);
254 VLC_API void vlc_cond_wait(vlc_cond_t *, vlc_mutex_t *);
255 VLC_API int vlc_cond_timedwait(vlc_cond_t *, vlc_mutex_t *, mtime_t);
256 VLC_API void vlc_sem_init(vlc_sem_t *, unsigned);
257 VLC_API void vlc_sem_destroy(vlc_sem_t *);
258 VLC_API int vlc_sem_post(vlc_sem_t *);
259 VLC_API void vlc_sem_wait(vlc_sem_t *);
260
261 VLC_API void vlc_rwlock_init(vlc_rwlock_t *);
262 VLC_API void vlc_rwlock_destroy(vlc_rwlock_t *);
263 VLC_API void vlc_rwlock_rdlock(vlc_rwlock_t *);
264 VLC_API void vlc_rwlock_wrlock(vlc_rwlock_t *);
265 VLC_API void vlc_rwlock_unlock(vlc_rwlock_t *);
266 VLC_API int vlc_threadvar_create(vlc_threadvar_t * , void (*) (void *) );
267 VLC_API void vlc_threadvar_delete(vlc_threadvar_t *);
268 VLC_API int vlc_threadvar_set(vlc_threadvar_t, void *);
269 VLC_API void * vlc_threadvar_get(vlc_threadvar_t);
270
271 VLC_API int vlc_clone(vlc_thread_t *, void * (*) (void *), void *, int) VLC_USED;
272 VLC_API void vlc_cancel(vlc_thread_t);
273 VLC_API void vlc_join(vlc_thread_t, void **);
274 VLC_API void vlc_control_cancel (int cmd, ...);
275
276 VLC_API mtime_t mdate(void);
277 VLC_API void mwait(mtime_t deadline);
278 VLC_API void msleep(mtime_t delay);
279
280 #define VLC_HARD_MIN_SLEEP   10000 /* 10 milliseconds = 1 tick at 100Hz */
281 #define VLC_SOFT_MIN_SLEEP 9000000 /* 9 seconds */
282
283 #if VLC_GCC_VERSION(4,3)
284 /* Linux has 100, 250, 300 or 1000Hz
285  *
286  * HZ=100 by default on FreeBSD, but some architectures use a 1000Hz timer
287  */
288
289 static
290 __attribute__((unused))
291 __attribute__((noinline))
292 __attribute__((error("sorry, cannot sleep for such short a time")))
293 mtime_t impossible_delay( mtime_t delay )
294 {
295     (void) delay;
296     return VLC_HARD_MIN_SLEEP;
297 }
298
299 static
300 __attribute__((unused))
301 __attribute__((noinline))
302 __attribute__((warning("use proper event handling instead of short delay")))
303 mtime_t harmful_delay( mtime_t delay )
304 {
305     return delay;
306 }
307
308 # define check_delay( d ) \
309     ((__builtin_constant_p(d < VLC_HARD_MIN_SLEEP) \
310    && (d < VLC_HARD_MIN_SLEEP)) \
311        ? impossible_delay(d) \
312        : ((__builtin_constant_p(d < VLC_SOFT_MIN_SLEEP) \
313        && (d < VLC_SOFT_MIN_SLEEP)) \
314            ? harmful_delay(d) \
315            : d))
316
317 static
318 __attribute__((unused))
319 __attribute__((noinline))
320 __attribute__((error("deadlines can not be constant")))
321 mtime_t impossible_deadline( mtime_t deadline )
322 {
323     return deadline;
324 }
325
326 # define check_deadline( d ) \
327     (__builtin_constant_p(d) ? impossible_deadline(d) : d)
328 #else
329 # define check_delay(d) (d)
330 # define check_deadline(d) (d)
331 #endif
332
333 #define msleep(d) msleep(check_delay(d))
334 #define mwait(d) mwait(check_deadline(d))
335
336 VLC_API int vlc_timer_create(vlc_timer_t *, void (*) (void *), void *) VLC_USED;
337 VLC_API void vlc_timer_destroy(vlc_timer_t);
338 VLC_API void vlc_timer_schedule(vlc_timer_t, bool, mtime_t, mtime_t);
339 VLC_API unsigned vlc_timer_getoverrun(vlc_timer_t) VLC_USED;
340
341 VLC_API unsigned vlc_GetCPUCount(void);
342
343 #ifndef LIBVLC_USE_PTHREAD_CANCEL
344 enum {
345     VLC_CLEANUP_PUSH,
346     VLC_CLEANUP_POP,
347 };
348 #endif
349
350 VLC_API int vlc_savecancel(void);
351 VLC_API void vlc_restorecancel(int state);
352 VLC_API void vlc_testcancel(void);
353
354 #if defined (LIBVLC_USE_PTHREAD_CANCEL) || defined(__ANDROID__)
355 /**
356  * Registers a new procedure to run if the thread is cancelled (or otherwise
357  * exits prematurely). Any call to vlc_cleanup_push() <b>must</b> paired with a
358  * call to either vlc_cleanup_pop() or vlc_cleanup_run(). Branching into or out
359  * of the block between these two function calls is not allowed (read: it will
360  * likely crash the whole process). If multiple procedures are registered,
361  * they are handled in last-in first-out order.
362  *
363  * @param routine procedure to call if the thread ends
364  * @param arg argument for the procedure
365  */
366 # define vlc_cleanup_push( routine, arg ) pthread_cleanup_push (routine, arg)
367
368 /**
369  * Removes a cleanup procedure that was previously registered with
370  * vlc_cleanup_push().
371  */
372 # define vlc_cleanup_pop( ) pthread_cleanup_pop (0)
373
374 /**
375  * Removes a cleanup procedure that was previously registered with
376  * vlc_cleanup_push(), and executes it.
377  */
378 # define vlc_cleanup_run( ) pthread_cleanup_pop (1)
379 #else
380 typedef struct vlc_cleanup_t vlc_cleanup_t;
381
382 struct vlc_cleanup_t
383 {
384     vlc_cleanup_t *next;
385     void         (*proc) (void *);
386     void          *data;
387 };
388
389 /* This macros opens a code block on purpose. This is needed for multiple
390  * calls within a single function. This also prevent Win32 developers from
391  * writing code that would break on POSIX (POSIX opens a block as well). */
392 # define vlc_cleanup_push( routine, arg ) \
393     do { \
394         vlc_cleanup_t vlc_cleanup_data = { NULL, routine, arg, }; \
395         vlc_control_cancel (VLC_CLEANUP_PUSH, &vlc_cleanup_data)
396
397 # define vlc_cleanup_pop( ) \
398         vlc_control_cancel (VLC_CLEANUP_POP); \
399     } while (0)
400
401 # define vlc_cleanup_run( ) \
402         vlc_control_cancel (VLC_CLEANUP_POP); \
403         vlc_cleanup_data.proc (vlc_cleanup_data.data); \
404     } while (0)
405 #endif /* LIBVLC_USE_PTHREAD_CANCEL || __ANDROID__ */
406
407 #if !defined (LIBVLC_USE_PTHREAD_CANCEL)
408 /* poll() with cancellation */
409 static inline int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout)
410 {
411     vlc_testcancel ();
412
413     while (timeout > 50)
414     {
415         int val = poll (fds, nfds, timeout);
416         if (val != 0)
417             return val;
418         timeout -= 50;
419         vlc_testcancel ();
420     }
421
422     return poll (fds, nfds, timeout);
423 }
424 # define poll(u,n,t) vlc_poll(u, n, t)
425
426 #endif /* LIBVLC_USE_PTHREAD_CANCEL */
427
428 static inline void vlc_cleanup_lock (void *lock)
429 {
430     vlc_mutex_unlock ((vlc_mutex_t *)lock);
431 }
432 #define mutex_cleanup_push( lock ) vlc_cleanup_push (vlc_cleanup_lock, lock)
433
434 # if defined (_POSIX_SPIN_LOCKS) && ((_POSIX_SPIN_LOCKS - 0) > 0)
435 typedef pthread_spinlock_t vlc_spinlock_t;
436
437 /**
438  * Initializes a spinlock.
439  */
440 static inline void vlc_spin_init (vlc_spinlock_t *spin)
441 {
442     if (pthread_spin_init (spin, PTHREAD_PROCESS_PRIVATE))
443         abort ();
444 }
445
446 /**
447  * Acquires a spinlock.
448  */
449 static inline void vlc_spin_lock (vlc_spinlock_t *spin)
450 {
451     pthread_spin_lock (spin);
452 }
453
454 /**
455  * Releases a spinlock.
456  */
457 static inline void vlc_spin_unlock (vlc_spinlock_t *spin)
458 {
459     pthread_spin_unlock (spin);
460 }
461
462 /**
463  * Deinitializes a spinlock.
464  */
465 static inline void vlc_spin_destroy (vlc_spinlock_t *spin)
466 {
467     pthread_spin_destroy (spin);
468 }
469
470 #elif defined (WIN32)
471
472 typedef CRITICAL_SECTION vlc_spinlock_t;
473
474 /**
475  * Initializes a spinlock.
476  */
477 static inline void vlc_spin_init (vlc_spinlock_t *spin)
478 {
479     if (!InitializeCriticalSectionAndSpinCount(spin, 4000))
480         abort ();
481 }
482
483 /**
484  * Acquires a spinlock.
485  */
486 static inline void vlc_spin_lock (vlc_spinlock_t *spin)
487 {
488     EnterCriticalSection(spin);
489 }
490
491 /**
492  * Releases a spinlock.
493  */
494 static inline void vlc_spin_unlock (vlc_spinlock_t *spin)
495 {
496     LeaveCriticalSection(spin);
497 }
498
499 /**
500  * Deinitializes a spinlock.
501  */
502 static inline void vlc_spin_destroy (vlc_spinlock_t *spin)
503 {
504     DeleteCriticalSection(spin);
505 }
506
507 #else
508
509 /* Fallback to plain mutexes if spinlocks are not available */
510 typedef vlc_mutex_t vlc_spinlock_t;
511
512 static inline void vlc_spin_init (vlc_spinlock_t *spin)
513 {
514     vlc_mutex_init (spin);
515 }
516
517 # define vlc_spin_lock    vlc_mutex_lock
518 # define vlc_spin_unlock  vlc_mutex_unlock
519 # define vlc_spin_destroy vlc_mutex_destroy
520 #endif
521
522 /**
523  * Issues a full memory barrier.
524  */
525 #if defined (__APPLE__)
526 # include <libkern/OSAtomic.h> /* OSMemoryBarrier() */
527 #endif
528 static inline void barrier (void)
529 {
530 #if defined (__GNUC__) && !defined (__APPLE__) && \
531             ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
532     __sync_synchronize ();
533 #elif defined(__APPLE__)
534     OSMemoryBarrier ();
535 #elif defined(__powerpc__)
536     asm volatile ("sync":::"memory");
537 #elif 0 // defined(__i386__) /*  Requires SSE2 support */
538     asm volatile ("mfence":::"memory");
539 #else
540     vlc_spinlock_t spin;
541     vlc_spin_init (&spin);
542     vlc_spin_lock (&spin);
543     vlc_spin_unlock (&spin);
544     vlc_spin_destroy (&spin);
545 #endif
546 }
547
548 #ifdef __cplusplus
549 /**
550  * Helper C++ class to lock a mutex.
551  * The mutex is locked when the object is created, and unlocked when the object
552  * is destroyed.
553  */
554 class vlc_mutex_locker
555 {
556     private:
557         vlc_mutex_t *lock;
558     public:
559         vlc_mutex_locker (vlc_mutex_t *m) : lock (m)
560         {
561             vlc_mutex_lock (lock);
562         }
563
564         ~vlc_mutex_locker (void)
565         {
566             vlc_mutex_unlock (lock);
567         }
568 };
569 #endif
570
571 enum {
572    VLC_AVCODEC_MUTEX = 0,
573    VLC_GCRYPT_MUTEX,
574    VLC_XLIB_MUTEX,
575    VLC_MOSAIC_MUTEX,
576    VLC_HIGHLIGHT_MUTEX,
577    VLC_ATOMIC_MUTEX,
578    /* Insert new entry HERE */
579    VLC_MAX_MUTEX
580 };
581
582 VLC_API void vlc_global_mutex( unsigned, bool );
583 #define vlc_global_lock( n ) vlc_global_mutex( n, true )
584 #define vlc_global_unlock( n ) vlc_global_mutex( n, false )
585
586 #endif /* !_VLC_THREADS_H */