vlc_threads_funcs.h
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:19k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * vlc_threads_funcs.h : threads implementation for the VideoLAN client
  3.  * This header provides a portable threads implementation.
  4.  *****************************************************************************
  5.  * Copyright (C) 1999, 2002 VideoLAN
  6.  * $Id: vlc_threads_funcs.h 8414 2004-08-11 23:34:38Z titer $
  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
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2 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 General Public License for more details.
  22.  *
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with this program; if not, write to the Free Software
  25.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  26.  *****************************************************************************/
  27. /*****************************************************************************
  28.  * Function definitions
  29.  *****************************************************************************/
  30. VLC_EXPORT( int,  __vlc_threads_init,  ( vlc_object_t * ) );
  31. VLC_EXPORT( int,  __vlc_threads_end,   ( vlc_object_t * ) );
  32. VLC_EXPORT( int,  __vlc_mutex_init,    ( vlc_object_t *, vlc_mutex_t * ) );
  33. VLC_EXPORT( int,  __vlc_mutex_destroy, ( char *, int, vlc_mutex_t * ) );
  34. VLC_EXPORT( int,  __vlc_cond_init,     ( vlc_object_t *, vlc_cond_t * ) );
  35. VLC_EXPORT( int,  __vlc_cond_destroy,  ( char *, int, vlc_cond_t * ) );
  36. VLC_EXPORT( int,  __vlc_thread_create, ( vlc_object_t *, char *, int, char *, void * ( * ) ( void * ), int, vlc_bool_t ) );
  37. VLC_EXPORT( int,  __vlc_thread_set_priority, ( vlc_object_t *, char *, int, int ) );
  38. VLC_EXPORT( void, __vlc_thread_ready,  ( vlc_object_t * ) );
  39. VLC_EXPORT( void, __vlc_thread_join,   ( vlc_object_t *, char *, int ) );
  40. /*****************************************************************************
  41.  * vlc_threads_init: initialize threads system
  42.  *****************************************************************************/
  43. #define vlc_threads_init( P_THIS )                                          
  44.     __vlc_threads_init( VLC_OBJECT(P_THIS) )
  45. /*****************************************************************************
  46.  * vlc_threads_end: deinitialize threads system
  47.  *****************************************************************************/
  48. #define vlc_threads_end( P_THIS )                                           
  49.     __vlc_threads_end( VLC_OBJECT(P_THIS) )
  50. /*****************************************************************************
  51.  * vlc_mutex_init: initialize a mutex
  52.  *****************************************************************************/
  53. #define vlc_mutex_init( P_THIS, P_MUTEX )                                   
  54.     __vlc_mutex_init( VLC_OBJECT(P_THIS), P_MUTEX )
  55. /*****************************************************************************
  56.  * vlc_mutex_lock: lock a mutex
  57.  *****************************************************************************/
  58. #define vlc_mutex_lock( P_MUTEX )                                           
  59.     __vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
  60. static inline int __vlc_mutex_lock( char * psz_file, int i_line,
  61.                                     vlc_mutex_t * p_mutex )
  62. {
  63.     int i_result;
  64.     /* In case of error : */
  65.     int i_thread = -1;
  66.     const char * psz_error = "";
  67. #if defined( PTH_INIT_IN_PTH_H )
  68.     i_result = ( pth_mutex_acquire( &p_mutex->mutex, FALSE, NULL ) == FALSE );
  69. #elif defined( ST_INIT_IN_ST_H )
  70.     i_result = st_mutex_lock( p_mutex->mutex );
  71. #elif defined( UNDER_CE )
  72.     EnterCriticalSection( &p_mutex->csection );
  73.     i_result = 0;
  74. #elif defined( WIN32 )
  75.     if( p_mutex->mutex )
  76.     {
  77.         WaitForSingleObject( p_mutex->mutex, INFINITE );
  78.     }
  79.     else
  80.     {
  81.         EnterCriticalSection( &p_mutex->csection );
  82.     }
  83.     i_result = 0;
  84. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  85.     if( p_mutex == NULL )
  86.     {
  87.         i_result = B_BAD_VALUE;
  88.     }
  89.     else if( p_mutex->init < 2000 )
  90.     {
  91.         i_result = B_NO_INIT;
  92.     }
  93.     else
  94.     {
  95.         i_result = acquire_sem( p_mutex->lock );
  96.     }
  97. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  98.     i_result = pthread_mutex_lock( &p_mutex->mutex );
  99.     if ( i_result )
  100.     {
  101.         i_thread = (int)pthread_self();
  102.         psz_error = strerror(i_result);
  103.     }
  104. #elif defined( HAVE_CTHREADS_H )
  105.     mutex_lock( p_mutex->mutex );
  106.     i_result = 0;
  107. #endif
  108.     if( i_result )
  109.     {
  110.         msg_Err( p_mutex->p_this,
  111.                  "thread %d: mutex_lock failed at %s:%d (%d:%s)",
  112.                  i_thread, psz_file, i_line, i_result, psz_error );
  113.     }
  114.     return i_result;
  115. }
  116. /*****************************************************************************
  117.  * vlc_mutex_unlock: unlock a mutex
  118.  *****************************************************************************/
  119. #define vlc_mutex_unlock( P_MUTEX )                                         
  120.     __vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
  121. static inline int __vlc_mutex_unlock( char * psz_file, int i_line,
  122.                                       vlc_mutex_t *p_mutex )
  123. {
  124.     int i_result;
  125.     /* In case of error : */
  126.     int i_thread = -1;
  127.     const char * psz_error = "";
  128. #if defined( PTH_INIT_IN_PTH_H )
  129.     i_result = ( pth_mutex_release( &p_mutex->mutex ) == FALSE );
  130. #elif defined( ST_INIT_IN_ST_H )
  131.     i_result = st_mutex_unlock( p_mutex->mutex );
  132. #elif defined( UNDER_CE )
  133.     LeaveCriticalSection( &p_mutex->csection );
  134.     i_result = 0;
  135. #elif defined( WIN32 )
  136.     if( p_mutex->mutex )
  137.     {
  138.         ReleaseMutex( p_mutex->mutex );
  139.     }
  140.     else
  141.     {
  142.         LeaveCriticalSection( &p_mutex->csection );
  143.     }
  144.     i_result = 0;
  145. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  146.     if( p_mutex == NULL )
  147.     {
  148.         i_result = B_BAD_VALUE;
  149.     }
  150.     else if( p_mutex->init < 2000 )
  151.     {
  152.         i_result = B_NO_INIT;
  153.     }
  154.     else
  155.     {
  156.         release_sem( p_mutex->lock );
  157.         return B_OK;
  158.     }
  159. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  160.     i_result = pthread_mutex_unlock( &p_mutex->mutex );
  161.     if ( i_result )
  162.     {
  163.         i_thread = (int)pthread_self();
  164.         psz_error = strerror(i_result);
  165.     }
  166. #elif defined( HAVE_CTHREADS_H )
  167.     mutex_unlock( p_mutex );
  168.     i_result = 0;
  169. #endif
  170.     if( i_result )
  171.     {
  172.         msg_Err( p_mutex->p_this,
  173.                  "thread %d: mutex_unlock failed at %s:%d (%d:%s)",
  174.                  i_thread, psz_file, i_line, i_result, psz_error );
  175.     }
  176.     return i_result;
  177. }
  178. /*****************************************************************************
  179.  * vlc_mutex_destroy: destroy a mutex
  180.  *****************************************************************************/
  181. #define vlc_mutex_destroy( P_MUTEX )                                        
  182.     __vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
  183. /*****************************************************************************
  184.  * vlc_cond_init: initialize a condition
  185.  *****************************************************************************/
  186. #define vlc_cond_init( P_THIS, P_COND )                                     
  187.     __vlc_cond_init( VLC_OBJECT(P_THIS), P_COND )
  188. /*****************************************************************************
  189.  * vlc_cond_signal: start a thread on condition completion
  190.  *****************************************************************************/
  191. #define vlc_cond_signal( P_COND )                                           
  192.     __vlc_cond_signal( __FILE__, __LINE__, P_COND )
  193. static inline int __vlc_cond_signal( char * psz_file, int i_line,
  194.                                      vlc_cond_t *p_condvar )
  195. {
  196.     int i_result;
  197.     /* In case of error : */
  198.     int i_thread = -1;
  199.     const char * psz_error = "";
  200. #if defined( PTH_INIT_IN_PTH_H )
  201.     i_result = ( pth_cond_notify( &p_condvar->cond, FALSE ) == FALSE );
  202. #elif defined( ST_INIT_IN_ST_H )
  203.     i_result = st_cond_signal( p_condvar->cond );
  204. #elif defined( UNDER_CE )
  205.     PulseEvent( p_condvar->event );
  206.     i_result = 0;
  207. #elif defined( WIN32 )
  208.     /* Release one waiting thread if one is available. */
  209.     /* For this trick to work properly, the vlc_cond_signal must be surrounded
  210.      * by a mutex. This will prevent another thread from stealing the signal */
  211.     if( !p_condvar->semaphore )
  212.     {
  213.         PulseEvent( p_condvar->event );
  214.     }
  215.     else if( p_condvar->i_win9x_cv == 1 )
  216.     {
  217.         /* Wait for the gate to be open */
  218.         WaitForSingleObject( p_condvar->event, INFINITE );
  219.         if( p_condvar->i_waiting_threads )
  220.         {
  221.             /* Using a semaphore exposes us to a race condition. It is
  222.              * possible for another thread to start waiting on the semaphore
  223.              * just after we signaled it and thus steal the signal.
  224.              * We have to prevent new threads from entering the cond_wait(). */
  225.             ResetEvent( p_condvar->event );
  226.             /* A semaphore is used here because Win9x doesn't have
  227.              * SignalObjectAndWait() and thus a race condition exists
  228.              * during the time we release the mutex and the time we start
  229.              * waiting on the event (more precisely, the signal can sometimes
  230.              * be missed by the waiting thread if we use PulseEvent()). */
  231.             ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
  232.         }
  233.     }
  234.     else
  235.     {
  236.         if( p_condvar->i_waiting_threads )
  237.         {
  238.             ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
  239.             /* Wait for the last thread to be awakened */
  240.             WaitForSingleObject( p_condvar->event, INFINITE );
  241.         }
  242.     }
  243.     i_result = 0;
  244. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  245.     if( p_condvar == NULL )
  246.     {
  247.         i_result = B_BAD_VALUE;
  248.     }
  249.     else if( p_condvar->init < 2000 )
  250.     {
  251.         i_result = B_NO_INIT;
  252.     }
  253.     else
  254.     {
  255.         while( p_condvar->thread != -1 )
  256.         {
  257.             thread_info info;
  258.             if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
  259.             {
  260.                 return 0;
  261.             }
  262.             if( info.state != B_THREAD_SUSPENDED )
  263.             {
  264.                 /* The  waiting thread is not suspended so it could
  265.                  * have been interrupted beetwen the unlock and the
  266.                  * suspend_thread line. That is why we sleep a little
  267.                  * before retesting p_condver->thread. */
  268.                 snooze( 10000 );
  269.             }
  270.             else
  271.             {
  272.                 /* Ok, we have to wake up that thread */
  273.                 resume_thread( p_condvar->thread );
  274.                 return 0;
  275.             }
  276.         }
  277.         i_result = 0;
  278.     }
  279. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  280.     i_result = pthread_cond_signal( &p_condvar->cond );
  281.     if ( i_result )
  282.     {
  283.         i_thread = (int)pthread_self();
  284.         psz_error = strerror(i_result);
  285.     }
  286. #elif defined( HAVE_CTHREADS_H )
  287.     /* condition_signal() */
  288.     if ( p_condvar->queue.head || p_condvar->implications )
  289.     {
  290.         cond_signal( (condition_t)p_condvar );
  291.     }
  292.     i_result = 0;
  293. #endif
  294.     if( i_result )
  295.     {
  296.         msg_Err( p_condvar->p_this,
  297.                  "thread %d: cond_signal failed at %s:%d (%d:%s)",
  298.                  i_thread, psz_file, i_line, i_result, psz_error );
  299.     }
  300.     return i_result;
  301. }
  302. /*****************************************************************************
  303.  * vlc_cond_wait: wait until condition completion
  304.  *****************************************************************************/
  305. #define vlc_cond_wait( P_COND, P_MUTEX )                                     
  306.     __vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX  )
  307. static inline int __vlc_cond_wait( char * psz_file, int i_line,
  308.                                    vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex )
  309. {
  310.     int i_result;
  311.     /* In case of error : */
  312.     int i_thread = -1;
  313.     const char * psz_error = "";
  314. #if defined( PTH_INIT_IN_PTH_H )
  315.     i_result = ( pth_cond_await( &p_condvar->cond, &p_mutex->mutex, NULL )
  316.                  == FALSE );
  317. #elif defined( ST_INIT_IN_ST_H )
  318.     st_mutex_unlock( p_mutex->mutex );
  319.     i_result = st_cond_wait( p_condvar->cond );
  320.     st_mutex_lock( p_mutex->mutex );
  321. #elif defined( UNDER_CE )
  322.     p_condvar->i_waiting_threads++;
  323.     LeaveCriticalSection( &p_mutex->csection );
  324.     WaitForSingleObject( p_condvar->event, INFINITE );
  325.     p_condvar->i_waiting_threads--;
  326.     /* Reacquire the mutex before returning. */
  327.     vlc_mutex_lock( p_mutex );
  328.     i_result = 0;
  329. #elif defined( WIN32 )
  330.     if( !p_condvar->semaphore )
  331.     {
  332.         /* Increase our wait count */
  333.         p_condvar->i_waiting_threads++;
  334.         if( p_mutex->mutex )
  335.         {
  336.             /* It is only possible to atomically release the mutex and
  337.              * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
  338.              * SignalObjectAndWait(). */
  339.             p_condvar->SignalObjectAndWait( p_mutex->mutex,
  340.                                             p_condvar->event,
  341.                                             INFINITE, FALSE );
  342.         }
  343.         else
  344.         {
  345.             LeaveCriticalSection( &p_mutex->csection );
  346.             WaitForSingleObject( p_condvar->event, INFINITE );
  347.         }
  348.         p_condvar->i_waiting_threads--;
  349.     }
  350.     else if( p_condvar->i_win9x_cv == 1 )
  351.     {
  352.         int i_waiting_threads;
  353.         /* Wait for the gate to be open */
  354.         WaitForSingleObject( p_condvar->event, INFINITE );
  355.         /* Increase our wait count */
  356.         p_condvar->i_waiting_threads++;
  357.         LeaveCriticalSection( &p_mutex->csection );
  358.         WaitForSingleObject( p_condvar->semaphore, INFINITE );
  359.         /* Decrement and test must be atomic */
  360.         EnterCriticalSection( &p_condvar->csection );
  361.         /* Decrease our wait count */
  362.         i_waiting_threads = --p_condvar->i_waiting_threads;
  363.         LeaveCriticalSection( &p_condvar->csection );
  364.         /* Reopen the gate if we were the last waiting thread */
  365.         if( !i_waiting_threads )
  366.             SetEvent( p_condvar->event );
  367.     }
  368.     else
  369.     {
  370.         int i_waiting_threads;
  371.         /* Increase our wait count */
  372.         p_condvar->i_waiting_threads++;
  373.         LeaveCriticalSection( &p_mutex->csection );
  374.         WaitForSingleObject( p_condvar->semaphore, INFINITE );
  375.         /* Decrement and test must be atomic */
  376.         EnterCriticalSection( &p_condvar->csection );
  377.         /* Decrease our wait count */
  378.         i_waiting_threads = --p_condvar->i_waiting_threads;
  379.         LeaveCriticalSection( &p_condvar->csection );
  380.         /* Signal that the last waiting thread just went through */
  381.         if( !i_waiting_threads )
  382.             SetEvent( p_condvar->event );
  383.     }
  384.     /* Reacquire the mutex before returning. */
  385.     vlc_mutex_lock( p_mutex );
  386.     i_result = 0;
  387. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  388.     if( p_condvar == NULL )
  389.     {
  390.         i_result = B_BAD_VALUE;
  391.     }
  392.     else if( p_mutex == NULL )
  393.     {
  394.         i_result = B_BAD_VALUE;
  395.     }
  396.     else if( p_condvar->init < 2000 )
  397.     {
  398.         i_result = B_NO_INIT;
  399.     }
  400.     /* The p_condvar->thread var is initialized before the unlock because
  401.      * it enables to identify when the thread is interrupted beetwen the
  402.      * unlock line and the suspend_thread line */
  403.     p_condvar->thread = find_thread( NULL );
  404.     vlc_mutex_unlock( p_mutex );
  405.     suspend_thread( p_condvar->thread );
  406.     p_condvar->thread = -1;
  407.     vlc_mutex_lock( p_mutex );
  408.     i_result = 0;
  409. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  410. #   ifdef DEBUG
  411.     /* In debug mode, timeout */
  412.     struct timeval now;
  413.     struct timespec timeout;
  414.     gettimeofday( &now, NULL );
  415.     timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT;
  416.     timeout.tv_nsec = now.tv_usec * 1000;
  417.     i_result = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex,
  418.                                        &timeout );
  419.     if( i_result == ETIMEDOUT )
  420.     {
  421.         /* People keep pissing me off with this. --Meuuh */
  422.         msg_Dbg( p_condvar->p_this,
  423.                   "thread %d: secret message triggered "
  424.                   "at %s:%d (%s)", (int)pthread_self(),
  425.                   psz_file, i_line, strerror(i_result) );
  426.         i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
  427.     }
  428. #   else
  429.     i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
  430. #   endif
  431.     if ( i_result )
  432.     {
  433.         i_thread = (int)pthread_self();
  434.         psz_error = strerror(i_result);
  435.     }
  436. #elif defined( HAVE_CTHREADS_H )
  437.     condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
  438.     i_result = 0;
  439. #endif
  440.     if( i_result )
  441.     {
  442.         msg_Err( p_condvar->p_this,
  443.                  "thread %d: cond_wait failed at %s:%d (%d:%s)",
  444.                  i_thread, psz_file, i_line, i_result, psz_error );
  445.     }
  446.     return i_result;
  447. }
  448. /*****************************************************************************
  449.  * vlc_cond_destroy: destroy a condition
  450.  *****************************************************************************/
  451. #define vlc_cond_destroy( P_COND )                                          
  452.     __vlc_cond_destroy( __FILE__, __LINE__, P_COND )
  453. /*****************************************************************************
  454.  * vlc_thread_create: create a thread
  455.  *****************************************************************************/
  456. #define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY, WAIT )         
  457.     __vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, (void * ( * ) ( void * ))FUNC, PRIORITY, WAIT )
  458. /*****************************************************************************
  459.  * vlc_thread_set_priority: set the priority of the calling thread
  460.  *****************************************************************************/
  461. #define vlc_thread_set_priority( P_THIS, PRIORITY )                         
  462.     __vlc_thread_set_priority( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PRIORITY )
  463. /*****************************************************************************
  464.  * vlc_thread_ready: tell the parent thread we were successfully spawned
  465.  *****************************************************************************/
  466. #define vlc_thread_ready( P_THIS )                                          
  467.     __vlc_thread_ready( VLC_OBJECT(P_THIS) )
  468. /*****************************************************************************
  469.  * vlc_thread_join: wait until a thread exits
  470.  *****************************************************************************/
  471. #define vlc_thread_join( P_THIS )                                           
  472.     __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )