X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fthreads.c;h=1c239a40bad62c7c9e5c3f5bde9ad37bc7751d4d;hb=54e8456263f8994e792be65907d341682bbdcc28;hp=db3cceca01d84aba1d86fc91da78423b33675db6;hpb=7a063304797e68b8109b2e5ac91f2458cb0c6752;p=vlc diff --git a/src/misc/threads.c b/src/misc/threads.c index db3cceca01..1c239a40ba 100644 --- a/src/misc/threads.c +++ b/src/misc/threads.c @@ -1,12 +1,13 @@ /***************************************************************************** * threads.c : threads implementation for the VideoLAN client ***************************************************************************** - * Copyright (C) 1999-2004 the VideoLAN team + * Copyright (C) 1999-2007 the VideoLAN team * $Id$ * * Authors: Jean-Marc Dressler * Samuel Hocevar * Gildas Bazin + * Clément Sténac * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,12 +21,20 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + #include -#include +#include "libvlc.h" +#include +#ifdef HAVE_UNISTD_H +# include +#endif #define VLC_THREADS_UNINITIALIZED 0 #define VLC_THREADS_PENDING 1 @@ -39,28 +48,49 @@ static volatile unsigned i_initializations = 0; static volatile int i_status = VLC_THREADS_UNINITIALIZED; static vlc_object_t *p_root; -#if defined( PTH_INIT_IN_PTH_H ) -#elif defined( ST_INIT_IN_ST_H ) -#elif defined( UNDER_CE ) +#if defined( UNDER_CE ) #elif defined( WIN32 ) + +/* following is only available on NT/2000/XP and above */ +static SIGNALOBJECTANDWAIT pf_SignalObjectAndWait = NULL; + +/* +** On Windows NT/2K/XP we use a slow mutex implementation but which +** allows us to correctly implement condition variables. +** You can also use the faster Win9x implementation but you might +** experience problems with it. +*/ +static vlc_bool_t b_fast_mutex = VLC_FALSE; +/* +** On Windows 9x/Me you can use a fast but incorrect condition variables +** implementation (more precisely there is a possibility for a race +** condition to happen). +** However it is possible to use slower alternatives which are more robust. +** Currently you can choose between implementation 0 (which is the +** fastest but slightly incorrect), 1 (default) and 2. +*/ +static int i_win9x_cv = 1; + #elif defined( HAVE_KERNEL_SCHEDULER_H ) -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) - static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER; -#elif defined( HAVE_CTHREADS_H ) +#elif defined( LIBVLC_USE_PTHREAD ) +static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER; #endif +vlc_threadvar_t msg_context_global_key; + +#ifndef NDEBUG /***************************************************************************** - * Global variable for named mutexes + * vlc_threads_error: Report an error from the threading mecanism + ***************************************************************************** + * This is especially useful to debug those errors, as this is a nice symbol + * on which you can break. *****************************************************************************/ -typedef struct vlc_namedmutex_t vlc_namedmutex_t; -struct vlc_namedmutex_t +void vlc_threads_error( vlc_object_t *p_this ) { - vlc_mutex_t lock; - - char *psz_name; - int i_usage; - vlc_namedmutex_t *p_next; -}; + msg_Err( p_this, "Error detected. Put a breakpoint in '%s' to debug.", + __func__ ); +} +#endif /***************************************************************************** * vlc_threads_init: initialize threads system @@ -71,19 +101,22 @@ struct vlc_namedmutex_t *****************************************************************************/ int __vlc_threads_init( vlc_object_t *p_this ) { - libvlc_t *p_libvlc = (libvlc_t *)p_this; + libvlc_global_data_t *p_libvlc_global = (libvlc_global_data_t *)p_this; int i_ret = VLC_SUCCESS; /* If we have lazy mutex initialization, use it. Otherwise, we just * hope nothing wrong happens. */ -#if defined( PTH_INIT_IN_PTH_H ) -#elif defined( ST_INIT_IN_ST_H ) -#elif defined( UNDER_CE ) +#if defined( UNDER_CE ) #elif defined( WIN32 ) + if( IsDebuggerPresent() ) + { + /* SignalObjectAndWait() is problematic under a debugger */ + b_fast_mutex = VLC_TRUE; + i_win9x_cv = 1; + } #elif defined( HAVE_KERNEL_SCHEDULER_H ) -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) +#elif defined( LIBVLC_USE_PTHREAD ) pthread_mutex_lock( &once_mutex ); -#elif defined( HAVE_CTHREADS_H ) #endif if( i_status == VLC_THREADS_UNINITIALIZED ) @@ -91,15 +124,9 @@ int __vlc_threads_init( vlc_object_t *p_this ) i_status = VLC_THREADS_PENDING; /* We should be safe now. Do all the initialization stuff we want. */ - p_libvlc->b_ready = VLC_FALSE; - -#if defined( PTH_INIT_IN_PTH_H ) - i_ret = ( pth_init() == FALSE ); + p_libvlc_global->b_ready = VLC_FALSE; -#elif defined( ST_INIT_IN_ST_H ) - i_ret = st_init(); - -#elif defined( UNDER_CE ) +#if defined( UNDER_CE ) /* Nothing to initialize */ #elif defined( WIN32 ) @@ -112,25 +139,17 @@ int __vlc_threads_init( vlc_object_t *p_this ) hInstLib = LoadLibrary( "kernel32" ); if( hInstLib ) { - p_libvlc->SignalObjectAndWait = + pf_SignalObjectAndWait = (SIGNALOBJECTANDWAIT)GetProcAddress( hInstLib, "SignalObjectAndWait" ); } } - else - { - p_libvlc->SignalObjectAndWait = NULL; - } - - p_libvlc->b_fast_mutex = 0; - p_libvlc->i_win9x_cv = 0; #elif defined( HAVE_KERNEL_SCHEDULER_H ) -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) -#elif defined( HAVE_CTHREADS_H ) +#elif defined( LIBVLC_USE_PTHREAD ) #endif - p_root = vlc_object_create( p_libvlc, VLC_OBJECT_ROOT ); + p_root = vlc_object_create( p_libvlc_global, VLC_OBJECT_GLOBAL ); if( p_root == NULL ) i_ret = VLC_ENOMEM; @@ -143,6 +162,8 @@ int __vlc_threads_init( vlc_object_t *p_this ) i_initializations++; i_status = VLC_THREADS_READY; } + + vlc_threadvar_create( p_root, &msg_context_global_key ); } else { @@ -152,20 +173,14 @@ int __vlc_threads_init( vlc_object_t *p_this ) /* If we have lazy mutex initialization support, unlock the mutex; * otherwize, do a naive wait loop. */ -#if defined( PTH_INIT_IN_PTH_H ) - while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP ); -#elif defined( ST_INIT_IN_ST_H ) - while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP ); -#elif defined( UNDER_CE ) +#if defined( UNDER_CE ) while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP ); #elif defined( WIN32 ) while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP ); #elif defined( HAVE_KERNEL_SCHEDULER_H ) while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP ); -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) +#elif defined( LIBVLC_USE_PTHREAD ) pthread_mutex_unlock( &once_mutex ); -#elif defined( HAVE_CTHREADS_H ) - while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP ); #endif if( i_status != VLC_THREADS_READY ) @@ -183,14 +198,12 @@ int __vlc_threads_init( vlc_object_t *p_this ) *****************************************************************************/ int __vlc_threads_end( vlc_object_t *p_this ) { -#if defined( PTH_INIT_IN_PTH_H ) -#elif defined( ST_INIT_IN_ST_H ) -#elif defined( UNDER_CE ) + (void)p_this; +#if defined( UNDER_CE ) #elif defined( WIN32 ) #elif defined( HAVE_KERNEL_SCHEDULER_H ) -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) +#elif defined( LIBVLC_USE_PTHREAD ) pthread_mutex_lock( &once_mutex ); -#elif defined( HAVE_CTHREADS_H ) #endif if( i_initializations == 0 ) @@ -203,23 +216,20 @@ int __vlc_threads_end( vlc_object_t *p_this ) vlc_object_destroy( p_root ); } -#if defined( PTH_INIT_IN_PTH_H ) - if( i_initializations == 0 ) - { - return ( pth_kill() == FALSE ); - } - -#elif defined( ST_INIT_IN_ST_H ) -#elif defined( UNDER_CE ) +#if defined( UNDER_CE ) #elif defined( WIN32 ) #elif defined( HAVE_KERNEL_SCHEDULER_H ) -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) +#elif defined( LIBVLC_USE_PTHREAD ) pthread_mutex_unlock( &once_mutex ); -#elif defined( HAVE_CTHREADS_H ) #endif return VLC_SUCCESS; } +#ifdef __linux__ +/* This is not prototyped under Linux, though it exists. */ +int pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind ); +#endif + /***************************************************************************** * vlc_mutex_init: initialize a mutex *****************************************************************************/ @@ -227,14 +237,7 @@ int __vlc_mutex_init( vlc_object_t *p_this, vlc_mutex_t *p_mutex ) { p_mutex->p_this = p_this; -#if defined( PTH_INIT_IN_PTH_H ) - return ( pth_mutex_init( &p_mutex->mutex ) == FALSE ); - -#elif defined( ST_INIT_IN_ST_H ) - p_mutex->mutex = st_mutex_new(); - return ( p_mutex->mutex == NULL ) ? errno : 0; - -#elif defined( UNDER_CE ) +#if defined( UNDER_CE ) InitializeCriticalSection( &p_mutex->csection ); return 0; @@ -243,8 +246,7 @@ int __vlc_mutex_init( vlc_object_t *p_this, vlc_mutex_t *p_mutex ) * 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( p_this->p_libvlc->SignalObjectAndWait && - !p_this->p_libvlc->b_fast_mutex ) + if( pf_SignalObjectAndWait && !b_fast_mutex ) { /* We are running on NT/2K/XP, we can use SignalObjectAndWait */ p_mutex->mutex = CreateMutex( 0, FALSE, 0 ); @@ -278,46 +280,74 @@ int __vlc_mutex_init( vlc_object_t *p_this, vlc_mutex_t *p_mutex ) p_mutex->init = 9999; return B_OK; -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) -# if defined(DEBUG) && defined(SYS_LINUX) +#elif defined( LIBVLC_USE_PTHREAD ) +# ifndef NDEBUG { /* Create error-checking mutex to detect problems more easily. */ pthread_mutexattr_t attr; int i_result; pthread_mutexattr_init( &attr ); +# if defined(SYS_LINUX) pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ERRORCHECK_NP ); +# else + pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK ); +# endif + i_result = pthread_mutex_init( &p_mutex->mutex, &attr ); pthread_mutexattr_destroy( &attr ); return( i_result ); } -# endif +# endif /* NDEBUG */ return pthread_mutex_init( &p_mutex->mutex, NULL ); -#elif defined( HAVE_CTHREADS_H ) - mutex_init( p_mutex ); - return 0; +#endif +} +/***************************************************************************** + * vlc_mutex_init: initialize a recursive mutex (Do not use) + *****************************************************************************/ +int __vlc_mutex_init_recursive( vlc_object_t *p_this, vlc_mutex_t *p_mutex ) +{ +#if defined( WIN32 ) + /* Create mutex returns a recursive mutex */ + p_mutex->mutex = CreateMutex( 0, FALSE, 0 ); + return ( p_mutex->mutex != NULL ? 0 : 1 ); +#elif defined( LIBVLC_USE_PTHREAD ) + pthread_mutexattr_t attr; + int i_result; + + pthread_mutexattr_init( &attr ); +# ifndef NDEBUG + /* Create error-checking mutex to detect problems more easily. */ +# if defined(SYS_LINUX) + pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ERRORCHECK_NP ); +# else + pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK ); +# endif +# endif + pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); + i_result = pthread_mutex_init( &p_mutex->mutex, &attr ); + pthread_mutexattr_destroy( &attr ); + return( i_result ); +#else + msg_Err(p_this, "no recursive mutex found. Falling back to regular mutex.\n" + "Expect hangs\n") + return __vlc_mutex_init( p_this, p_mutex ); #endif } + /***************************************************************************** * vlc_mutex_destroy: destroy a mutex, inner version *****************************************************************************/ -int __vlc_mutex_destroy( char * psz_file, int i_line, vlc_mutex_t *p_mutex ) +int __vlc_mutex_destroy( const char * psz_file, int i_line, vlc_mutex_t *p_mutex ) { int i_result; /* In case of error : */ int i_thread = -1; - const char * psz_error = ""; -#if defined( PTH_INIT_IN_PTH_H ) - return 0; - -#elif defined( ST_INIT_IN_ST_H ) - i_result = st_mutex_destroy( p_mutex->mutex ); - -#elif defined( UNDER_CE ) +#if defined( UNDER_CE ) DeleteCriticalSection( &p_mutex->csection ); return 0; @@ -341,24 +371,22 @@ int __vlc_mutex_destroy( char * psz_file, int i_line, vlc_mutex_t *p_mutex ) p_mutex->init = 0; return B_OK; -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) +#elif defined( LIBVLC_USE_PTHREAD ) i_result = pthread_mutex_destroy( &p_mutex->mutex ); - if ( i_result ) + if( i_result ) { - i_thread = (int)pthread_self(); - psz_error = strerror(i_result); + i_thread = CAST_PTHREAD_TO_INT(pthread_self()); + errno = i_result; } -#elif defined( HAVE_CTHREADS_H ) - return 0; - #endif if( i_result ) { msg_Err( p_mutex->p_this, - "thread %d: mutex_destroy failed at %s:%d (%d:%s)", - i_thread, psz_file, i_line, i_result, psz_error ); + "thread %d: mutex_destroy failed at %s:%d (%d:%m)", + i_thread, psz_file, i_line, i_result ); + vlc_threads_error( p_mutex->p_this ); } return i_result; } @@ -370,14 +398,7 @@ int __vlc_cond_init( vlc_object_t *p_this, vlc_cond_t *p_condvar ) { p_condvar->p_this = p_this; -#if defined( PTH_INIT_IN_PTH_H ) - return ( pth_cond_init( &p_condvar->cond ) == FALSE ); - -#elif defined( ST_INIT_IN_ST_H ) - p_condvar->cond = st_cond_new(); - return ( p_condvar->cond == NULL ) ? errno : 0; - -#elif defined( UNDER_CE ) +#if defined( UNDER_CE ) /* Initialize counter */ p_condvar->i_waiting_threads = 0; @@ -393,10 +414,10 @@ int __vlc_cond_init( vlc_object_t *p_this, vlc_cond_t *p_condvar ) p_condvar->i_waiting_threads = 0; /* Misc init */ - p_condvar->i_win9x_cv = p_this->p_libvlc->i_win9x_cv; - p_condvar->SignalObjectAndWait = p_this->p_libvlc->SignalObjectAndWait; + p_condvar->i_win9x_cv = i_win9x_cv; + p_condvar->SignalObjectAndWait = pf_SignalObjectAndWait; - if( (p_condvar->SignalObjectAndWait && !p_this->p_libvlc->b_fast_mutex) + if( (p_condvar->SignalObjectAndWait && !b_fast_mutex) || p_condvar->i_win9x_cv == 0 ) { /* Create an auto-reset event. */ @@ -442,17 +463,26 @@ int __vlc_cond_init( vlc_object_t *p_this, vlc_cond_t *p_condvar ) p_condvar->init = 9999; return 0; -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) - return pthread_cond_init( &p_condvar->cond, NULL ); +#elif defined( LIBVLC_USE_PTHREAD ) + pthread_condattr_t attr; + int ret; -#elif defined( HAVE_CTHREADS_H ) - /* condition_init() */ - spin_lock_init( &p_condvar->lock ); - cthread_queue_init( &p_condvar->queue ); - p_condvar->name = 0; - p_condvar->implications = 0; + ret = pthread_condattr_init (&attr); + if (ret) + return ret; - return 0; +# if !defined (_POSIX_CLOCK_SELECTION) + /* Fairly outdated POSIX support (that was defined in 2001) */ +# define _POSIX_CLOCK_SELECTION (-1) +# endif +# if (_POSIX_CLOCK_SELECTION >= 0) + /* NOTE: This must be the same clock as the one in mtime.c */ + pthread_condattr_setclock (&attr, CLOCK_MONOTONIC); +# endif + + ret = pthread_cond_init (&p_condvar->cond, &attr); + pthread_condattr_destroy (&attr); + return ret; #endif } @@ -460,20 +490,13 @@ int __vlc_cond_init( vlc_object_t *p_this, vlc_cond_t *p_condvar ) /***************************************************************************** * vlc_cond_destroy: destroy a condition, inner version *****************************************************************************/ -int __vlc_cond_destroy( char * psz_file, int i_line, vlc_cond_t *p_condvar ) +int __vlc_cond_destroy( const char * psz_file, int i_line, vlc_cond_t *p_condvar ) { int i_result; /* In case of error : */ int i_thread = -1; - const char * psz_error = ""; - -#if defined( PTH_INIT_IN_PTH_H ) - return 0; - -#elif defined( ST_INIT_IN_ST_H ) - i_result = st_cond_destroy( p_condvar->cond ); -#elif defined( UNDER_CE ) +#if defined( UNDER_CE ) i_result = !CloseHandle( p_condvar->event ); #elif defined( WIN32 ) @@ -484,106 +507,125 @@ int __vlc_cond_destroy( char * psz_file, int i_line, vlc_cond_t *p_condvar ) || !CloseHandle( p_condvar->semaphore ); if( p_condvar->semaphore != NULL ) - DeleteCriticalSection( &p_condvar->csection ); + DeleteCriticalSection( &p_condvar->csection ); #elif defined( HAVE_KERNEL_SCHEDULER_H ) p_condvar->init = 0; return 0; -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) +#elif defined( LIBVLC_USE_PTHREAD ) i_result = pthread_cond_destroy( &p_condvar->cond ); - if ( i_result ) + if( i_result ) { - i_thread = (int)pthread_self(); - psz_error = strerror(i_result); + i_thread = CAST_PTHREAD_TO_INT(pthread_self()); + errno = i_result; } -#elif defined( HAVE_CTHREADS_H ) - return 0; - #endif if( i_result ) { msg_Err( p_condvar->p_this, - "thread %d: cond_destroy failed at %s:%d (%d:%s)", - i_thread, psz_file, i_line, i_result, psz_error ); + "thread %d: cond_destroy failed at %s:%d (%d:%m)", + i_thread, psz_file, i_line, i_result ); + vlc_threads_error( p_condvar->p_this ); } return i_result; } +/***************************************************************************** + * vlc_tls_create: create a thread-local variable + *****************************************************************************/ +int __vlc_threadvar_create( vlc_object_t *p_this, vlc_threadvar_t *p_tls ) +{ + int i_ret = -1; + (void)p_this; + +#if defined( HAVE_KERNEL_SCHEDULER_H ) + msg_Err( p_this, "TLS not implemented" ); + i_ret VLC_EGENERIC; +#elif defined( UNDER_CE ) || defined( WIN32 ) +#elif defined( WIN32 ) + p_tls->handle = TlsAlloc(); + i_ret = !( p_tls->handle == 0xFFFFFFFF ); + +#elif defined( LIBVLC_USE_PTHREAD ) + i_ret = pthread_key_create( &p_tls->handle, NULL ); +#endif + return i_ret; +} + /***************************************************************************** * vlc_thread_create: create a thread, inner version ***************************************************************************** * Note that i_priority is only taken into account on platforms supporting * userland real-time priority threads. *****************************************************************************/ -int __vlc_thread_create( vlc_object_t *p_this, char * psz_file, int i_line, - char *psz_name, void * ( *func ) ( void * ), +int __vlc_thread_create( vlc_object_t *p_this, const char * psz_file, int i_line, + const char *psz_name, void * ( *func ) ( void * ), int i_priority, vlc_bool_t b_wait ) { int i_ret; void *p_data = (void *)p_this; + vlc_object_internals_t *p_priv = p_this->p_internals; vlc_mutex_lock( &p_this->object_lock ); -#if defined( PTH_INIT_IN_PTH_H ) - p_this->thread_id = pth_spawn( PTH_ATTR_DEFAULT, func, p_data ); - i_ret = p_this->thread_id == NULL; - -#elif defined( ST_INIT_IN_ST_H ) - p_this->thread_id = st_thread_create( func, p_data, 1, 0 ); - i_ret = 0; - -#elif defined( WIN32 ) || defined( UNDER_CE ) +#if defined( WIN32 ) || defined( UNDER_CE ) { - 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 (see Microsoft * Knowledge Base, article 104641) */ - p_this->thread_id = #if defined( UNDER_CE ) - (HANDLE)CreateThread( NULL, 0, (PTHREAD_START) func, - p_data, 0, &threadID ); + DWORD threadId; + HANDLE hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)func, + (LPVOID)p_data, CREATE_SUSPENDED, + &threadId ); #else - (HANDLE)_beginthreadex( NULL, 0, (PTHREAD_START) func, - p_data, 0, &threadID ); + unsigned threadId; + uintptr_t hThread = _beginthreadex( NULL, 0, + (LPTHREAD_START_ROUTINE)func, + (void*)p_data, CREATE_SUSPENDED, + &threadId ); #endif + p_priv->thread_id.id = (DWORD)threadId; + p_priv->thread_id.hThread = (HANDLE)hThread; + ResumeThread((HANDLE)hThread); } - if ( p_this->thread_id && i_priority ) + i_ret = ( p_priv->thread_id.hThread ? 0 : 1 ); + + if( !i_ret && i_priority ) { - if ( !SetThreadPriority(p_this->thread_id, i_priority) ) + if( !SetThreadPriority(p_priv->thread_id.hThread, i_priority) ) { msg_Warn( p_this, "couldn't set a faster priority" ); i_priority = 0; } } - i_ret = ( p_this->thread_id ? 0 : 1 ); - #elif defined( HAVE_KERNEL_SCHEDULER_H ) - p_this->thread_id = spawn_thread( (thread_func)func, psz_name, + p_priv->thread_id = spawn_thread( (thread_func)func, psz_name, i_priority, p_data ); - i_ret = resume_thread( p_this->thread_id ); + i_ret = resume_thread( p_priv->thread_id ); -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) - i_ret = pthread_create( &p_this->thread_id, NULL, func, p_data ); +#elif defined( LIBVLC_USE_PTHREAD ) + i_ret = pthread_create( &p_priv->thread_id, NULL, func, p_data ); -#if !defined(SYS_BEOS) && defined(PTHREAD_COND_T_IN_PTHREAD_H) - i_ret = config_GetInt( p_this, "rt-priority" ); +#ifndef __APPLE__ + if( config_GetInt( p_this, "rt-priority" ) ) #endif - if( i_ret ) { int i_error, i_policy; struct sched_param param; memset( ¶m, 0, sizeof(struct sched_param) ); -#if !defined(SYS_BEOS) && defined(PTHREAD_COND_T_IN_PTHREAD_H) - i_priority += config_GetInt( p_this, "rt-offset" ); -#endif - if ( i_priority <= 0 ) + if( config_GetType( p_this, "rt-offset" ) ) + { + i_priority += config_GetInt( p_this, "rt-offset" ); + } + if( i_priority <= 0 ) { param.sched_priority = (-1) * i_priority; i_policy = SCHED_OTHER; @@ -593,22 +635,21 @@ int __vlc_thread_create( vlc_object_t *p_this, char * psz_file, int i_line, param.sched_priority = i_priority; i_policy = SCHED_RR; } - if ( (i_error = pthread_setschedparam( p_this->thread_id, + if( (i_error = pthread_setschedparam( p_priv->thread_id, i_policy, ¶m )) ) { - msg_Warn( p_this, "couldn't set thread priority (%s:%d): %s", - psz_file, i_line, strerror(i_error) ); + errno = i_error; + msg_Warn( p_this, "couldn't set thread priority (%s:%d): %m", + psz_file, i_line ); i_priority = 0; } } +#ifndef __APPLE__ else { i_priority = 0; } - -#elif defined( HAVE_CTHREADS_H ) - p_this->thread_id = cthread_fork( (cthread_fn_t)func, (any_t)p_data ); - i_ret = 0; +#endif #endif @@ -617,26 +658,30 @@ int __vlc_thread_create( vlc_object_t *p_this, char * psz_file, int i_line, if( b_wait ) { msg_Dbg( p_this, "waiting for thread completion" ); - vlc_cond_wait( &p_this->object_wait, &p_this->object_lock ); + vlc_object_wait( p_this ); } - p_this->b_thread = 1; + p_priv->b_thread = VLC_TRUE; +#if defined( WIN32 ) || defined( UNDER_CE ) msg_Dbg( p_this, "thread %u (%s) created at priority %d (%s:%d)", - (unsigned int)p_this->thread_id, psz_name, i_priority, + (unsigned int)p_priv->thread_id.id, psz_name, + i_priority, psz_file, i_line ); +#else + msg_Dbg( p_this, "thread %u (%s) created at priority %d (%s:%d)", + (unsigned int)p_priv->thread_id, psz_name, i_priority, psz_file, i_line ); +#endif + vlc_mutex_unlock( &p_this->object_lock ); } else { -#ifdef HAVE_STRERROR - msg_Err( p_this, "%s thread could not be created at %s:%d (%s)", - psz_name, psz_file, i_line, strerror(i_ret) ); -#else - msg_Err( p_this, "%s thread could not be created at %s:%d", + errno = i_ret; + msg_Err( p_this, "%s thread could not be created at %s:%d (%m)", psz_name, psz_file, i_line ); -#endif + vlc_threads_error( p_this ); vlc_mutex_unlock( &p_this->object_lock ); } @@ -647,31 +692,33 @@ int __vlc_thread_create( vlc_object_t *p_this, char * psz_file, int i_line, * vlc_thread_set_priority: set the priority of the current thread when we * couldn't set it in vlc_thread_create (for instance for the main thread) *****************************************************************************/ -int __vlc_thread_set_priority( vlc_object_t *p_this, char * psz_file, +int __vlc_thread_set_priority( vlc_object_t *p_this, const char * psz_file, int i_line, int i_priority ) { - int i_ret; - -#if defined( PTH_INIT_IN_PTH_H ) || defined( ST_INIT_IN_ST_H ) -#elif defined( WIN32 ) || defined( UNDER_CE ) - if ( !SetThreadPriority(GetCurrentThread(), i_priority) ) + vlc_object_internals_t *p_priv = p_this->p_internals; +#if defined( WIN32 ) || defined( UNDER_CE ) + if( !p_priv->thread_id.hThread ) + p_priv->thread_id.hThread = GetCurrentThread(); + if( !SetThreadPriority(p_priv->thread_id.hThread, i_priority) ) { msg_Warn( p_this, "couldn't set a faster priority" ); return 1; } -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) -#if !defined(SYS_BEOS) && defined(PTHREAD_COND_T_IN_PTHREAD_H) - i_ret = config_GetInt( p_this, "rt-priority" ); - if( i_ret ) -#endif +#elif defined( LIBVLC_USE_PTHREAD ) +# ifndef __APPLE__ + if( config_GetInt( p_this, "rt-priority" ) > 0 ) +# endif { int i_error, i_policy; struct sched_param param; memset( ¶m, 0, sizeof(struct sched_param) ); - i_priority += config_GetInt( p_this, "rt-offset" ); - if ( i_priority <= 0 ) + if( config_GetType( p_this, "rt-offset" ) ) + { + i_priority += config_GetInt( p_this, "rt-offset" ); + } + if( i_priority <= 0 ) { param.sched_priority = (-1) * i_priority; i_policy = SCHED_OTHER; @@ -681,13 +728,14 @@ int __vlc_thread_set_priority( vlc_object_t *p_this, char * psz_file, param.sched_priority = i_priority; i_policy = SCHED_RR; } - if ( !p_this->thread_id ) - p_this->thread_id = pthread_self(); - if ( (i_error = pthread_setschedparam( p_this->thread_id, + if( !p_priv->thread_id ) + p_priv->thread_id = pthread_self(); + if( (i_error = pthread_setschedparam( p_priv->thread_id, i_policy, ¶m )) ) { - msg_Warn( p_this, "couldn't set thread priority (%s:%d): %s", - psz_file, i_line, strerror(i_error) ); + errno = i_error; + msg_Warn( p_this, "couldn't set thread priority (%s:%d): %m", + psz_file, i_line ); i_priority = 0; } } @@ -701,33 +749,49 @@ int __vlc_thread_set_priority( vlc_object_t *p_this, char * psz_file, *****************************************************************************/ void __vlc_thread_ready( vlc_object_t *p_this ) { - vlc_mutex_lock( &p_this->object_lock ); - vlc_cond_signal( &p_this->object_wait ); - vlc_mutex_unlock( &p_this->object_lock ); + vlc_object_signal( p_this ); } /***************************************************************************** * vlc_thread_join: wait until a thread exits, inner version *****************************************************************************/ -void __vlc_thread_join( vlc_object_t *p_this, char * psz_file, int i_line ) +void __vlc_thread_join( vlc_object_t *p_this, const char * psz_file, int i_line ) { - int i_ret = 0; - -#if defined( PTH_INIT_IN_PTH_H ) - i_ret = ( pth_join( p_this->thread_id, NULL ) == FALSE ); - -#elif defined( ST_INIT_IN_ST_H ) - i_ret = st_thread_join( p_this->thread_id, NULL ); + vlc_object_internals_t *p_priv = p_this->p_internals; -#elif defined( UNDER_CE ) || defined( WIN32 ) +#if defined( UNDER_CE ) || defined( WIN32 ) HMODULE hmodule; BOOL (WINAPI *OurGetThreadTimes)( HANDLE, FILETIME*, FILETIME*, FILETIME*, FILETIME* ); FILETIME create_ft, exit_ft, kernel_ft, user_ft; int64_t real_time, kernel_time, user_time; + HANDLE hThread; + + /* + ** object will close its thread handle when destroyed, duplicate it here + ** to be on the safe side + */ + if( ! DuplicateHandle(GetCurrentProcess(), + p_priv->thread_id.hThread, + GetCurrentProcess(), + &hThread, + 0, + FALSE, + DUPLICATE_SAME_ACCESS) ) + { + msg_Err( p_this, "thread_join(%u) failed at %s:%d (%s)", + (unsigned int)p_priv->thread_id.id, + psz_file, i_line, GetLastError() ); + vlc_threads_error( p_this ); + p_priv->b_thread = VLC_FALSE; + return; + } - WaitForSingleObject( p_this->thread_id, INFINITE ); + WaitForSingleObject( hThread, INFINITE ); + msg_Dbg( p_this, "thread %u joined (%s:%d)", + (unsigned int)p_priv->thread_id.id, + psz_file, i_line ); #if defined( UNDER_CE ) hmodule = GetModuleHandle( _T("COREDLL") ); #else @@ -738,7 +802,7 @@ void __vlc_thread_join( vlc_object_t *p_this, char * psz_file, int i_line ) GetProcAddress( hmodule, _T("GetThreadTimes") ); if( OurGetThreadTimes && - OurGetThreadTimes( p_this->thread_id, + OurGetThreadTimes( hThread, &create_ft, &exit_ft, &kernel_ft, &user_ft ) ) { real_time = @@ -763,38 +827,36 @@ void __vlc_thread_join( vlc_object_t *p_this, char * psz_file, int i_line ) user_time/60/1000000, (double)((user_time%(60*1000000))/1000000.0) ); } - CloseHandle( p_this->thread_id ); + CloseHandle( hThread ); -#elif defined( HAVE_KERNEL_SCHEDULER_H ) - int32_t exit_value; - wait_for_thread( p_this->thread_id, &exit_value ); +#else /* !defined(WIN32) */ + + int i_ret = 0; -#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) - i_ret = pthread_join( p_this->thread_id, NULL ); +#if defined( HAVE_KERNEL_SCHEDULER_H ) + int32_t exit_value; + i_ret = (B_OK == wait_for_thread( p_priv->thread_id, &exit_value )); -#elif defined( HAVE_CTHREADS_H ) - cthread_join( p_this->thread_id ); - i_ret = 1; +#elif defined( LIBVLC_USE_PTHREAD ) + i_ret = pthread_join( p_priv->thread_id, NULL ); #endif if( i_ret ) { -#ifdef HAVE_STRERROR - msg_Err( p_this, "thread_join(%u) failed at %s:%d (%s)", - (unsigned int)p_this->thread_id, psz_file, i_line, - strerror(i_ret) ); -#else - msg_Err( p_this, "thread_join(%u) failed at %s:%d", - (unsigned int)p_this->thread_id, psz_file, i_line ); -#endif + errno = i_ret; + msg_Err( p_this, "thread_join(%u) failed at %s:%d (%m)", + (unsigned int)p_priv->thread_id, psz_file, i_line ); + vlc_threads_error( p_this ); } else { msg_Dbg( p_this, "thread %u joined (%s:%d)", - (unsigned int)p_this->thread_id, psz_file, i_line ); + (unsigned int)p_priv->thread_id, psz_file, i_line ); } - p_this->b_thread = 0; +#endif + + p_priv->b_thread = VLC_FALSE; }