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