Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

vlc_threads_funcs.h

00001 /*****************************************************************************
00002  * vlc_threads_funcs.h : threads implementation for the VideoLAN client
00003  * This header provides a portable threads implementation.
00004  *****************************************************************************
00005  * Copyright (C) 1999, 2002 the VideoLAN team
00006  * $Id: vlc_threads_funcs.h 11664 2005-07-09 06:17:09Z courmisch $
00007  *
00008  * Authors: Jean-Marc Dressler <[email protected]>
00009  *          Samuel Hocevar <[email protected]>
00010  *          Gildas Bazin <[email protected]>
00011  *          Christophe Massiot <[email protected]>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00026  *****************************************************************************/
00027 
00028 /*****************************************************************************
00029  * Function definitions
00030  *****************************************************************************/
00031 VLC_EXPORT( int,  __vlc_threads_init,  ( vlc_object_t * ) );
00032 VLC_EXPORT( int,  __vlc_threads_end,   ( vlc_object_t * ) );
00033 VLC_EXPORT( int,  __vlc_mutex_init,    ( vlc_object_t *, vlc_mutex_t * ) );
00034 VLC_EXPORT( int,  __vlc_mutex_destroy, ( char *, int, vlc_mutex_t * ) );
00035 VLC_EXPORT( int,  __vlc_cond_init,     ( vlc_object_t *, vlc_cond_t * ) );
00036 VLC_EXPORT( int,  __vlc_cond_destroy,  ( char *, int, vlc_cond_t * ) );
00037 VLC_EXPORT( int,  __vlc_thread_create, ( vlc_object_t *, char *, int, char *, void * ( * ) ( void * ), int, vlc_bool_t ) );
00038 VLC_EXPORT( int,  __vlc_thread_set_priority, ( vlc_object_t *, char *, int, int ) );
00039 VLC_EXPORT( void, __vlc_thread_ready,  ( vlc_object_t * ) );
00040 VLC_EXPORT( void, __vlc_thread_join,   ( vlc_object_t *, char *, int ) );
00041 
00042 
00043 /*****************************************************************************
00044  * vlc_threads_init: initialize threads system
00045  *****************************************************************************/
00046 #define vlc_threads_init( P_THIS )                                          \
00047     __vlc_threads_init( VLC_OBJECT(P_THIS) )
00048 
00049 /*****************************************************************************
00050  * vlc_threads_end: deinitialize threads system
00051  *****************************************************************************/
00052 #define vlc_threads_end( P_THIS )                                           \
00053     __vlc_threads_end( VLC_OBJECT(P_THIS) )
00054 
00055 /*****************************************************************************
00056  * vlc_mutex_init: initialize a mutex
00057  *****************************************************************************/
00058 #define vlc_mutex_init( P_THIS, P_MUTEX )                                   \
00059     __vlc_mutex_init( VLC_OBJECT(P_THIS), P_MUTEX )
00060 
00061 /*****************************************************************************
00062  * vlc_mutex_lock: lock a mutex
00063  *****************************************************************************/
00064 #define vlc_mutex_lock( P_MUTEX )                                           \
00065     __vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
00066 
00067 static inline int __vlc_mutex_lock( char * psz_file, int i_line,
00068                                     vlc_mutex_t * p_mutex )
00069 {
00070     int i_result;
00071     /* In case of error : */
00072     int i_thread = -1;
00073     const char * psz_error = "";
00074 
00075 #if defined( PTH_INIT_IN_PTH_H )
00076     i_result = ( pth_mutex_acquire( &p_mutex->mutex, FALSE, NULL ) == FALSE );
00077 
00078 #elif defined( ST_INIT_IN_ST_H )
00079     i_result = st_mutex_lock( p_mutex->mutex );
00080 
00081 #elif defined( UNDER_CE )
00082     EnterCriticalSection( &p_mutex->csection );
00083     i_result = 0;
00084 
00085 #elif defined( WIN32 )
00086     if( p_mutex->mutex )
00087     {
00088         WaitForSingleObject( p_mutex->mutex, INFINITE );
00089     }
00090     else
00091     {
00092         EnterCriticalSection( &p_mutex->csection );
00093     }
00094     i_result = 0;
00095 
00096 #elif defined( HAVE_KERNEL_SCHEDULER_H )
00097     if( p_mutex == NULL )
00098     {
00099         i_result = B_BAD_VALUE;
00100     }
00101     else if( p_mutex->init < 2000 )
00102     {
00103         i_result = B_NO_INIT;
00104     }
00105     else
00106     {
00107         i_result = acquire_sem( p_mutex->lock );
00108     }
00109 
00110 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
00111     i_result = pthread_mutex_lock( &p_mutex->mutex );
00112     if ( i_result )
00113     {
00114         i_thread = (int)pthread_self();
00115         psz_error = strerror(i_result);
00116     }
00117 
00118 #elif defined( HAVE_CTHREADS_H )
00119     mutex_lock( p_mutex->mutex );
00120     i_result = 0;
00121 
00122 #endif
00123 
00124     if( i_result )
00125     {
00126         msg_Err( p_mutex->p_this,
00127                  "thread %u: mutex_lock failed at %s:%d (%d:%s)",
00128                  i_thread, psz_file, i_line, i_result, psz_error );
00129     }
00130     return i_result;
00131 }
00132 
00133 /*****************************************************************************
00134  * vlc_mutex_unlock: unlock a mutex
00135  *****************************************************************************/
00136 #define vlc_mutex_unlock( P_MUTEX )                                         \
00137     __vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
00138 
00139 static inline int __vlc_mutex_unlock( char * psz_file, int i_line,
00140                                       vlc_mutex_t *p_mutex )
00141 {
00142     int i_result;
00143     /* In case of error : */
00144     int i_thread = -1;
00145     const char * psz_error = "";
00146 
00147 #if defined( PTH_INIT_IN_PTH_H )
00148     i_result = ( pth_mutex_release( &p_mutex->mutex ) == FALSE );
00149 
00150 #elif defined( ST_INIT_IN_ST_H )
00151     i_result = st_mutex_unlock( p_mutex->mutex );
00152 
00153 #elif defined( UNDER_CE )
00154     LeaveCriticalSection( &p_mutex->csection );
00155     i_result = 0;
00156 
00157 #elif defined( WIN32 )
00158     if( p_mutex->mutex )
00159     {
00160         ReleaseMutex( p_mutex->mutex );
00161     }
00162     else
00163     {
00164         LeaveCriticalSection( &p_mutex->csection );
00165     }
00166     i_result = 0;
00167 
00168 #elif defined( HAVE_KERNEL_SCHEDULER_H )
00169     if( p_mutex == NULL )
00170     {
00171         i_result = B_BAD_VALUE;
00172     }
00173     else if( p_mutex->init < 2000 )
00174     {
00175         i_result = B_NO_INIT;
00176     }
00177     else
00178     {
00179         release_sem( p_mutex->lock );
00180         return B_OK;
00181     }
00182 
00183 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
00184     i_result = pthread_mutex_unlock( &p_mutex->mutex );
00185     if ( i_result )
00186     {
00187         i_thread = (int)pthread_self();
00188         psz_error = strerror(i_result);
00189     }
00190 
00191 #elif defined( HAVE_CTHREADS_H )
00192     mutex_unlock( p_mutex );
00193     i_result = 0;
00194 
00195 #endif
00196 
00197     if( i_result )
00198     {
00199         msg_Err( p_mutex->p_this,
00200                  "thread %u: mutex_unlock failed at %s:%d (%d:%s)",
00201                  i_thread, psz_file, i_line, i_result, psz_error );
00202     }
00203 
00204     return i_result;
00205 }
00206 
00207 /*****************************************************************************
00208  * vlc_mutex_destroy: destroy a mutex
00209  *****************************************************************************/
00210 #define vlc_mutex_destroy( P_MUTEX )                                        \
00211     __vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
00212 
00213 /*****************************************************************************
00214  * vlc_cond_init: initialize a condition
00215  *****************************************************************************/
00216 #define vlc_cond_init( P_THIS, P_COND )                                     \
00217     __vlc_cond_init( VLC_OBJECT(P_THIS), P_COND )
00218 
00219 /*****************************************************************************
00220  * vlc_cond_signal: start a thread on condition completion
00221  *****************************************************************************/
00222 #define vlc_cond_signal( P_COND )                                           \
00223     __vlc_cond_signal( __FILE__, __LINE__, P_COND )
00224 
00225 static inline int __vlc_cond_signal( char * psz_file, int i_line,
00226                                      vlc_cond_t *p_condvar )
00227 {
00228     int i_result;
00229     /* In case of error : */
00230     int i_thread = -1;
00231     const char * psz_error = "";
00232 
00233 #if defined( PTH_INIT_IN_PTH_H )
00234     i_result = ( pth_cond_notify( &p_condvar->cond, FALSE ) == FALSE );
00235 
00236 #elif defined( ST_INIT_IN_ST_H )
00237     i_result = st_cond_signal( p_condvar->cond );
00238 
00239 #elif defined( UNDER_CE )
00240     PulseEvent( p_condvar->event );
00241     i_result = 0;
00242 
00243 #elif defined( WIN32 )
00244     /* Release one waiting thread if one is available. */
00245     /* For this trick to work properly, the vlc_cond_signal must be surrounded
00246      * by a mutex. This will prevent another thread from stealing the signal */
00247     if( !p_condvar->semaphore )
00248     {
00249         PulseEvent( p_condvar->event );
00250     }
00251     else if( p_condvar->i_win9x_cv == 1 )
00252     {
00253         /* Wait for the gate to be open */
00254         WaitForSingleObject( p_condvar->event, INFINITE );
00255 
00256         if( p_condvar->i_waiting_threads )
00257         {
00258             /* Using a semaphore exposes us to a race condition. It is
00259              * possible for another thread to start waiting on the semaphore
00260              * just after we signaled it and thus steal the signal.
00261              * We have to prevent new threads from entering the cond_wait(). */
00262             ResetEvent( p_condvar->event );
00263 
00264             /* A semaphore is used here because Win9x doesn't have
00265              * SignalObjectAndWait() and thus a race condition exists
00266              * during the time we release the mutex and the time we start
00267              * waiting on the event (more precisely, the signal can sometimes
00268              * be missed by the waiting thread if we use PulseEvent()). */
00269             ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
00270         }
00271     }
00272     else
00273     {
00274         if( p_condvar->i_waiting_threads )
00275         {
00276             ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
00277 
00278             /* Wait for the last thread to be awakened */
00279             WaitForSingleObject( p_condvar->event, INFINITE );
00280         }
00281     }
00282     i_result = 0;
00283 
00284 #elif defined( HAVE_KERNEL_SCHEDULER_H )
00285     if( p_condvar == NULL )
00286     {
00287         i_result = B_BAD_VALUE;
00288     }
00289     else if( p_condvar->init < 2000 )
00290     {
00291         i_result = B_NO_INIT;
00292     }
00293     else
00294     {
00295         while( p_condvar->thread != -1 )
00296         {
00297             thread_info info;
00298             if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
00299             {
00300                 return 0;
00301             }
00302 
00303             if( info.state != B_THREAD_SUSPENDED )
00304             {
00305                 /* The  waiting thread is not suspended so it could
00306                  * have been interrupted beetwen the unlock and the
00307                  * suspend_thread line. That is why we sleep a little
00308                  * before retesting p_condver->thread. */
00309                 snooze( 10000 );
00310             }
00311             else
00312             {
00313                 /* Ok, we have to wake up that thread */
00314                 resume_thread( p_condvar->thread );
00315                 return 0;
00316             }
00317         }
00318         i_result = 0;
00319     }
00320 
00321 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
00322     i_result = pthread_cond_signal( &p_condvar->cond );
00323     if ( i_result )
00324     {
00325         i_thread = (int)pthread_self();
00326         psz_error = strerror(i_result);
00327     }
00328 
00329 #elif defined( HAVE_CTHREADS_H )
00330     /* condition_signal() */
00331     if ( p_condvar->queue.head || p_condvar->implications )
00332     {
00333         cond_signal( (condition_t)p_condvar );
00334     }
00335     i_result = 0;
00336 
00337 #endif
00338 
00339     if( i_result )
00340     {
00341         msg_Err( p_condvar->p_this,
00342                  "thread %u: cond_signal failed at %s:%d (%d:%s)",
00343                  i_thread, psz_file, i_line, i_result, psz_error );
00344     }
00345 
00346     return i_result;
00347 }
00348 
00349 /*****************************************************************************
00350  * vlc_cond_wait: wait until condition completion
00351  *****************************************************************************/
00352 #define vlc_cond_wait( P_COND, P_MUTEX )                                     \
00353     __vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX  )
00354 
00355 static inline int __vlc_cond_wait( char * psz_file, int i_line,
00356                                    vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex )
00357 {
00358     int i_result;
00359     /* In case of error : */
00360     int i_thread = -1;
00361     const char * psz_error = "";
00362 
00363 #if defined( PTH_INIT_IN_PTH_H )
00364     i_result = ( pth_cond_await( &p_condvar->cond, &p_mutex->mutex, NULL )
00365                  == FALSE );
00366 
00367 #elif defined( ST_INIT_IN_ST_H )
00368     st_mutex_unlock( p_mutex->mutex );
00369     i_result = st_cond_wait( p_condvar->cond );
00370     st_mutex_lock( p_mutex->mutex );
00371 
00372 #elif defined( UNDER_CE )
00373     p_condvar->i_waiting_threads++;
00374     LeaveCriticalSection( &p_mutex->csection );
00375     WaitForSingleObject( p_condvar->event, INFINITE );
00376     p_condvar->i_waiting_threads--;
00377 
00378     /* Reacquire the mutex before returning. */
00379     vlc_mutex_lock( p_mutex );
00380 
00381     i_result = 0;
00382 
00383 #elif defined( WIN32 )
00384     if( !p_condvar->semaphore )
00385     {
00386         /* Increase our wait count */
00387         p_condvar->i_waiting_threads++;
00388 
00389         if( p_mutex->mutex )
00390         {
00391             /* It is only possible to atomically release the mutex and
00392              * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
00393              * SignalObjectAndWait(). */
00394             p_condvar->SignalObjectAndWait( p_mutex->mutex,
00395                                             p_condvar->event,
00396                                             INFINITE, FALSE );
00397         }
00398         else
00399         {
00400             LeaveCriticalSection( &p_mutex->csection );
00401             WaitForSingleObject( p_condvar->event, INFINITE );
00402         }
00403 
00404         p_condvar->i_waiting_threads--;
00405     }
00406     else if( p_condvar->i_win9x_cv == 1 )
00407     {
00408         int i_waiting_threads;
00409 
00410         /* Wait for the gate to be open */
00411         WaitForSingleObject( p_condvar->event, INFINITE );
00412 
00413         /* Increase our wait count */
00414         p_condvar->i_waiting_threads++;
00415 
00416         LeaveCriticalSection( &p_mutex->csection );
00417         WaitForSingleObject( p_condvar->semaphore, INFINITE );
00418 
00419         /* Decrement and test must be atomic */
00420         EnterCriticalSection( &p_condvar->csection );
00421 
00422         /* Decrease our wait count */
00423         i_waiting_threads = --p_condvar->i_waiting_threads;
00424 
00425         LeaveCriticalSection( &p_condvar->csection );
00426 
00427         /* Reopen the gate if we were the last waiting thread */
00428         if( !i_waiting_threads )
00429             SetEvent( p_condvar->event );
00430     }
00431     else
00432     {
00433         int i_waiting_threads;
00434 
00435         /* Increase our wait count */
00436         p_condvar->i_waiting_threads++;
00437 
00438         LeaveCriticalSection( &p_mutex->csection );
00439         WaitForSingleObject( p_condvar->semaphore, INFINITE );
00440 
00441         /* Decrement and test must be atomic */
00442         EnterCriticalSection( &p_condvar->csection );
00443 
00444         /* Decrease our wait count */
00445         i_waiting_threads = --p_condvar->i_waiting_threads;
00446 
00447         LeaveCriticalSection( &p_condvar->csection );
00448 
00449         /* Signal that the last waiting thread just went through */
00450         if( !i_waiting_threads )
00451             SetEvent( p_condvar->event );
00452     }
00453 
00454     /* Reacquire the mutex before returning. */
00455     vlc_mutex_lock( p_mutex );
00456 
00457     i_result = 0;
00458 
00459 #elif defined( HAVE_KERNEL_SCHEDULER_H )
00460     if( p_condvar == NULL )
00461     {
00462         i_result = B_BAD_VALUE;
00463     }
00464     else if( p_mutex == NULL )
00465     {
00466         i_result = B_BAD_VALUE;
00467     }
00468     else if( p_condvar->init < 2000 )
00469     {
00470         i_result = B_NO_INIT;
00471     }
00472 
00473     /* The p_condvar->thread var is initialized before the unlock because
00474      * it enables to identify when the thread is interrupted beetwen the
00475      * unlock line and the suspend_thread line */
00476     p_condvar->thread = find_thread( NULL );
00477     vlc_mutex_unlock( p_mutex );
00478     suspend_thread( p_condvar->thread );
00479     p_condvar->thread = -1;
00480 
00481     vlc_mutex_lock( p_mutex );
00482     i_result = 0;
00483 
00484 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
00485 
00486 #   ifdef DEBUG
00487     /* In debug mode, timeout */
00488     struct timeval now;
00489     struct timespec timeout;
00490 
00491     gettimeofday( &now, NULL );
00492     timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT;
00493     timeout.tv_nsec = now.tv_usec * 1000;
00494 
00495     i_result = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex,
00496                                        &timeout );
00497 
00498     if( i_result == ETIMEDOUT )
00499     {
00500         /* People keep pissing me off with this. --Meuuh */
00501         msg_Dbg( p_condvar->p_this,
00502                   "thread %u: secret message triggered "
00503                   "at %s:%d (%s)", (int)pthread_self(),
00504                   psz_file, i_line, strerror(i_result) );
00505 
00506         i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
00507     }
00508 
00509 #   else
00510     i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
00511 #   endif
00512 
00513     if ( i_result )
00514     {
00515         i_thread = (int)pthread_self();
00516         psz_error = strerror(i_result);
00517     }
00518 
00519 #elif defined( HAVE_CTHREADS_H )
00520     condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
00521     i_result = 0;
00522 
00523 #endif
00524 
00525     if( i_result )
00526     {
00527         msg_Err( p_condvar->p_this,
00528                  "thread %u: cond_wait failed at %s:%d (%d:%s)",
00529                  i_thread, psz_file, i_line, i_result, psz_error );
00530     }
00531 
00532     return i_result;
00533 }
00534 
00535 /*****************************************************************************
00536  * vlc_cond_destroy: destroy a condition
00537  *****************************************************************************/
00538 #define vlc_cond_destroy( P_COND )                                          \
00539     __vlc_cond_destroy( __FILE__, __LINE__, P_COND )
00540 
00541 /*****************************************************************************
00542  * vlc_thread_create: create a thread
00543  *****************************************************************************/
00544 #define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY, WAIT )         \
00545     __vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, (void * ( * ) ( void * ))FUNC, PRIORITY, WAIT )
00546 
00547 /*****************************************************************************
00548  * vlc_thread_set_priority: set the priority of the calling thread
00549  *****************************************************************************/
00550 #define vlc_thread_set_priority( P_THIS, PRIORITY )                         \
00551     __vlc_thread_set_priority( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PRIORITY )
00552 
00553 /*****************************************************************************
00554  * vlc_thread_ready: tell the parent thread we were successfully spawned
00555  *****************************************************************************/
00556 #define vlc_thread_ready( P_THIS )                                          \
00557     __vlc_thread_ready( VLC_OBJECT(P_THIS) )
00558 
00559 /*****************************************************************************
00560  * vlc_thread_join: wait until a thread exits
00561  *****************************************************************************/
00562 #define vlc_thread_join( P_THIS )                                           \
00563     __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )

Generated on Tue Dec 20 10:14:19 2005 for vlc-0.8.4a by  doxygen 1.4.2