vlc_threads.h

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * vlc_threads.h : threads implementation for the VideoLAN client
00003  * This header provides portable declarations for mutexes & conditions
00004  *****************************************************************************
00005  * Copyright (C) 1999, 2002 VLC authors and VideoLAN
00006  * Copyright © 2007-2008 Rémi Denis-Courmont
00007  *
00008  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
00009  *          Samuel Hocevar <sam@via.ecp.fr>
00010  *          Gildas Bazin <gbazin@netcourrier.com>
00011  *          Christophe Massiot <massiot@via.ecp.fr>
00012  *
00013  * This program is free software; you can redistribute it and/or modify it
00014  * under the terms of the GNU Lesser General Public License as published by
00015  * the Free Software Foundation; either version 2.1 of the License, or
00016  * (at your option) any later version.
00017  *
00018  * This program is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00021  * GNU Lesser General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU Lesser General Public License
00024  * along with this program; if not, write to the Free Software Foundation,
00025  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
00026  *****************************************************************************/
00027 
00028 #ifndef VLC_THREADS_H_
00029 #define VLC_THREADS_H_
00030 
00031 /**
00032  * \file
00033  * This file defines structures and functions for handling threads in vlc
00034  *
00035  */
00036 
00037 #if defined( UNDER_CE )
00038 #elif defined( WIN32 )
00039 #   include <process.h>                                         /* Win32 API */
00040 
00041 #elif defined( __OS2__ )                                        /* OS/2 API  */
00042 #   include <errno.h>
00043 
00044 #   define pthread_sigmask  sigprocmask
00045 
00046 #else                                         /* pthreads (like Linux & BSD) */
00047 #   define LIBVLC_USE_PTHREAD 1
00048 #   define LIBVLC_USE_PTHREAD_CANCEL 1
00049 #   define _APPLE_C_SOURCE    1 /* Proper pthread semantics on OSX */
00050 
00051 #   include <unistd.h> /* _POSIX_SPIN_LOCKS */
00052 #   include <pthread.h>
00053 
00054 /* Unnamed POSIX semaphores not supported on Mac OS X, use Mach semaphores instead */
00055 #   if defined (__APPLE__)
00056 #      include <mach/semaphore.h>
00057 #      include <mach/task.h>
00058 #   else
00059 #      include <semaphore.h>
00060 #   endif
00061 
00062 #endif
00063 
00064 /*****************************************************************************
00065  * Constants
00066  *****************************************************************************/
00067 
00068 /* Thread priorities */
00069 #ifdef __APPLE__
00070 #   define VLC_THREAD_PRIORITY_LOW      0
00071 #   define VLC_THREAD_PRIORITY_INPUT   22
00072 #   define VLC_THREAD_PRIORITY_AUDIO   22
00073 #   define VLC_THREAD_PRIORITY_VIDEO    0
00074 #   define VLC_THREAD_PRIORITY_OUTPUT  22
00075 #   define VLC_THREAD_PRIORITY_HIGHEST 22
00076 
00077 #elif defined(LIBVLC_USE_PTHREAD)
00078 #   define VLC_THREAD_PRIORITY_LOW      0
00079 #   define VLC_THREAD_PRIORITY_INPUT   10
00080 #   define VLC_THREAD_PRIORITY_AUDIO    5
00081 #   define VLC_THREAD_PRIORITY_VIDEO    0
00082 #   define VLC_THREAD_PRIORITY_OUTPUT  15
00083 #   define VLC_THREAD_PRIORITY_HIGHEST 20
00084 
00085 #elif defined(WIN32) || defined(UNDER_CE)
00086 /* Define different priorities for WinNT/2K/XP and Win9x/Me */
00087 #   define VLC_THREAD_PRIORITY_LOW 0
00088 #   define VLC_THREAD_PRIORITY_INPUT \
00089         THREAD_PRIORITY_ABOVE_NORMAL
00090 #   define VLC_THREAD_PRIORITY_AUDIO \
00091         THREAD_PRIORITY_HIGHEST
00092 #   define VLC_THREAD_PRIORITY_VIDEO 0
00093 #   define VLC_THREAD_PRIORITY_OUTPUT \
00094         THREAD_PRIORITY_ABOVE_NORMAL
00095 #   define VLC_THREAD_PRIORITY_HIGHEST \
00096         THREAD_PRIORITY_TIME_CRITICAL
00097 
00098 #elif defined(__OS2__)
00099 #   define VLC_THREAD_PRIORITY_LOW      0
00100 #   define VLC_THREAD_PRIORITY_INPUT    MAKESHORT( PRTYD_MAXIMUM / 2, PRTYC_REGULAR )
00101 #   define VLC_THREAD_PRIORITY_AUDIO    MAKESHORT( PRTYD_MAXIMUM, PRTYC_REGULAR )
00102 #   define VLC_THREAD_PRIORITY_VIDEO    0
00103 #   define VLC_THREAD_PRIORITY_OUTPUT   MAKESHORT( PRTYD_MAXIMUM / 2, PRTYC_REGULAR )
00104 #   define VLC_THREAD_PRIORITY_HIGHEST  MAKESHORT( 0, PRTYC_TIMECRITICAL )
00105 
00106 #else
00107 #   define VLC_THREAD_PRIORITY_LOW 0
00108 #   define VLC_THREAD_PRIORITY_INPUT 0
00109 #   define VLC_THREAD_PRIORITY_AUDIO 0
00110 #   define VLC_THREAD_PRIORITY_VIDEO 0
00111 #   define VLC_THREAD_PRIORITY_OUTPUT 0
00112 #   define VLC_THREAD_PRIORITY_HIGHEST 0
00113 
00114 #endif
00115 
00116 /*****************************************************************************
00117  * Type definitions
00118  *****************************************************************************/
00119 
00120 #if defined (LIBVLC_USE_PTHREAD)
00121 typedef pthread_t       vlc_thread_t;
00122 typedef pthread_mutex_t vlc_mutex_t;
00123 #define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER
00124 typedef pthread_cond_t  vlc_cond_t;
00125 #define VLC_STATIC_COND  PTHREAD_COND_INITIALIZER
00126 typedef pthread_rwlock_t vlc_rwlock_t;
00127 #define VLC_STATIC_RWLOCK PTHREAD_RWLOCK_INITIALIZER
00128 typedef pthread_key_t   vlc_threadvar_t;
00129 typedef struct vlc_timer *vlc_timer_t;
00130 
00131 #if defined (__APPLE__)
00132 typedef semaphore_t     vlc_sem_t;
00133 #else
00134 typedef sem_t           vlc_sem_t;
00135 #endif
00136 
00137 #elif defined( WIN32 )
00138 typedef struct vlc_thread *vlc_thread_t;
00139 
00140 typedef struct
00141 {
00142     bool dynamic;
00143     union
00144     {
00145         struct
00146         {
00147             bool locked;
00148             unsigned long contention;
00149         };
00150         CRITICAL_SECTION mutex;
00151     };
00152 } vlc_mutex_t;
00153 #define VLC_STATIC_MUTEX { false, { { false, 0 } } }
00154 
00155 typedef struct
00156 {
00157     HANDLE   handle;
00158     unsigned clock;
00159 } vlc_cond_t;
00160 #define VLC_STATIC_COND { 0, 0 }
00161 
00162 typedef HANDLE  vlc_sem_t;
00163 
00164 typedef struct
00165 {
00166     vlc_mutex_t   mutex;
00167     vlc_cond_t    wait;
00168     unsigned long readers;
00169     DWORD         writer;
00170 } vlc_rwlock_t;
00171 #define VLC_STATIC_RWLOCK \
00172     { VLC_STATIC_MUTEX, VLC_STATIC_COND, 0, 0 }
00173 
00174 typedef struct vlc_threadvar *vlc_threadvar_t;
00175 typedef struct vlc_timer *vlc_timer_t;
00176 
00177 #elif defined( __OS2__ )
00178 typedef struct vlc_thread *vlc_thread_t;
00179 
00180 typedef struct
00181 {
00182     bool dynamic;
00183     union
00184     {
00185         struct
00186         {
00187             bool locked;
00188             unsigned long contention;
00189         };
00190         HMTX hmtx;
00191     };
00192 } vlc_mutex_t;
00193 
00194 #define VLC_STATIC_MUTEX { false, { { false, 0 } } }
00195 
00196 typedef struct
00197 {
00198     HEV      hev;
00199     unsigned clock;
00200 } vlc_cond_t;
00201 
00202 #define VLC_STATIC_COND { 0, 0 }
00203 
00204 typedef struct
00205 {
00206     HEV  hev;
00207     HMTX wait_mutex;
00208     HMTX count_mutex;
00209     int  count;
00210 } vlc_sem_t;
00211 
00212 typedef struct
00213 {
00214     vlc_mutex_t   mutex;
00215     vlc_cond_t    wait;
00216     unsigned long readers;
00217     int           writer;
00218 } vlc_rwlock_t;
00219 #define VLC_STATIC_RWLOCK \
00220     { VLC_STATIC_MUTEX, VLC_STATIC_COND, 0, 0 }
00221 
00222 typedef struct vlc_threadvar *vlc_threadvar_t;
00223 typedef struct vlc_timer *vlc_timer_t;
00224 
00225 #endif
00226 
00227 #if defined( WIN32 ) && !defined ETIMEDOUT
00228 #  define ETIMEDOUT 10060 /* This is the value in winsock.h. */
00229 #endif
00230 
00231 /*****************************************************************************
00232  * Function definitions
00233  *****************************************************************************/
00234 VLC_API void vlc_mutex_init( vlc_mutex_t * );
00235 VLC_API void vlc_mutex_init_recursive( vlc_mutex_t * );
00236 VLC_API void vlc_mutex_destroy( vlc_mutex_t * );
00237 VLC_API void vlc_mutex_lock( vlc_mutex_t * );
00238 VLC_API int vlc_mutex_trylock( vlc_mutex_t * ) VLC_USED;
00239 VLC_API void vlc_mutex_unlock( vlc_mutex_t * );
00240 VLC_API void vlc_cond_init( vlc_cond_t * );
00241 VLC_API void vlc_cond_init_daytime( vlc_cond_t * );
00242 VLC_API void vlc_cond_destroy( vlc_cond_t * );
00243 VLC_API void vlc_cond_signal(vlc_cond_t *);
00244 VLC_API void vlc_cond_broadcast(vlc_cond_t *);
00245 VLC_API void vlc_cond_wait(vlc_cond_t *, vlc_mutex_t *);
00246 VLC_API int vlc_cond_timedwait(vlc_cond_t *, vlc_mutex_t *, mtime_t);
00247 VLC_API void vlc_sem_init(vlc_sem_t *, unsigned);
00248 VLC_API void vlc_sem_destroy(vlc_sem_t *);
00249 VLC_API int vlc_sem_post(vlc_sem_t *);
00250 VLC_API void vlc_sem_wait(vlc_sem_t *);
00251 
00252 VLC_API void vlc_rwlock_init(vlc_rwlock_t *);
00253 VLC_API void vlc_rwlock_destroy(vlc_rwlock_t *);
00254 VLC_API void vlc_rwlock_rdlock(vlc_rwlock_t *);
00255 VLC_API void vlc_rwlock_wrlock(vlc_rwlock_t *);
00256 VLC_API void vlc_rwlock_unlock(vlc_rwlock_t *);
00257 VLC_API int vlc_threadvar_create(vlc_threadvar_t * , void (*) (void *) );
00258 VLC_API void vlc_threadvar_delete(vlc_threadvar_t *);
00259 VLC_API int vlc_threadvar_set(vlc_threadvar_t, void *);
00260 VLC_API void * vlc_threadvar_get(vlc_threadvar_t);
00261 
00262 VLC_API int vlc_clone(vlc_thread_t *, void * (*) (void *), void *, int) VLC_USED;
00263 VLC_API void vlc_cancel(vlc_thread_t);
00264 VLC_API void vlc_join(vlc_thread_t, void **);
00265 VLC_API void vlc_control_cancel (int cmd, ...);
00266 
00267 VLC_API mtime_t mdate(void);
00268 VLC_API void mwait(mtime_t deadline);
00269 VLC_API void msleep(mtime_t delay);
00270 
00271 #define VLC_HARD_MIN_SLEEP   10000 /* 10 milliseconds = 1 tick at 100Hz */
00272 #define VLC_SOFT_MIN_SLEEP 9000000 /* 9 seconds */
00273 
00274 #if VLC_GCC_VERSION(4,3)
00275 /* Linux has 100, 250, 300 or 1000Hz
00276  *
00277  * HZ=100 by default on FreeBSD, but some architectures use a 1000Hz timer
00278  */
00279 
00280 static
00281 __attribute__((unused))
00282 __attribute__((noinline))
00283 __attribute__((error("sorry, cannot sleep for such short a time")))
00284 mtime_t impossible_delay( mtime_t delay )
00285 {
00286     (void) delay;
00287     return VLC_HARD_MIN_SLEEP;
00288 }
00289 
00290 static
00291 __attribute__((unused))
00292 __attribute__((noinline))
00293 __attribute__((warning("use proper event handling instead of short delay")))
00294 mtime_t harmful_delay( mtime_t delay )
00295 {
00296     return delay;
00297 }
00298 
00299 # define check_delay( d ) \
00300     ((__builtin_constant_p(d < VLC_HARD_MIN_SLEEP) \
00301    && (d < VLC_HARD_MIN_SLEEP)) \
00302        ? impossible_delay(d) \
00303        : ((__builtin_constant_p(d < VLC_SOFT_MIN_SLEEP) \
00304        && (d < VLC_SOFT_MIN_SLEEP)) \
00305            ? harmful_delay(d) \
00306            : d))
00307 
00308 static
00309 __attribute__((unused))
00310 __attribute__((noinline))
00311 __attribute__((error("deadlines can not be constant")))
00312 mtime_t impossible_deadline( mtime_t deadline )
00313 {
00314     return deadline;
00315 }
00316 
00317 # define check_deadline( d ) \
00318     (__builtin_constant_p(d) ? impossible_deadline(d) : d)
00319 #else
00320 # define check_delay(d) (d)
00321 # define check_deadline(d) (d)
00322 #endif
00323 
00324 #define msleep(d) msleep(check_delay(d))
00325 #define mwait(d) mwait(check_deadline(d))
00326 
00327 VLC_API int vlc_timer_create(vlc_timer_t *, void (*) (void *), void *) VLC_USED;
00328 VLC_API void vlc_timer_destroy(vlc_timer_t);
00329 VLC_API void vlc_timer_schedule(vlc_timer_t, bool, mtime_t, mtime_t);
00330 VLC_API unsigned vlc_timer_getoverrun(vlc_timer_t) VLC_USED;
00331 
00332 VLC_API unsigned vlc_GetCPUCount(void);
00333 
00334 #ifndef LIBVLC_USE_PTHREAD_CANCEL
00335 enum {
00336     VLC_CLEANUP_PUSH,
00337     VLC_CLEANUP_POP,
00338 };
00339 #endif
00340 
00341 VLC_API int vlc_savecancel(void);
00342 VLC_API void vlc_restorecancel(int state);
00343 VLC_API void vlc_testcancel(void);
00344 
00345 #if defined (LIBVLC_USE_PTHREAD_CANCEL)
00346 /**
00347  * Registers a new procedure to run if the thread is cancelled (or otherwise
00348  * exits prematurely). Any call to vlc_cleanup_push() <b>must</b> paired with a
00349  * call to either vlc_cleanup_pop() or vlc_cleanup_run(). Branching into or out
00350  * of the block between these two function calls is not allowed (read: it will
00351  * likely crash the whole process). If multiple procedures are registered,
00352  * they are handled in last-in first-out order.
00353  *
00354  * @param routine procedure to call if the thread ends
00355  * @param arg argument for the procedure
00356  */
00357 # define vlc_cleanup_push( routine, arg ) pthread_cleanup_push (routine, arg)
00358 
00359 /**
00360  * Removes a cleanup procedure that was previously registered with
00361  * vlc_cleanup_push().
00362  */
00363 # define vlc_cleanup_pop( ) pthread_cleanup_pop (0)
00364 
00365 /**
00366  * Removes a cleanup procedure that was previously registered with
00367  * vlc_cleanup_push(), and executes it.
00368  */
00369 # define vlc_cleanup_run( ) pthread_cleanup_pop (1)
00370 #else
00371 typedef struct vlc_cleanup_t vlc_cleanup_t;
00372 
00373 struct vlc_cleanup_t
00374 {
00375     vlc_cleanup_t *next;
00376     void         (*proc) (void *);
00377     void          *data;
00378 };
00379 
00380 /* This macros opens a code block on purpose. This is needed for multiple
00381  * calls within a single function. This also prevent Win32 developers from
00382  * writing code that would break on POSIX (POSIX opens a block as well). */
00383 # define vlc_cleanup_push( routine, arg ) \
00384     do { \
00385         vlc_cleanup_t vlc_cleanup_data = { NULL, routine, arg, }; \
00386         vlc_control_cancel (VLC_CLEANUP_PUSH, &vlc_cleanup_data)
00387 
00388 # define vlc_cleanup_pop( ) \
00389         vlc_control_cancel (VLC_CLEANUP_POP); \
00390     } while (0)
00391 
00392 # define vlc_cleanup_run( ) \
00393         vlc_control_cancel (VLC_CLEANUP_POP); \
00394         vlc_cleanup_data.proc (vlc_cleanup_data.data); \
00395     } while (0)
00396 
00397 /* poll() with cancellation */
00398 static inline int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout)
00399 {
00400     vlc_testcancel ();
00401 
00402     while (timeout > 50)
00403     {
00404         int val = poll (fds, nfds, timeout);
00405         if (val != 0)
00406             return val;
00407         timeout -= 50;
00408         vlc_testcancel ();
00409     }
00410 
00411     return poll (fds, nfds, timeout);
00412 }
00413 # define poll(u,n,t) vlc_poll(u, n, t)
00414 
00415 #endif /* LIBVLC_USE_PTHREAD_CANCEL */
00416 
00417 static inline void vlc_cleanup_lock (void *lock)
00418 {
00419     vlc_mutex_unlock ((vlc_mutex_t *)lock);
00420 }
00421 #define mutex_cleanup_push( lock ) vlc_cleanup_push (vlc_cleanup_lock, lock)
00422 
00423 # if defined (_POSIX_SPIN_LOCKS) && ((_POSIX_SPIN_LOCKS - 0) > 0)
00424 typedef pthread_spinlock_t vlc_spinlock_t;
00425 
00426 /**
00427  * Initializes a spinlock.
00428  */
00429 static inline void vlc_spin_init (vlc_spinlock_t *spin)
00430 {
00431     if (pthread_spin_init (spin, PTHREAD_PROCESS_PRIVATE))
00432         abort ();
00433 }
00434 
00435 /**
00436  * Acquires a spinlock.
00437  */
00438 static inline void vlc_spin_lock (vlc_spinlock_t *spin)
00439 {
00440     pthread_spin_lock (spin);
00441 }
00442 
00443 /**
00444  * Releases a spinlock.
00445  */
00446 static inline void vlc_spin_unlock (vlc_spinlock_t *spin)
00447 {
00448     pthread_spin_unlock (spin);
00449 }
00450 
00451 /**
00452  * Deinitializes a spinlock.
00453  */
00454 static inline void vlc_spin_destroy (vlc_spinlock_t *spin)
00455 {
00456     pthread_spin_destroy (spin);
00457 }
00458 
00459 #elif defined (WIN32) && !defined (UNDER_CE)
00460 
00461 typedef CRITICAL_SECTION vlc_spinlock_t;
00462 
00463 /**
00464  * Initializes a spinlock.
00465  */
00466 static inline void vlc_spin_init (vlc_spinlock_t *spin)
00467 {
00468     if (!InitializeCriticalSectionAndSpinCount(spin, 4000))
00469         abort ();
00470 }
00471 
00472 /**
00473  * Acquires a spinlock.
00474  */
00475 static inline void vlc_spin_lock (vlc_spinlock_t *spin)
00476 {
00477     EnterCriticalSection(spin);
00478 }
00479 
00480 /**
00481  * Releases a spinlock.
00482  */
00483 static inline void vlc_spin_unlock (vlc_spinlock_t *spin)
00484 {
00485     LeaveCriticalSection(spin);
00486 }
00487 
00488 /**
00489  * Deinitializes a spinlock.
00490  */
00491 static inline void vlc_spin_destroy (vlc_spinlock_t *spin)
00492 {
00493     DeleteCriticalSection(spin);
00494 }
00495 
00496 #else
00497 
00498 /* Fallback to plain mutexes if spinlocks are not available */
00499 typedef vlc_mutex_t vlc_spinlock_t;
00500 
00501 static inline void vlc_spin_init (vlc_spinlock_t *spin)
00502 {
00503     vlc_mutex_init (spin);
00504 }
00505 
00506 # define vlc_spin_lock    vlc_mutex_lock
00507 # define vlc_spin_unlock  vlc_mutex_unlock
00508 # define vlc_spin_destroy vlc_mutex_destroy
00509 #endif
00510 
00511 /**
00512  * Issues a full memory barrier.
00513  */
00514 #if defined (__APPLE__)
00515 # include <libkern/OSAtomic.h> /* OSMemoryBarrier() */
00516 #endif
00517 static inline void barrier (void)
00518 {
00519 #if defined (__GNUC__) && !defined (__APPLE__) && \
00520             ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
00521     __sync_synchronize ();
00522 #elif defined(__APPLE__)
00523     OSMemoryBarrier ();
00524 #elif defined(__powerpc__)
00525     asm volatile ("sync":::"memory");
00526 #elif 0 // defined(__i386__) /*  Requires SSE2 support */
00527     asm volatile ("mfence":::"memory");
00528 #else
00529     vlc_spinlock_t spin;
00530     vlc_spin_init (&spin);
00531     vlc_spin_lock (&spin);
00532     vlc_spin_unlock (&spin);
00533     vlc_spin_destroy (&spin);
00534 #endif
00535 }
00536 
00537 #ifdef __cplusplus
00538 /**
00539  * Helper C++ class to lock a mutex.
00540  * The mutex is locked when the object is created, and unlocked when the object
00541  * is destroyed.
00542  */
00543 class vlc_mutex_locker
00544 {
00545     private:
00546         vlc_mutex_t *lock;
00547     public:
00548         vlc_mutex_locker (vlc_mutex_t *m) : lock (m)
00549         {
00550             vlc_mutex_lock (lock);
00551         }
00552 
00553         ~vlc_mutex_locker (void)
00554         {
00555             vlc_mutex_unlock (lock);
00556         }
00557 };
00558 #endif
00559 
00560 enum {
00561    VLC_AVCODEC_MUTEX = 0,
00562    VLC_GCRYPT_MUTEX,
00563    VLC_XLIB_MUTEX,
00564    VLC_MOSAIC_MUTEX,
00565    VLC_HIGHLIGHT_MUTEX,
00566    /* Insert new entry HERE */
00567    VLC_MAX_MUTEX
00568 };
00569 
00570 VLC_API void vlc_global_mutex( unsigned, bool );
00571 #define vlc_global_lock( n ) vlc_global_mutex( n, true )
00572 #define vlc_global_unlock( n ) vlc_global_mutex( n, false )
00573 
00574 #endif /* !_VLC_THREADS_H */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines