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 the VideoLAN team
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
00014  * it under the terms of the GNU General Public License as published by
00015  * the Free Software Foundation; either version 2 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 General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, 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 #   include <errno.h>                                           /* WinCE API */
00039 #elif defined( WIN32 )
00040 #   include <process.h>                                         /* Win32 API */
00041 #   include <errno.h>
00042 
00043 #else                                         /* pthreads (like Linux & BSD) */
00044 #   define LIBVLC_USE_PTHREAD 1
00045 #   define LIBVLC_USE_PTHREAD_CANCEL 1
00046 #   define _APPLE_C_SOURCE    1 /* Proper pthread semantics on OSX */
00047 
00048 #   include <stdlib.h> /* lldiv_t definition (only in C99) */
00049 #   include <unistd.h> /* _POSIX_SPIN_LOCKS */
00050 #   include <pthread.h>
00051 #   include <semaphore.h>
00052 #   include <time.h>
00053 
00054 #endif
00055 
00056 /*****************************************************************************
00057  * Constants
00058  *****************************************************************************/
00059 
00060 /* Thread priorities */
00061 #ifdef __APPLE__
00062 #   define VLC_THREAD_PRIORITY_LOW      0
00063 #   define VLC_THREAD_PRIORITY_INPUT   22
00064 #   define VLC_THREAD_PRIORITY_AUDIO   22
00065 #   define VLC_THREAD_PRIORITY_VIDEO    0
00066 #   define VLC_THREAD_PRIORITY_OUTPUT  22
00067 #   define VLC_THREAD_PRIORITY_HIGHEST 22
00068 
00069 #elif defined(LIBVLC_USE_PTHREAD)
00070 #   define VLC_THREAD_PRIORITY_LOW      0
00071 #   define VLC_THREAD_PRIORITY_INPUT   10
00072 #   define VLC_THREAD_PRIORITY_AUDIO    5
00073 #   define VLC_THREAD_PRIORITY_VIDEO    0
00074 #   define VLC_THREAD_PRIORITY_OUTPUT  15
00075 #   define VLC_THREAD_PRIORITY_HIGHEST 20
00076 
00077 #elif defined(WIN32) || defined(UNDER_CE)
00078 /* Define different priorities for WinNT/2K/XP and Win9x/Me */
00079 #   define VLC_THREAD_PRIORITY_LOW 0
00080 #   define VLC_THREAD_PRIORITY_INPUT \
00081         THREAD_PRIORITY_ABOVE_NORMAL
00082 #   define VLC_THREAD_PRIORITY_AUDIO \
00083         THREAD_PRIORITY_HIGHEST
00084 #   define VLC_THREAD_PRIORITY_VIDEO 0
00085 #   define VLC_THREAD_PRIORITY_OUTPUT \
00086         THREAD_PRIORITY_ABOVE_NORMAL
00087 #   define VLC_THREAD_PRIORITY_HIGHEST \
00088         THREAD_PRIORITY_TIME_CRITICAL
00089 
00090 #else
00091 #   define VLC_THREAD_PRIORITY_LOW 0
00092 #   define VLC_THREAD_PRIORITY_INPUT 0
00093 #   define VLC_THREAD_PRIORITY_AUDIO 0
00094 #   define VLC_THREAD_PRIORITY_VIDEO 0
00095 #   define VLC_THREAD_PRIORITY_OUTPUT 0
00096 #   define VLC_THREAD_PRIORITY_HIGHEST 0
00097 
00098 #endif
00099 
00100 /*****************************************************************************
00101  * Type definitions
00102  *****************************************************************************/
00103 
00104 #if defined (LIBVLC_USE_PTHREAD)
00105 typedef pthread_t       vlc_thread_t;
00106 typedef pthread_mutex_t vlc_mutex_t;
00107 #define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER
00108 typedef pthread_cond_t  vlc_cond_t;
00109 typedef sem_t           vlc_sem_t;
00110 typedef pthread_rwlock_t vlc_rwlock_t;
00111 typedef pthread_key_t   vlc_threadvar_t;
00112 typedef struct vlc_timer *vlc_timer_t;
00113 
00114 #elif defined( WIN32 )
00115 #if !defined( UNDER_CE )
00116 typedef HANDLE vlc_thread_t;
00117 #else
00118 typedef struct
00119 {
00120     HANDLE handle;
00121     HANDLE cancel_event;
00122 } *vlc_thread_t;
00123 #endif
00124 
00125 typedef struct
00126 {
00127     LONG initialized;
00128     CRITICAL_SECTION mutex;
00129 } vlc_mutex_t;
00130 #define VLC_STATIC_MUTEX { 0, }
00131 
00132 typedef HANDLE  vlc_cond_t;
00133 typedef HANDLE  vlc_sem_t;
00134 
00135 typedef struct
00136 {
00137     vlc_mutex_t   mutex;
00138     vlc_cond_t    read_wait;
00139     vlc_cond_t    write_wait;
00140     unsigned long readers;
00141     unsigned long writers;
00142     DWORD         writer;
00143 } vlc_rwlock_t;
00144 
00145 typedef DWORD   vlc_threadvar_t;
00146 typedef struct vlc_timer *vlc_timer_t;
00147 #endif
00148 
00149 #if defined( WIN32 ) && !defined ETIMEDOUT
00150 #  define ETIMEDOUT 10060 /* This is the value in winsock.h. */
00151 #endif
00152 
00153 /*****************************************************************************
00154  * Function definitions
00155  *****************************************************************************/
00156 VLC_EXPORT( void, vlc_mutex_init,    ( vlc_mutex_t * ) );
00157 VLC_EXPORT( void, vlc_mutex_init_recursive, ( vlc_mutex_t * ) );
00158 VLC_EXPORT( void, vlc_mutex_destroy, ( vlc_mutex_t * ) );
00159 VLC_EXPORT( void, vlc_mutex_lock, ( vlc_mutex_t * ) );
00160 VLC_EXPORT( int,  vlc_mutex_trylock, ( vlc_mutex_t * ) LIBVLC_USED );
00161 VLC_EXPORT( void, vlc_mutex_unlock, ( vlc_mutex_t * ) );
00162 VLC_EXPORT( void, vlc_cond_init,     ( vlc_cond_t * ) );
00163 VLC_EXPORT( void, vlc_cond_destroy,  ( vlc_cond_t * ) );
00164 VLC_EXPORT( void, vlc_cond_signal, (vlc_cond_t *) );
00165 VLC_EXPORT( void, vlc_cond_broadcast, (vlc_cond_t *) );
00166 VLC_EXPORT( void, vlc_cond_wait, (vlc_cond_t *, vlc_mutex_t *) );
00167 VLC_EXPORT( int,  vlc_cond_timedwait, (vlc_cond_t *, vlc_mutex_t *, mtime_t) );
00168 VLC_EXPORT( void, vlc_sem_init, (vlc_sem_t *, unsigned) );
00169 VLC_EXPORT( void, vlc_sem_destroy, (vlc_sem_t *) );
00170 VLC_EXPORT( int,  vlc_sem_post, (vlc_sem_t *) );
00171 VLC_EXPORT( void, vlc_sem_wait, (vlc_sem_t *) );
00172 
00173 VLC_EXPORT( void, vlc_rwlock_init, (vlc_rwlock_t *) );
00174 VLC_EXPORT( void, vlc_rwlock_destroy, (vlc_rwlock_t *) );
00175 VLC_EXPORT( void, vlc_rwlock_rdlock, (vlc_rwlock_t *) );
00176 VLC_EXPORT( void, vlc_rwlock_wrlock, (vlc_rwlock_t *) );
00177 VLC_EXPORT( void, vlc_rwlock_unlock, (vlc_rwlock_t *) );
00178 VLC_EXPORT( int, vlc_threadvar_create, (vlc_threadvar_t * , void (*) (void *) ) );
00179 VLC_EXPORT( void, vlc_threadvar_delete, (vlc_threadvar_t *) );
00180 VLC_EXPORT( int, vlc_threadvar_set, (vlc_threadvar_t, void *) );
00181 VLC_EXPORT( void *, vlc_threadvar_get, (vlc_threadvar_t) );
00182 VLC_EXPORT( int,  vlc_thread_create, ( vlc_object_t *, const char *, int, const char *, void * ( * ) ( vlc_object_t * ), int ) LIBVLC_USED );
00183 VLC_EXPORT( int,  __vlc_thread_set_priority, ( vlc_object_t *, const char *, int, int ) );
00184 VLC_EXPORT( void, __vlc_thread_join,   ( vlc_object_t * ) );
00185 
00186 VLC_EXPORT( int, vlc_clone, (vlc_thread_t *, void * (*) (void *), void *, int) LIBVLC_USED );
00187 VLC_EXPORT( void, vlc_cancel, (vlc_thread_t) );
00188 VLC_EXPORT( void, vlc_join, (vlc_thread_t, void **) );
00189 VLC_EXPORT (void, vlc_control_cancel, (int cmd, ...));
00190 
00191 VLC_EXPORT( int, vlc_timer_create, (vlc_timer_t *, void (*) (void *), void *) LIBVLC_USED );
00192 VLC_EXPORT( void, vlc_timer_destroy, (vlc_timer_t) );
00193 VLC_EXPORT( void, vlc_timer_schedule, (vlc_timer_t, bool, mtime_t, mtime_t) );
00194 VLC_EXPORT( unsigned, vlc_timer_getoverrun, (vlc_timer_t) LIBVLC_USED );
00195 
00196 #ifndef LIBVLC_USE_PTHREAD_CANCEL
00197 enum {
00198     VLC_DO_CANCEL,
00199     VLC_CLEANUP_PUSH,
00200     VLC_CLEANUP_POP,
00201 };
00202 #endif
00203 
00204 VLC_EXPORT( int, vlc_savecancel, (void) );
00205 VLC_EXPORT( void, vlc_restorecancel, (int state) );
00206 VLC_EXPORT( void, vlc_testcancel, (void) );
00207 
00208 #if defined (LIBVLC_USE_PTHREAD_CANCEL)
00209 /**
00210  * Registers a new procedure to run if the thread is cancelled (or otherwise
00211  * exits prematurely). Any call to vlc_cleanup_push() <b>must</b> paired with a
00212  * call to either vlc_cleanup_pop() or vlc_cleanup_run(). Branching into or out
00213  * of the block between these two function calls is not allowed (read: it will
00214  * likely crash the whole process). If multiple procedures are registered,
00215  * they are handled in last-in first-out order.
00216  *
00217  * @param routine procedure to call if the thread ends
00218  * @param arg argument for the procedure
00219  */
00220 # define vlc_cleanup_push( routine, arg ) pthread_cleanup_push (routine, arg)
00221 
00222 /**
00223  * Removes a cleanup procedure that was previously registered with
00224  * vlc_cleanup_push().
00225  */
00226 # define vlc_cleanup_pop( ) pthread_cleanup_pop (0)
00227 
00228 /**
00229  * Removes a cleanup procedure that was previously registered with
00230  * vlc_cleanup_push(), and executes it.
00231  */
00232 # define vlc_cleanup_run( ) pthread_cleanup_pop (1)
00233 #else
00234 typedef struct vlc_cleanup_t vlc_cleanup_t;
00235 
00236 struct vlc_cleanup_t
00237 {
00238     vlc_cleanup_t *next;
00239     void         (*proc) (void *);
00240     void          *data;
00241 };
00242 
00243 /* This macros opens a code block on purpose. This is needed for multiple
00244  * calls within a single function. This also prevent Win32 developers from
00245  * writing code that would break on POSIX (POSIX opens a block as well). */
00246 # define vlc_cleanup_push( routine, arg ) \
00247     do { \
00248         vlc_cleanup_t vlc_cleanup_data = { NULL, routine, arg, }; \
00249         vlc_control_cancel (VLC_CLEANUP_PUSH, &vlc_cleanup_data)
00250 
00251 # define vlc_cleanup_pop( ) \
00252         vlc_control_cancel (VLC_CLEANUP_POP); \
00253     } while (0)
00254 
00255 # define vlc_cleanup_run( ) \
00256         vlc_control_cancel (VLC_CLEANUP_POP); \
00257         vlc_cleanup_data.proc (vlc_cleanup_data.data); \
00258     } while (0)
00259 
00260 #endif /* LIBVLC_USE_PTHREAD_CANCEL */
00261 
00262 static inline void vlc_cleanup_lock (void *lock)
00263 {
00264     vlc_mutex_unlock ((vlc_mutex_t *)lock);
00265 }
00266 #define mutex_cleanup_push( lock ) vlc_cleanup_push (vlc_cleanup_lock, lock)
00267 
00268 # if defined (_POSIX_SPIN_LOCKS) && ((_POSIX_SPIN_LOCKS - 0) > 0)
00269 typedef pthread_spinlock_t vlc_spinlock_t;
00270 
00271 /**
00272  * Initializes a spinlock.
00273  */
00274 static inline void vlc_spin_init (vlc_spinlock_t *spin)
00275 {
00276     if (pthread_spin_init (spin, PTHREAD_PROCESS_PRIVATE))
00277         abort ();
00278 }
00279 
00280 /**
00281  * Acquires a spinlock.
00282  */
00283 static inline void vlc_spin_lock (vlc_spinlock_t *spin)
00284 {
00285     pthread_spin_lock (spin);
00286 }
00287 
00288 /**
00289  * Releases a spinlock.
00290  */
00291 static inline void vlc_spin_unlock (vlc_spinlock_t *spin)
00292 {
00293     pthread_spin_unlock (spin);
00294 }
00295 
00296 /**
00297  * Deinitializes a spinlock.
00298  */
00299 static inline void vlc_spin_destroy (vlc_spinlock_t *spin)
00300 {
00301     pthread_spin_destroy (spin);
00302 }
00303 
00304 #elif defined (WIN32) && !defined (UNDER_CE)
00305 
00306 typedef CRITICAL_SECTION vlc_spinlock_t;
00307 
00308 /**
00309  * Initializes a spinlock.
00310  */
00311 static inline void vlc_spin_init (vlc_spinlock_t *spin)
00312 {
00313     if (!InitializeCriticalSectionAndSpinCount(spin, 4000))
00314         abort ();
00315 }
00316 
00317 /**
00318  * Acquires a spinlock.
00319  */
00320 static inline void vlc_spin_lock (vlc_spinlock_t *spin)
00321 {
00322     EnterCriticalSection(spin);
00323 }
00324 
00325 /**
00326  * Releases a spinlock.
00327  */
00328 static inline void vlc_spin_unlock (vlc_spinlock_t *spin)
00329 {
00330     LeaveCriticalSection(spin);
00331 }
00332 
00333 /**
00334  * Deinitializes a spinlock.
00335  */
00336 static inline void vlc_spin_destroy (vlc_spinlock_t *spin)
00337 {
00338     DeleteCriticalSection(spin);
00339 }
00340 
00341 #else
00342 
00343 /* Fallback to plain mutexes if spinlocks are not available */
00344 typedef vlc_mutex_t vlc_spinlock_t;
00345 
00346 static inline void vlc_spin_init (vlc_spinlock_t *spin)
00347 {
00348     vlc_mutex_init (spin);
00349 }
00350 
00351 # define vlc_spin_lock    vlc_mutex_lock
00352 # define vlc_spin_unlock  vlc_mutex_unlock
00353 # define vlc_spin_destroy vlc_mutex_destroy
00354 #endif
00355 
00356 /**
00357  * Issues a full memory barrier.
00358  */
00359 #if defined (__APPLE__)
00360 # include <libkern/OSAtomic.h> /* OSMemoryBarrier() */
00361 #endif
00362 static inline void barrier (void)
00363 {
00364 #if defined (__GNUC__) && !defined (__APPLE__) && \
00365             ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
00366     __sync_synchronize ();
00367 #elif defined(__APPLE__)
00368     OSMemoryBarrier ();
00369 #elif defined(__powerpc__)
00370     asm volatile ("sync":::"memory");
00371 #elif 0 // defined(__i386__) /*  Requires SSE2 support */
00372     asm volatile ("mfence":::"memory");
00373 #else
00374     vlc_spinlock_t spin;
00375     vlc_spin_init (&spin);
00376     vlc_spin_lock (&spin);
00377     vlc_spin_unlock (&spin);
00378     vlc_spin_destroy (&spin);
00379 #endif
00380 }
00381 
00382 /*****************************************************************************
00383  * vlc_thread_create: create a thread
00384  *****************************************************************************/
00385 #define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY )         \
00386     vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, FUNC, PRIORITY )
00387 
00388 /*****************************************************************************
00389  * vlc_thread_set_priority: set the priority of the calling thread
00390  *****************************************************************************/
00391 #define vlc_thread_set_priority( P_THIS, PRIORITY )                         \
00392     __vlc_thread_set_priority( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PRIORITY )
00393 
00394 /*****************************************************************************
00395  * vlc_thread_join: wait until a thread exits
00396  *****************************************************************************/
00397 #define vlc_thread_join( P_THIS )                                           \
00398     __vlc_thread_join( VLC_OBJECT(P_THIS) )
00399 
00400 #ifdef __cplusplus
00401 /**
00402  * Helper C++ class to lock a mutex.
00403  * The mutex is locked when the object is created, and unlocked when the object
00404  * is destroyed.
00405  */
00406 class vlc_mutex_locker
00407 {
00408     private:
00409         vlc_mutex_t *lock;
00410     public:
00411         vlc_mutex_locker (vlc_mutex_t *m) : lock (m)
00412         {
00413             vlc_mutex_lock (lock);
00414         }
00415 
00416         ~vlc_mutex_locker (void)
00417         {
00418             vlc_mutex_unlock (lock);
00419         }
00420 };
00421 #endif
00422 
00423 #endif /* !_VLC_THREADS_H */

Generated on Sun Nov 22 08:05:13 2009 for VLC by  doxygen 1.5.6