X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=include%2Fthreads.h;h=01b385ad99b6c50ae3ca2d29eab05d55d1182ecc;hb=e98aae28c0040819f43bde6259ec95d3029deedf;hp=6704bc05eee69016b8bd4c776d7b297040093f89;hpb=13fd7a12d6063648849bc5b18ad288152f06a69e;p=vlc diff --git a/include/threads.h b/include/threads.h index 6704bc05ee..01b385ad99 100644 --- a/include/threads.h +++ b/include/threads.h @@ -3,7 +3,7 @@ * This header provides a portable threads implementation. ***************************************************************************** * Copyright (C) 1999, 2000 VideoLAN - * $Id: threads.h,v 1.30 2001/11/29 10:20:56 massiot Exp $ + * $Id: threads.h,v 1.40 2002/04/05 03:27:27 sam Exp $ * * Authors: Jean-Marc Dressler * Samuel Hocevar @@ -32,8 +32,18 @@ #if defined( PTH_INIT_IN_PTH_H ) /* GNU Pth */ # include +#elif defined( ST_INIT_IN_ST_H ) /* State threads */ +# include + +#elif defined( WIN32 ) +# include + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) /* pthreads (like Linux & BSD) */ # include +# ifdef DEBUG +/* Needed for pthread_cond_timedwait */ +# include +# endif /* This is not prototyped under Linux, though it exists. */ int pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind ); @@ -41,17 +51,10 @@ int pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind ); # include #elif defined( HAVE_KERNEL_SCHEDULER_H ) /* BeOS */ -# undef MAX -# undef MIN # include # include # include -#elif defined( WIN32 ) -#define WIN32_LEAN_AND_MEAN -# include -# include - #else # error no threads available on your system ! @@ -92,6 +95,28 @@ typedef pth_t vlc_thread_t; typedef pth_mutex_t vlc_mutex_t; typedef pth_cond_t vlc_cond_t; +#elif defined( ST_INIT_IN_ST_H ) +typedef st_thread_t * vlc_thread_t; +typedef st_mutex_t * vlc_mutex_t; +typedef st_cond_t * vlc_cond_t; + +#elif defined( WIN32 ) +typedef HANDLE vlc_thread_t; + +typedef struct +{ + CRITICAL_SECTION csection; + HANDLE mutex; +} vlc_mutex_t; + +typedef struct +{ + int i_waiting_threads; + HANDLE signal; +} vlc_cond_t; + +typedef unsigned (__stdcall *PTHREAD_START) (void *); + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) typedef pthread_t vlc_thread_t; typedef pthread_mutex_t vlc_mutex_t; @@ -136,18 +161,6 @@ typedef struct thread_id thread; } vlc_cond_t; -#elif defined( WIN32 ) -typedef HANDLE vlc_thread_t; -typedef CRITICAL_SECTION vlc_mutex_t; - -typedef struct -{ - int i_waiting_threads; - HANDLE signal; -} vlc_cond_t; - -typedef unsigned (__stdcall *PTHREAD_START) (void *); - #endif typedef void *(*vlc_thread_func_t)(void *p_data); @@ -156,17 +169,25 @@ typedef void *(*vlc_thread_func_t)(void *p_data); * Prototypes *****************************************************************************/ -/* Message functions - this is kludgy because we are included before - * modules_export.h */ -#ifdef PLUGIN -# define intf_ErrMsg p_symbols->intf_ErrMsg -# define intf_WarnMsg p_symbols->intf_WarnMsg -#endif - #ifdef GPROF /* Wrapper function for profiling */ static void * vlc_thread_wrapper ( void *p_wrapper ); +# ifdef WIN32 + +# define ITIMER_REAL 1 +# define ITIMER_PROF 2 + +struct itimerval +{ + struct timeval it_value; + struct timeval it_interval; +}; + +int setitimer(int kind, const struct itimerval* itnew, struct itimerval* itold); + +# endif /* WIN32 */ + typedef struct wrapper_s { /* Data lock access */ @@ -182,21 +203,6 @@ typedef struct wrapper_s } wrapper_t; -#ifdef WIN32 -struct itimerval -{ - struct timeval it_value; - struct timeval it_interval; -}; - -int setitimer(int kind, const struct itimerval* itnew, - struct itimerval* itold); - -#define ITIMER_REAL 1 -#define ITIMER_PROF 2 - -#endif /* WIN32 */ - #endif /* GPROF */ /***************************************************************************** @@ -207,6 +213,12 @@ static __inline__ int vlc_threads_init( void ) #if defined( PTH_INIT_IN_PTH_H ) return pth_init(); +#elif defined( ST_INIT_IN_ST_H ) + return st_init(); + +#elif defined( WIN32 ) + return 0; + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) return 0; @@ -216,9 +228,6 @@ static __inline__ int vlc_threads_init( void ) #elif defined( HAVE_KERNEL_SCHEDULER_H ) return 0; -#elif defined( WIN32 ) - return 0; - #endif } @@ -230,6 +239,12 @@ static __inline__ int vlc_threads_end( void ) #if defined( PTH_INIT_IN_PTH_H ) return pth_kill(); +#elif defined( ST_INIT_IN_ST_H ) + return 0; + +#elif defined( WIN32 ) + return 0; + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) return 0; @@ -239,9 +254,6 @@ static __inline__ int vlc_threads_end( void ) #elif defined( HAVE_KERNEL_SCHEDULER_H ) return 0; -#elif defined( WIN32 ) - return 0; - #endif } @@ -253,6 +265,28 @@ static __inline__ int vlc_mutex_init( vlc_mutex_t *p_mutex ) #if defined( PTH_INIT_IN_PTH_H ) return pth_mutex_init( p_mutex ); +#elif defined( ST_INIT_IN_ST_H ) + *p_mutex = st_mutex_new(); + return ( *p_mutex == NULL ) ? errno : 0; + +#elif defined( WIN32 ) + /* We use mutexes on WinNT/2K/XP because we can use the SignalObjectAndWait + * function and have a 100% correct vlc_cond_wait() implementation. + * As this function is not available on Win9x, we can use the faster + * CriticalSections */ + if( (GetVersion() < 0x80000000) && !p_main_sys->b_fast_pthread ) + { + /* We are running on NT/2K/XP, we can use SignalObjectAndWait */ + p_mutex->mutex = CreateMutex( 0, FALSE, 0 ); + return ( p_mutex->mutex ? 0 : 1 ); + } + else + { + InitializeCriticalSection( &p_mutex->csection ); + p_mutex->mutex = NULL; + return 0; + } + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) # if defined(DEBUG) && defined(SYS_LINUX) /* Create error-checking mutex to detect threads problems more easily. */ @@ -294,10 +328,6 @@ static __inline__ int vlc_mutex_init( vlc_mutex_t *p_mutex ) p_mutex->init = 9999; return B_OK; -#elif defined( WIN32 ) - InitializeCriticalSection( p_mutex ); - return 0; - #endif } @@ -318,6 +348,20 @@ static __inline__ int _vlc_mutex_lock( char * psz_file, int i_line, #if defined( PTH_INIT_IN_PTH_H ) return pth_mutex_acquire( p_mutex, TRUE, NULL ); +#elif defined( ST_INIT_IN_ST_H ) + return st_mutex_lock( *p_mutex ); + +#elif defined( WIN32 ) + if( p_mutex->mutex ) + { + WaitForSingleObject( p_mutex->mutex, INFINITE ); + } + else + { + EnterCriticalSection( &p_mutex->csection ); + } + return 0; + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) int i_return = pthread_mutex_lock( p_mutex ); if( i_return ) @@ -347,10 +391,6 @@ static __inline__ int _vlc_mutex_lock( char * psz_file, int i_line, err = acquire_sem( p_mutex->lock ); return err; -#elif defined( WIN32 ) - EnterCriticalSection( p_mutex ); - return 0; - #endif } @@ -371,6 +411,20 @@ static __inline__ int _vlc_mutex_unlock( char * psz_file, int i_line, #if defined( PTH_INIT_IN_PTH_H ) return pth_mutex_release( p_mutex ); +#elif defined( ST_INIT_IN_ST_H ) + return st_mutex_unlock( *p_mutex ); + +#elif defined( WIN32 ) + if( p_mutex->mutex ) + { + ReleaseMutex( p_mutex->mutex ); + } + else + { + LeaveCriticalSection( &p_mutex->csection ); + } + return 0; + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) int i_return = pthread_mutex_unlock( p_mutex ); if( i_return ) @@ -398,10 +452,6 @@ static __inline__ int _vlc_mutex_unlock( char * psz_file, int i_line, release_sem( p_mutex->lock ); return B_OK; -#elif defined( WIN32 ) - LeaveCriticalSection( p_mutex ); - return 0; - #endif } @@ -422,6 +472,20 @@ static __inline__ int _vlc_mutex_destroy( char * psz_file, int i_line, #if defined( PTH_INIT_IN_PTH_H ) return 0; +#elif defined( ST_INIT_IN_ST_H ) + return st_mutex_destroy( *p_mutex ); + +#elif defined( WIN32 ) + if( p_mutex->mutex ) + { + CloseHandle( p_mutex->mutex ); + } + else + { + DeleteCriticalSection( &p_mutex->csection ); + } + return 0; + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) int i_return = pthread_mutex_destroy( p_mutex ); if( i_return ) @@ -443,10 +507,6 @@ static __inline__ int _vlc_mutex_destroy( char * psz_file, int i_line, p_mutex->init = 0; return B_OK; -#elif defined( WIN32 ) - DeleteCriticalSection( p_mutex ); - return 0; - #endif } @@ -458,6 +518,22 @@ static __inline__ int vlc_cond_init( vlc_cond_t *p_condvar ) #if defined( PTH_INIT_IN_PTH_H ) return pth_cond_init( p_condvar ); +#elif defined( ST_INIT_IN_ST_H ) + *p_condvar = st_cond_new(); + return ( *p_condvar == NULL ) ? errno : 0; + +#elif defined( WIN32 ) + /* initialise counter */ + p_condvar->i_waiting_threads = 0; + + /* Create an auto-reset event. */ + p_condvar->signal = CreateEvent( NULL, /* no security */ + FALSE, /* auto-reset event */ + FALSE, /* non-signaled initially */ + NULL ); /* unnamed */ + + return( !p_condvar->signal ); + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) return pthread_cond_init( p_condvar, NULL ); @@ -485,18 +561,6 @@ static __inline__ int vlc_cond_init( vlc_cond_t *p_condvar ) p_condvar->init = 9999; return 0; -#elif defined( WIN32 ) - /* initialise counter */ - p_condvar->i_waiting_threads = 0; - - /* Create an auto-reset event. */ - p_condvar->signal = CreateEvent( NULL, /* no security */ - FALSE, /* auto-reset event */ - FALSE, /* non-signaled initially */ - NULL ); /* unnamed */ - - return( !p_condvar->signal ); - #endif } @@ -508,6 +572,16 @@ static __inline__ int vlc_cond_signal( vlc_cond_t *p_condvar ) #if defined( PTH_INIT_IN_PTH_H ) return pth_cond_notify( p_condvar, FALSE ); +#elif defined( ST_INIT_IN_ST_H ) + return st_cond_signal( *p_condvar ); + +#elif defined( WIN32 ) + /* Release one waiting thread if one is available. */ + /* For this trick to work properly, the vlc_cond_signal must be surrounded + * by a mutex. This will prevent another thread from stealing the signal */ + PulseEvent( p_condvar->signal ); + return 0; + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) return pthread_cond_signal( p_condvar ); @@ -555,19 +629,6 @@ static __inline__ int vlc_cond_signal( vlc_cond_t *p_condvar ) } return 0; -#elif defined( WIN32 ) - /* Release one waiting thread if one is available. */ - /* For this trick to work properly, the vlc_cond_signal must be surrounded - * by a mutex. This will prevent another thread from stealing the signal */ - int i_waiting_threads = p_condvar->i_waiting_threads; - while( p_condvar->i_waiting_threads - && p_condvar->i_waiting_threads == i_waiting_threads ) - { - PulseEvent( p_condvar->signal ); - Sleep( 0 ); /* deschedule the current thread */ - } - return 0; - #endif } @@ -584,6 +645,20 @@ static __inline__ int vlc_cond_broadcast( vlc_cond_t *p_condvar ) #if defined( PTH_INIT_IN_PTH_H ) return pth_cond_notify( p_condvar, FALSE ); +#elif defined( ST_INIT_IN_ST_H ) + return st_cond_broadcast( p_condvar ); + +#elif defined( WIN32 ) + /* Release all waiting threads. */ + /* For this trick to work properly, the vlc_cond_signal must be surrounded + * by a mutex. This will prevent another thread from stealing the signal */ + while( p_condvar->i_waiting_threads ) + { + PulseEvent( p_condvar->signal ); + Sleep( 1 ); /* deschedule the current thread */ + } + return 0; + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) return pthread_cond_broadcast( p_condvar ); @@ -631,17 +706,6 @@ static __inline__ int vlc_cond_broadcast( vlc_cond_t *p_condvar ) } return 0; -#elif defined( WIN32 ) - /* Release all waiting threads. */ - /* For this trick to work properly, the vlc_cond_signal must be surrounded - * by a mutex. This will prevent another thread from stealing the signal */ - while( p_condvar->i_waiting_threads ) - { - PulseEvent( p_condvar->signal ); - Sleep( 0 ); /* deschedule the current thread */ - } - return 0; - #endif } @@ -663,6 +727,47 @@ static __inline__ int _vlc_cond_wait( char * psz_file, int i_line, #if defined( PTH_INIT_IN_PTH_H ) return pth_cond_await( p_condvar, p_mutex, NULL ); +#elif defined( ST_INIT_IN_ST_H ) + int i_ret; + + st_mutex_unlock( *p_mutex ); + i_ret = st_cond_wait( *p_condvar ); + st_mutex_lock( *p_mutex ); + + return i_ret; + +#elif defined( WIN32 ) + /* The ideal would be to use a function which atomically releases the + * mutex and initiate the waiting. + * Unfortunately only the SignalObjectAndWait function does this and it's + * only supported on WinNT/2K, furthermore it cannot take multiple + * events as parameters. + * + * The solution we use should however fulfill all our needs (even though + * it is not a correct pthreads implementation) + */ + int i_result; + + p_condvar->i_waiting_threads ++; + + if( p_mutex->mutex ) + { + p_main_sys->SignalObjectAndWait( p_mutex->mutex, p_condvar->signal, + INFINITE, FALSE ); + } + else + { + /* Release the mutex */ + vlc_mutex_unlock( p_mutex ); + i_result = WaitForSingleObject( p_condvar->signal, INFINITE); + p_condvar->i_waiting_threads --; + } + + /* Reacquire the mutex before returning. */ + vlc_mutex_lock( p_mutex ); + + return( i_result == WAIT_FAILED ); + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) #ifndef DEBUG @@ -679,15 +784,21 @@ static __inline__ int _vlc_cond_wait( char * psz_file, int i_line, timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT; timeout.tv_nsec = now.tv_usec * 1000; - if( (i_result = pthread_cond_timedwait( p_condvar, p_mutex, &timeout )) ) + i_result = pthread_cond_timedwait( p_condvar, p_mutex, &timeout ); + + if( i_result == ETIMEDOUT ) { - intf_ErrMsg( "thread %d warning: Possible deadlock detected in cond_wait at %s:%d (%s)", - pthread_self(), psz_file, i_line, strerror(i_result) ); + intf_WarnMsg( 1, "thread %d warning: Possible deadlock detected in cond_wait at %s:%d (%s)", + pthread_self(), psz_file, i_line, strerror(i_result) ); + continue; } - else + + if( i_result ) { - return i_result; + intf_ErrMsg( "thread %d error: cond_wait failed at %s:%d (%s)", + pthread_self(), psz_file, i_line, strerror(i_result) ); } + return( i_result ); } #endif @@ -722,33 +833,6 @@ static __inline__ int _vlc_cond_wait( char * psz_file, int i_line, vlc_mutex_lock( p_mutex ); return 0; -#elif defined( WIN32 ) - /* The ideal would be to use a function which atomically releases the - * mutex and initiate the waiting. - * Unfortunately only the SignalObjectAndWait function does this and it's - * only supported on WinNT/2K, furthermore it cannot take multiple - * events as parameters. - * - * The solution we use should however fulfill all our needs (even though - * it is not a correct pthreads implementation) - */ - int i_result; - - p_condvar->i_waiting_threads ++; - - /* Release the mutex */ - vlc_mutex_unlock( p_mutex ); - - i_result = WaitForSingleObject( p_condvar->signal, INFINITE); - - /* maybe we should protect this with a mutex ? */ - p_condvar->i_waiting_threads --; - - /* Reacquire the mutex before returning. */ - vlc_mutex_lock( p_mutex ); - - return( i_result == WAIT_FAILED ); - #endif } @@ -769,6 +853,12 @@ static __inline__ int _vlc_cond_destroy( char * psz_file, int i_line, #if defined( PTH_INIT_IN_PTH_H ) return 0; +#elif defined( ST_INIT_IN_ST_H ) + return st_cond_destroy( *p_condvar ); + +#elif defined( WIN32 ) + return( !CloseHandle( p_condvar->signal ) ); + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) int i_result = pthread_cond_destroy( p_condvar ); if( i_result ) @@ -785,9 +875,6 @@ static __inline__ int _vlc_cond_destroy( char * psz_file, int i_line, p_condvar->init = 0; return 0; -#elif defined( WIN32 ) - return( !CloseHandle( p_condvar->signal ) ); - #endif } @@ -831,6 +918,20 @@ static __inline__ int _vlc_thread_create( char * psz_file, int i_line, *p_thread = pth_spawn( PTH_ATTR_DEFAULT, func, p_data ); i_ret = ( p_thread == NULL ); +#elif defined( ST_INIT_IN_ST_H ) + *p_thread = st_thread_create( func, p_data, 1, 0 ); + i_ret = ( p_thread == NULL ); + +#elif defined( WIN32 ) + unsigned threadID; + /* When using the MSVCRT C library you have to use the _beginthreadex + * function instead of CreateThread, otherwise you'll end up with memory + * leaks and the signal functions not working */ + *p_thread = (HANDLE)_beginthreadex( NULL, 0, (PTHREAD_START) func, + p_data, 0, &threadID ); + + i_ret = ( *p_thread ? 0 : 1 ); + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) i_ret = pthread_create( p_thread, NULL, func, p_data ); @@ -843,23 +944,6 @@ static __inline__ int _vlc_thread_create( char * psz_file, int i_line, B_NORMAL_PRIORITY, p_data ); i_ret = resume_thread( *p_thread ); -#elif defined( WIN32 ) -#if 0 - DWORD threadID; - /* This method is not recommended when using the MSVCRT C library, - * so we'll have to use _beginthreadex instead */ - *p_thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) func, - p_data, 0, &threadID); -#endif - unsigned threadID; - /* When using the MSVCRT C library you have to use the _beginthreadex - * function instead of CreateThread, otherwise you'll end up with memory - * leaks and the signal function not working */ - *p_thread = (HANDLE)_beginthreadex(NULL, 0, (PTHREAD_START) func, - p_data, 0, &threadID); - - i_ret = ( *p_thread ? 0 : 1 ); - #endif #ifdef GPROF @@ -895,6 +979,15 @@ static __inline__ void vlc_thread_exit( void ) #if defined( PTH_INIT_IN_PTH_H ) pth_exit( 0 ); +#elif defined( ST_INIT_IN_ST_H ) + int result; + st_thread_exit( &result ); + +#elif defined( WIN32 ) + /* For now we don't close the thread handles (because of race conditions). + * Need to be looked at. */ + _endthreadex(0); + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) pthread_exit( 0 ); @@ -905,14 +998,6 @@ static __inline__ void vlc_thread_exit( void ) #elif defined( HAVE_KERNEL_SCHEDULER_H ) exit_thread( 0 ); -#elif defined( WIN32 ) -#if 0 - ExitThread( 0 ); -#endif - /* For now we don't close the thread handles (because of race conditions). - * Need to be looked at. */ - _endthreadex(0); - #endif } @@ -935,19 +1020,23 @@ static __inline__ void _vlc_thread_join( char * psz_file, int i_line, #if defined( PTH_INIT_IN_PTH_H ) i_ret = pth_join( thread, NULL ); +#elif defined( ST_INIT_IN_ST_H ) + i_ret = st_thread_join( thread, NULL ); + +#elif defined( WIN32 ) + WaitForSingleObject( thread, INFINITE ); + #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) i_ret = pthread_join( thread, NULL ); #elif defined( HAVE_CTHREADS_H ) - i_ret = cthread_join( thread ); + cthread_join( thread ); + i_ret = 1; #elif defined( HAVE_KERNEL_SCHEDULER_H ) int32 exit_value; wait_for_thread( thread, &exit_value ); -#elif defined( WIN32 ) - WaitForSingleObject( thread, INFINITE ); - #endif if( i_ret ) @@ -981,8 +1070,3 @@ static void *vlc_thread_wrapper( void *p_wrapper ) return func( p_data ); } #endif - -#ifdef PLUGIN -# undef intf_WarnMsg -# undef intf_ErrMsg -#endif