X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fthreads.c;h=fd84ad7270cc94de9779719290817947eacda60b;hb=29d478ff1e54a3390f576da3c8af937b61a3b0d7;hp=abc83b1c9275bd25d492b874a13e3a4d1dd24ed0;hpb=23afa490b8437080f779fbab6052c860f00f1640;p=vlc diff --git a/src/misc/threads.c b/src/misc/threads.c index abc83b1c92..fd84ad7270 100644 --- a/src/misc/threads.c +++ b/src/misc/threads.c @@ -1,13 +1,14 @@ /***************************************************************************** * threads.c : threads implementation for the VideoLAN client ***************************************************************************** - * Copyright (C) 1999-2007 the VideoLAN team + * Copyright (C) 1999-2008 the VideoLAN team * $Id$ * * Authors: Jean-Marc Dressler * Samuel Hocevar * Gildas Bazin * Clément Sténac + * Rémi Denis-Courmont * * 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 @@ -28,532 +29,96 @@ # include "config.h" #endif -#include +#include #include "libvlc.h" #include +#include #ifdef HAVE_UNISTD_H # include #endif -#define VLC_THREADS_UNINITIALIZED 0 -#define VLC_THREADS_PENDING 1 -#define VLC_THREADS_ERROR 2 -#define VLC_THREADS_READY 3 - -/***************************************************************************** - * Global mutex for lazy initialization of the threads system - *****************************************************************************/ -static volatile unsigned i_initializations = 0; -static vlc_object_t *p_root; - -#if defined( UNDER_CE ) -#elif defined( WIN32 ) -#elif defined( HAVE_KERNEL_SCHEDULER_H ) -#elif defined( LIBVLC_USE_PTHREAD ) -static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif - -vlc_threadvar_t msg_context_global_key; - -#if defined(LIBVLC_USE_PTHREAD) -static inline unsigned long vlc_threadid (void) -{ - union { pthread_t th; unsigned long int i; } v = { }; - v.th = pthread_self (); - return v.i; -} - - -/***************************************************************************** - * vlc_thread_fatal: Report an error from the threading layer - ***************************************************************************** - * This is mostly meant for debugging. - *****************************************************************************/ -void vlc_pthread_fatal (const char *action, int error, - const char *file, unsigned line) -{ - fprintf (stderr, "LibVLC fatal error %s in thread %lu at %s:%u: %d\n", - action, vlc_threadid (), file, line, error); - fflush (stderr); - - /* Sometimes strerror_r() crashes too, so make sure we print an error - * message before we invoke it */ -#ifdef __GLIBC__ - /* Avoid the strerror_r() prototype brain damage in glibc */ - errno = error; - fprintf (stderr, " Error message: %m\n"); -#else - char buf[1000]; - const char *msg; - - switch (strerror_r (error, buf, sizeof (buf))) - { - case 0: - msg = buf; - break; - case ERANGE: /* should never happen */ - msg = "unknwon (too big to display)"; - break; - default: - msg = "unknown (invalid error number)"; - break; - } - fprintf (stderr, " Error message: %s\n", msg); -#endif - - fflush (stderr); - abort (); -} -#endif - - -/***************************************************************************** - * vlc_threads_init: initialize threads system - ***************************************************************************** - * This function requires lazy initialization of a global lock in order to - * keep the library really thread-safe. Some architectures don't support this - * and thus do not guarantee the complete reentrancy. - *****************************************************************************/ -int __vlc_threads_init( vlc_object_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( UNDER_CE ) -#elif defined( WIN32 ) -#elif defined( HAVE_KERNEL_SCHEDULER_H ) -#elif defined( LIBVLC_USE_PTHREAD ) - pthread_mutex_lock( &once_mutex ); -#endif - - if( i_initializations == 0 ) - { - /* We should be safe now. Do all the initialization stuff we want. */ - p_libvlc_global->b_ready = false; - - p_root = vlc_custom_create( VLC_OBJECT(p_libvlc_global), 0, - VLC_OBJECT_GLOBAL, "global" ); - if( p_root == NULL ) - { - i_ret = VLC_ENOMEM; - goto out; - } - vlc_threadvar_create( p_root, &msg_context_global_key ); - } - i_initializations++; - -out: - /* If we have lazy mutex initialization support, unlock the mutex. - * Otherwize, we are screwed. */ -#if defined( UNDER_CE ) -#elif defined( WIN32 ) -#elif defined( HAVE_KERNEL_SCHEDULER_H ) -#elif defined( LIBVLC_USE_PTHREAD ) - pthread_mutex_unlock( &once_mutex ); -#endif - - return i_ret; -} - -/***************************************************************************** - * vlc_threads_end: stop threads system - ***************************************************************************** - * FIXME: This function is far from being threadsafe. - *****************************************************************************/ -int __vlc_threads_end( vlc_object_t *p_this ) -{ - (void)p_this; -#if defined( UNDER_CE ) -#elif defined( WIN32 ) -#elif defined( HAVE_KERNEL_SCHEDULER_H ) -#elif defined( LIBVLC_USE_PTHREAD ) - pthread_mutex_lock( &once_mutex ); -#endif - - assert( i_initializations > 0 ); - if( --i_initializations == 0 ) - vlc_object_release( p_root ); - -#if defined( UNDER_CE ) -#elif defined( WIN32 ) -#elif defined( HAVE_KERNEL_SCHEDULER_H ) -#elif defined( LIBVLC_USE_PTHREAD ) - pthread_mutex_unlock( &once_mutex ); -#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 - *****************************************************************************/ -int __vlc_mutex_init( vlc_mutex_t *p_mutex ) -{ -#if defined( UNDER_CE ) - InitializeCriticalSection( &p_mutex->csection ); - return 0; - -#elif defined( WIN32 ) - *p_mutex = CreateMutex( 0, FALSE, 0 ); - return (*p_mutex != NULL) ? 0 : ENOMEM; - -#elif defined( HAVE_KERNEL_SCHEDULER_H ) - /* check the arguments and whether it's already been initialized */ - if( p_mutex == NULL ) - { - return B_BAD_VALUE; - } - - if( p_mutex->init == 9999 ) - { - return EALREADY; - } - - p_mutex->lock = create_sem( 1, "BeMutex" ); - if( p_mutex->lock < B_NO_ERROR ) - { - return( -1 ); - } - - p_mutex->init = 9999; - return B_OK; - -#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 - i_result = pthread_mutex_init( p_mutex, &attr ); - pthread_mutexattr_destroy( &attr ); - return i_result; -#endif -} - -/***************************************************************************** - * vlc_mutex_init: initialize a recursive mutex (Do not use) - *****************************************************************************/ -int __vlc_mutex_init_recursive( vlc_mutex_t *p_mutex ) -{ -#if defined( WIN32 ) - /* Create mutex returns a recursive mutex */ - *p_mutex = CreateMutex( 0, FALSE, 0 ); - return (*p_mutex != NULL) ? 0 : ENOMEM; -#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, &attr ); - pthread_mutexattr_destroy( &attr ); - return( i_result ); -#else -# error Unimplemented! -#endif -} - - -/***************************************************************************** - * vlc_mutex_destroy: destroy a mutex, inner version - *****************************************************************************/ -void __vlc_mutex_destroy( const char * psz_file, int i_line, vlc_mutex_t *p_mutex ) -{ -#if defined( UNDER_CE ) - VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); - - DeleteCriticalSection( &p_mutex->csection ); - -#elif defined( WIN32 ) - VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); - - CloseHandle( *p_mutex ); - -#elif defined( HAVE_KERNEL_SCHEDULER_H ) - if( p_mutex->init == 9999 ) - delete_sem( p_mutex->lock ); - - p_mutex->init = 0; - -#elif defined( LIBVLC_USE_PTHREAD ) - int val = pthread_mutex_destroy( p_mutex ); - VLC_THREAD_ASSERT ("destroying mutex"); - -#endif -} - -/***************************************************************************** - * vlc_cond_init: initialize a condition - *****************************************************************************/ -int __vlc_cond_init( vlc_cond_t *p_condvar ) -{ -#if defined( UNDER_CE ) || defined( WIN32 ) - /* Initialize counter */ - p_condvar->i_waiting_threads = 0; - - /* Create an auto-reset event. */ - p_condvar->event = CreateEvent( NULL, /* no security */ - FALSE, /* auto-reset event */ - FALSE, /* start non-signaled */ - NULL ); /* unnamed */ - return !p_condvar->event; - -#elif defined( HAVE_KERNEL_SCHEDULER_H ) - if( !p_condvar ) - { - return B_BAD_VALUE; - } - - if( p_condvar->init == 9999 ) - { - return EALREADY; - } - - p_condvar->thread = -1; - p_condvar->init = 9999; - return 0; - -#elif defined( LIBVLC_USE_PTHREAD ) - pthread_condattr_t attr; - int ret; - - ret = pthread_condattr_init (&attr); - if (ret) - return ret; - -# 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, &attr); - pthread_condattr_destroy (&attr); - return ret; - +#if defined( LIBVLC_USE_PTHREAD ) +# include #endif -} -/***************************************************************************** - * vlc_cond_destroy: destroy a condition, inner version - *****************************************************************************/ -void __vlc_cond_destroy( const char * psz_file, int i_line, vlc_cond_t *p_condvar ) +struct vlc_thread_boot { -#if defined( UNDER_CE ) || defined( WIN32 ) - VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); + void * (*entry) (vlc_object_t *); + vlc_object_t *object; +}; - CloseHandle( p_condvar->event ); - -#elif defined( HAVE_KERNEL_SCHEDULER_H ) - p_condvar->init = 0; - -#elif defined( LIBVLC_USE_PTHREAD ) - int val = pthread_cond_destroy( p_condvar ); - VLC_THREAD_ASSERT ("destroying condition"); - -#endif -} - -/***************************************************************************** - * vlc_tls_create: create a thread-local variable - *****************************************************************************/ -int __vlc_threadvar_create( vlc_threadvar_t *p_tls ) +static void *thread_entry (void *data) { - int i_ret = -1; + vlc_object_t *obj = ((struct vlc_thread_boot *)data)->object; + void *(*func) (vlc_object_t *) = ((struct vlc_thread_boot *)data)->entry; -#if defined( HAVE_KERNEL_SCHEDULER_H ) -# error Unimplemented! -#elif defined( UNDER_CE ) -#elif defined( WIN32 ) - *p_tls = TlsAlloc(); - i_ret = (*p_tls == INVALID_HANDLE_VALUE) ? EAGAIN : 0; + free (data); + msg_Dbg (obj, "thread started"); + func (obj); + msg_Dbg (obj, "thread ended"); -#elif defined( LIBVLC_USE_PTHREAD ) - i_ret = pthread_key_create( p_tls, NULL ); -#endif - return i_ret; + return NULL; } +#undef vlc_thread_create /***************************************************************************** - * vlc_thread_create: create a thread, inner version + * vlc_thread_create: create a thread ***************************************************************************** * 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, const char * psz_file, int i_line, - const char *psz_name, void * ( *func ) ( void * ), - int i_priority, bool b_wait ) +int vlc_thread_create( vlc_object_t *p_this, const char * psz_file, int i_line, + const char *psz_name, void *(*func) ( vlc_object_t * ), + int i_priority ) { int i_ret; - void *p_data = (void *)p_this; vlc_object_internals_t *p_priv = vlc_internals( p_this ); - vlc_mutex_lock( &p_this->object_lock ); + struct vlc_thread_boot *boot = malloc (sizeof (*boot)); + if (boot == NULL) + return errno; + boot->entry = func; + boot->object = p_this; -#if defined( WIN32 ) || defined( UNDER_CE ) - { - /* 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) */ -#if defined( UNDER_CE ) - DWORD threadId; - HANDLE hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)func, - (LPVOID)p_data, CREATE_SUSPENDED, - &threadId ); -#else - 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); - } - - i_ret = ( p_priv->thread_id.hThread ? 0 : 1 ); - - if( !i_ret && i_priority ) - { - if( !SetThreadPriority(p_priv->thread_id.hThread, i_priority) ) - { - msg_Warn( p_this, "couldn't set a faster priority" ); - i_priority = 0; - } - } - -#elif defined( HAVE_KERNEL_SCHEDULER_H ) - p_priv->thread_id = spawn_thread( (thread_func)func, psz_name, - i_priority, p_data ); - i_ret = resume_thread( p_priv->thread_id ); - -#elif defined( LIBVLC_USE_PTHREAD ) - i_ret = pthread_create( &p_priv->thread_id, NULL, func, p_data ); - -#ifndef __APPLE__ - if( config_GetInt( p_this, "rt-priority" ) ) -#endif - { - int i_error, i_policy; - struct sched_param param; - - memset( ¶m, 0, sizeof(struct sched_param) ); - 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; - } - else - { - param.sched_priority = i_priority; - i_policy = SCHED_RR; - } - if( (i_error = pthread_setschedparam( p_priv->thread_id, - i_policy, ¶m )) ) - { - 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; - } -#endif - -#endif + /* Make sure we don't re-create a thread if the object has already one */ + assert( !p_priv->b_thread ); + p_priv->b_thread = true; + i_ret = vlc_clone( &p_priv->thread_id, thread_entry, boot, i_priority ); if( i_ret == 0 ) - { - if( b_wait ) - { - msg_Dbg( p_this, "waiting for thread completion" ); - vlc_object_wait( p_this ); - } - - p_priv->b_thread = 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_priv->thread_id, psz_name, i_priority, - psz_file, i_line ); -#endif - - - vlc_mutex_unlock( &p_this->object_lock ); - } + msg_Dbg( p_this, "thread (%s) created at priority %d (%s:%d)", + psz_name, i_priority, psz_file, i_line ); else { + p_priv->b_thread = false; errno = i_ret; msg_Err( p_this, "%s thread could not be created at %s:%d (%m)", psz_name, psz_file, i_line ); - vlc_mutex_unlock( &p_this->object_lock ); } return i_ret; } +#undef vlc_thread_set_priority /***************************************************************************** * 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, const char * psz_file, - int i_line, int i_priority ) +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 = vlc_internals( p_this ); -#if defined( WIN32 ) || defined( UNDER_CE ) - VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); - if( !p_priv->thread_id.hThread ) - p_priv->thread_id.hThread = GetCurrentThread(); - if( !SetThreadPriority(p_priv->thread_id.hThread, i_priority) ) + if( !p_priv->b_thread ) { - msg_Warn( p_this, "couldn't set a faster priority" ); - return 1; + msg_Err( p_this, "couldn't set priority of non-existent thread" ); + return ESRCH; } -#elif defined( LIBVLC_USE_PTHREAD ) +#if defined( LIBVLC_USE_PTHREAD ) # ifndef __APPLE__ - if( config_GetInt( p_this, "rt-priority" ) > 0 ) + if( var_InheritBool( p_this, "rt-priority" ) ) # endif { int i_error, i_policy; @@ -561,9 +126,7 @@ int __vlc_thread_set_priority( vlc_object_t *p_this, const char * psz_file, memset( ¶m, 0, sizeof(struct sched_param) ); if( config_GetType( p_this, "rt-offset" ) ) - { - i_priority += config_GetInt( p_this, "rt-offset" ); - } + i_priority += var_InheritInteger( p_this, "rt-offset" ); if( i_priority <= 0 ) { param.sched_priority = (-1) * i_priority; @@ -574,10 +137,8 @@ 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_priv->thread_id ) - p_priv->thread_id = pthread_self(); if( (i_error = pthread_setschedparam( p_priv->thread_id, - i_policy, ¶m )) ) + i_policy, ¶m )) ) { errno = i_error; msg_Warn( p_this, "couldn't set thread priority (%s:%d): %m", @@ -585,70 +146,57 @@ int __vlc_thread_set_priority( vlc_object_t *p_this, const char * psz_file, i_priority = 0; } } + +#elif defined( WIN32 ) || defined( UNDER_CE ) + VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); + +#ifndef UNDER_CE + if( !SetThreadPriority(p_priv->thread_id, i_priority) ) +#else + if( !SetThreadPriority(p_priv->thread_id->handle, i_priority) ) #endif + { + msg_Warn( p_this, "couldn't set a faster priority" ); + return 1; + } - return 0; -} +#endif -/***************************************************************************** - * vlc_thread_ready: tell the parent thread we were successfully spawned - *****************************************************************************/ -void __vlc_thread_ready( vlc_object_t *p_this ) -{ - vlc_object_signal( p_this ); + return 0; } +#undef vlc_thread_join /***************************************************************************** * vlc_thread_join: wait until a thread exits, inner version *****************************************************************************/ -void __vlc_thread_join( vlc_object_t *p_this, const char * psz_file, int i_line ) +void vlc_thread_join( vlc_object_t *p_this ) { vlc_object_internals_t *p_priv = vlc_internals( p_this ); -#if defined( UNDER_CE ) || defined( WIN32 ) - HMODULE hmodule; - BOOL (WINAPI *OurGetThreadTimes)( HANDLE, FILETIME*, FILETIME*, - FILETIME*, FILETIME* ); +#if defined( WIN32 ) && !defined( UNDER_CE ) + HANDLE hThread; 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, + p_priv->thread_id, GetCurrentProcess(), &hThread, 0, FALSE, DUPLICATE_SAME_ACCESS) ) { - msg_Err( p_this, "thread_join(%u) failed at %s:%d (%u)", - (unsigned int)p_priv->thread_id.id, - psz_file, i_line, (unsigned int)GetLastError() ); p_priv->b_thread = false; - return; + return; /* We have a problem! */ } - - 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 - hmodule = GetModuleHandle( _T("KERNEL32") ); #endif - OurGetThreadTimes = (BOOL (WINAPI*)( HANDLE, FILETIME*, FILETIME*, - FILETIME*, FILETIME* )) - GetProcAddress( hmodule, _T("GetThreadTimes") ); - if( OurGetThreadTimes && - OurGetThreadTimes( hThread, - &create_ft, &exit_ft, &kernel_ft, &user_ft ) ) + vlc_join( p_priv->thread_id, NULL ); + +#if defined( WIN32 ) && !defined( UNDER_CE ) + /* FIXME: this could work on WinCE too... except that it seems always to + * return 0 for exit_ft and kernel_ft */ + if( GetThreadTimes( hThread, &create_ft, &exit_ft, &kernel_ft, &user_ft ) ) { real_time = ((((int64_t)exit_ft.dwHighDateTime)<<32)| exit_ft.dwLowDateTime) - @@ -673,38 +221,37 @@ void __vlc_thread_join( vlc_object_t *p_this, const char * psz_file, int i_line (double)((user_time%(60*1000000))/1000000.0) ); } CloseHandle( hThread ); +#endif -#else /* !defined(WIN32) */ + p_priv->b_thread = false; +} - int i_ret = 0; +void vlc_thread_cancel (vlc_object_t *obj) +{ + vlc_object_internals_t *priv = vlc_internals (obj); -#if defined( HAVE_KERNEL_SCHEDULER_H ) - int32_t exit_value; - i_ret = (B_OK == wait_for_thread( p_priv->thread_id, &exit_value )); + if (priv->b_thread) + vlc_cancel (priv->thread_id); +} -#elif defined( LIBVLC_USE_PTHREAD ) - /* Make sure we do return if we are calling vlc_thread_join() - * from the joined thread */ - if (pthread_equal (pthread_self (), p_priv->thread_id)) - i_ret = pthread_detach (p_priv->thread_id); - else - i_ret = pthread_join (p_priv->thread_id, NULL); -#endif +/*** Global locks ***/ - if( i_ret ) - { - 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 ); - } +void vlc_global_mutex (unsigned n, bool acquire) +{ + static vlc_mutex_t locks[] = { + VLC_STATIC_MUTEX, + VLC_STATIC_MUTEX, + VLC_STATIC_MUTEX, + }; + assert (n < (sizeof (locks) / sizeof (locks[0]))); + vlc_mutex_t *lock = locks + n; + + if (acquire) + vlc_mutex_lock (lock); else - { - msg_Dbg( p_this, "thread %u joined (%s:%d)", - (unsigned int)p_priv->thread_id, psz_file, i_line ); - } + vlc_mutex_unlock (lock); -#endif - - p_priv->b_thread = false; + /* Compile-time assertion ;-) */ + char enough_locks[(sizeof (locks) / sizeof (locks[0])) - VLC_MAX_MUTEX]; + (void) enough_locks; } -