X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fthreads.c;h=ffd09f683f92708df4529114a33db85edaaee465;hb=6ee1e193fd896ab9a4729fde14f009d9ce629815;hp=367511be2df359986856a8f5ea7e38b617df3d86;hpb=651078ecf9be6d0bb9c2323023ebb7fbd7f0d145;p=vlc diff --git a/src/misc/threads.c b/src/misc/threads.c index 367511be2d..ffd09f683f 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 @@ -25,7 +26,7 @@ #include -#include +#include "libvlc.h" #define VLC_THREADS_UNINITIALIZED 0 #define VLC_THREADS_PENDING 1 @@ -43,12 +44,35 @@ static vlc_object_t *p_root; #elif defined( ST_INIT_IN_ST_H ) #elif 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; +static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER; #elif defined( HAVE_CTHREADS_H ) #endif +vlc_threadvar_t msg_context_global_key; + /***************************************************************************** * vlc_threads_init: initialize threads system ***************************************************************************** @@ -67,6 +91,12 @@ int __vlc_threads_init( vlc_object_t *p_this ) #elif defined( ST_INIT_IN_ST_H ) #elif 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 ) pthread_mutex_lock( &once_mutex ); @@ -99,18 +129,11 @@ int __vlc_threads_init( vlc_object_t *p_this ) hInstLib = LoadLibrary( "kernel32" ); if( hInstLib ) { - p_libvlc_global->SignalObjectAndWait = + pf_SignalObjectAndWait = (SIGNALOBJECTANDWAIT)GetProcAddress( hInstLib, "SignalObjectAndWait" ); } } - else - { - p_libvlc_global->SignalObjectAndWait = NULL; - } - - p_libvlc_global->b_fast_mutex = 0; - p_libvlc_global->i_win9x_cv = 0; #elif defined( HAVE_KERNEL_SCHEDULER_H ) #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) @@ -130,6 +153,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 { @@ -170,6 +195,7 @@ int __vlc_threads_init( vlc_object_t *p_this ) *****************************************************************************/ int __vlc_threads_end( vlc_object_t *p_this ) { + (void)p_this; #if defined( PTH_INIT_IN_PTH_H ) #elif defined( ST_INIT_IN_ST_H ) #elif defined( UNDER_CE ) @@ -230,8 +256,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_global->SignalObjectAndWait && - !p_this->p_libvlc_global->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 ); @@ -380,11 +405,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_global->i_win9x_cv; - p_condvar->SignalObjectAndWait = p_this->p_libvlc_global->SignalObjectAndWait; + p_condvar->i_win9x_cv = i_win9x_cv; + p_condvar->SignalObjectAndWait = pf_SignalObjectAndWait; - if( (p_condvar->SignalObjectAndWait && - !p_this->p_libvlc_global->b_fast_mutex) + if( (p_condvar->SignalObjectAndWait && !b_fast_mutex) || p_condvar->i_win9x_cv == 0 ) { /* Create an auto-reset event. */ @@ -472,7 +496,7 @@ int __vlc_cond_destroy( const 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; @@ -505,29 +529,26 @@ int __vlc_cond_destroy( const char * psz_file, int i_line, vlc_cond_t *p_condvar *****************************************************************************/ int __vlc_threadvar_create( vlc_object_t *p_this, vlc_threadvar_t *p_tls ) { + int i_ret = -1; + (void)p_this; #if defined( PTH_INIT_IN_PTH_H ) + i_ret = pth_key_create( &p_tls->handle, NULL ); #elif defined( HAVE_KERNEL_SCHEDULER_H ) -#elif defined( ST_INIT_IN_ST_H ) msg_Err( p_this, "TLS not implemented" ); - return VLC_EGENERIC; - + i_ret VLC_EGENERIC; +#elif defined( ST_INIT_IN_ST_H ) + i_ret = st_key_create( &p_tls->handle, NULL ); #elif defined( UNDER_CE ) || defined( WIN32 ) #elif defined( WIN32 ) p_tls->handle = TlsAlloc(); - if( p_tls->handle == 0xFFFFFFFF ) - { - return VLC_EGENERIC; - } - - msg_Err( p_this, "TLS not implemented" ); - return VLC_EGENERIC; + i_ret = !( p_tls->handle == 0xFFFFFFFF ); #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) - return pthread_key_create( &p_tls->handle, NULL ); - + i_ret = pthread_key_create( &p_tls->handle, NULL ); #elif defined( HAVE_CTHREADS_H ) - return cthread_keycreate( &p_tls-handle ); + i_ret = cthread_keycreate( &p_tls-handle ); #endif + return i_ret; } /***************************************************************************** @@ -542,52 +563,59 @@ int __vlc_thread_create( vlc_object_t *p_this, const char * psz_file, int i_line { 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; + p_priv->thread_id = pth_spawn( PTH_ATTR_DEFAULT, func, p_data ); + i_ret = p_priv->thread_id == NULL; #elif defined( ST_INIT_IN_ST_H ) - p_this->thread_id = st_thread_create( func, p_data, 1, 0 ); + p_priv->thread_id = st_thread_create( func, p_data, 1, 0 ); i_ret = 0; #elif 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 ); + i_ret = pthread_create( &p_priv->thread_id, NULL, func, p_data ); #ifndef __APPLE__ if( config_GetInt( p_this, "rt-priority" ) ) @@ -611,7 +639,7 @@ int __vlc_thread_create( vlc_object_t *p_this, const 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", @@ -627,7 +655,7 @@ int __vlc_thread_create( vlc_object_t *p_this, const char * psz_file, int i_line #endif #elif defined( HAVE_CTHREADS_H ) - p_this->thread_id = cthread_fork( (cthread_fn_t)func, (any_t)p_data ); + p_priv->thread_id = cthread_fork( (cthread_fn_t)func, (any_t)p_data ); i_ret = 0; #endif @@ -640,11 +668,18 @@ int __vlc_thread_create( vlc_object_t *p_this, const char * psz_file, int i_line vlc_cond_wait( &p_this->object_wait, &p_this->object_lock ); } - 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_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_this->thread_id, psz_name, i_priority, + (unsigned int)p_priv->thread_id, psz_name, i_priority, psz_file, i_line ); +#endif + vlc_mutex_unlock( &p_this->object_lock ); } @@ -665,18 +700,21 @@ int __vlc_thread_create( vlc_object_t *p_this, const char * psz_file, int i_line int __vlc_thread_set_priority( vlc_object_t *p_this, const char * psz_file, int i_line, int i_priority ) { + vlc_object_internals_t *p_priv = p_this->p_internals; #if defined( PTH_INIT_IN_PTH_H ) || defined( ST_INIT_IN_ST_H ) #elif defined( WIN32 ) || defined( UNDER_CE ) - if( !SetThreadPriority(GetCurrentThread(), i_priority) ) + 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 ) -#ifndef __APPLE__ - if( config_GetInt( p_this, "rt-priority" ) ) -#endif +# ifndef __APPLE__ + if( config_GetInt( p_this, "rt-priority" ) > 0 ) +# endif { int i_error, i_policy; struct sched_param param; @@ -696,9 +734,9 @@ int __vlc_thread_set_priority( vlc_object_t *p_this, const 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", @@ -726,23 +764,40 @@ void __vlc_thread_ready( vlc_object_t *p_this ) *****************************************************************************/ void __vlc_thread_join( vlc_object_t *p_this, const char * psz_file, int i_line ) { - int i_ret = 0; + vlc_object_internals_t *p_priv = p_this->p_internals; -#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 ); - -#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() ); + 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 @@ -753,7 +808,7 @@ void __vlc_thread_join( vlc_object_t *p_this, const 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 = @@ -778,17 +833,27 @@ void __vlc_thread_join( vlc_object_t *p_this, const char * psz_file, int i_line user_time/60/1000000, (double)((user_time%(60*1000000))/1000000.0) ); } - CloseHandle( p_this->thread_id ); + CloseHandle( hThread ); + +#else /* !defined(WIN32) */ + + int i_ret = 0; + +#if defined( PTH_INIT_IN_PTH_H ) + i_ret = ( pth_join( p_priv->thread_id, NULL ) == FALSE ); + +#elif defined( ST_INIT_IN_ST_H ) + i_ret = st_thread_join( p_priv->thread_id, NULL ); #elif defined( HAVE_KERNEL_SCHEDULER_H ) int32_t exit_value; - wait_for_thread( p_this->thread_id, &exit_value ); + i_ret = (B_OK == wait_for_thread( p_priv->thread_id, &exit_value )); #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) - i_ret = pthread_join( p_this->thread_id, NULL ); + i_ret = pthread_join( p_priv->thread_id, NULL ); #elif defined( HAVE_CTHREADS_H ) - cthread_join( p_this->thread_id ); + cthread_join( p_priv->thread_id ); i_ret = 1; #endif @@ -796,15 +861,17 @@ void __vlc_thread_join( vlc_object_t *p_this, const char * psz_file, int i_line if( i_ret ) { msg_Err( p_this, "thread_join(%u) failed at %s:%d (%s)", - (unsigned int)p_this->thread_id, psz_file, i_line, + (unsigned int)p_priv->thread_id, psz_file, i_line, strerror(i_ret) ); } 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; }