* This header provides a portable threads implementation.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: threads.h,v 1.21 2001/07/25 08:41:21 gbazin Exp $
+ * $Id: threads.h,v 1.34 2002/01/04 14:01:34 sam Exp $
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr>
#include <stdio.h>
-#ifdef PROFILING
+#if defined(GPROF) || defined(DEBUG)
# include <sys/time.h>
#endif
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) /* pthreads (like Linux & BSD) */
# include <pthread.h>
+/* This is not prototyped under Linux, though it exists. */
+int pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind );
#elif defined( HAVE_CTHREADS_H ) /* GNUMach */
# include <cthreads.h>
# include <byteorder.h>
#elif defined( WIN32 )
+#define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <process.h>
* Prototypes
*****************************************************************************/
-static __inline__ int vlc_threads_init ( void );
-static __inline__ int vlc_threads_end ( void );
+#ifdef GPROF
+/* Wrapper function for profiling */
+static void * vlc_thread_wrapper ( void *p_wrapper );
-static __inline__ int vlc_mutex_init ( vlc_mutex_t * );
-static __inline__ int vlc_mutex_lock ( vlc_mutex_t * );
-static __inline__ int vlc_mutex_unlock ( vlc_mutex_t * );
-static __inline__ int vlc_mutex_destroy ( vlc_mutex_t * );
+# ifdef WIN32
-static __inline__ int vlc_cond_init ( vlc_cond_t * );
-static __inline__ int vlc_cond_signal ( vlc_cond_t * );
-static __inline__ int vlc_cond_wait ( vlc_cond_t *, vlc_mutex_t * );
-static __inline__ int vlc_cond_destroy ( vlc_cond_t * );
+# define ITIMER_REAL 1
+# define ITIMER_PROF 2
-static __inline__ int vlc_thread_create ( vlc_thread_t *, char *,
- vlc_thread_func_t, void * );
-static __inline__ void vlc_thread_exit ( void );
-static __inline__ void vlc_thread_join ( vlc_thread_t );
+struct itimerval
+{
+ struct timeval it_value;
+ struct timeval it_interval;
+};
-#if 0
-static __inline__ int vlc_cond_timedwait( vlc_cond_t *, vlc_mutex_t *,
- mtime_t );
-#endif
+int setitimer(int kind, const struct itimerval* itnew, struct itimerval* itold);
-#ifdef PROFILING
-/* Wrapper function for profiling */
-static void * vlc_thread_wrapper ( void *p_wrapper );
+# endif /* WIN32 */
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 /* PROFILING */
+#endif /* GPROF */
/*****************************************************************************
* vlc_threads_init: initialize threads system
return pth_mutex_init( p_mutex );
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
+# if defined(DEBUG) && defined(SYS_LINUX)
+ /* Create error-checking mutex to detect threads problems more easily. */
+ pthread_mutexattr_t attr;
+ int i_result;
+
+ pthread_mutexattr_init( &attr );
+ pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ERRORCHECK_NP );
+ i_result = pthread_mutex_init( p_mutex, &attr );
+ pthread_mutexattr_destroy( &attr );
+ return( i_result );
+# endif
+
return pthread_mutex_init( p_mutex, NULL );
#elif defined( HAVE_CTHREADS_H )
/*****************************************************************************
* vlc_mutex_lock: lock a mutex
*****************************************************************************/
-static __inline__ int vlc_mutex_lock( vlc_mutex_t *p_mutex )
+#ifdef DEBUG
+# define vlc_mutex_lock( P_MUTEX ) \
+ _vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
+#else
+# define vlc_mutex_lock( P_MUTEX ) \
+ _vlc_mutex_lock( NULL, 0, P_MUTEX )
+#endif
+
+static __inline__ int _vlc_mutex_lock( char * psz_file, int i_line,
+ vlc_mutex_t *p_mutex )
{
#if defined( PTH_INIT_IN_PTH_H )
return pth_mutex_acquire( p_mutex, TRUE, NULL );
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
- return pthread_mutex_lock( p_mutex );
+ int i_return = pthread_mutex_lock( p_mutex );
+ if( i_return )
+ {
+ intf_ErrMsg( "thread %d error: mutex_lock failed at %s:%d (%s)",
+ pthread_self(), psz_file, i_line, strerror(i_return) );
+ }
+ return i_return;
#elif defined( HAVE_CTHREADS_H )
mutex_lock( p_mutex );
/*****************************************************************************
* vlc_mutex_unlock: unlock a mutex
*****************************************************************************/
-static __inline__ int vlc_mutex_unlock( vlc_mutex_t *p_mutex )
+#ifdef DEBUG
+# define vlc_mutex_unlock( P_MUTEX ) \
+ _vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
+#else
+# define vlc_mutex_unlock( P_MUTEX ) \
+ _vlc_mutex_unlock( NULL, 0, P_MUTEX )
+#endif
+
+static __inline__ int _vlc_mutex_unlock( char * psz_file, int i_line,
+ vlc_mutex_t *p_mutex )
{
#if defined( PTH_INIT_IN_PTH_H )
return pth_mutex_release( p_mutex );
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
- return pthread_mutex_unlock( p_mutex );
+ int i_return = pthread_mutex_unlock( p_mutex );
+ if( i_return )
+ {
+ intf_ErrMsg( "thread %d error: mutex_unlock failed at %s:%d (%s)",
+ pthread_self(), psz_file, i_line, strerror(i_return) );
+ }
+ return i_return;
#elif defined( HAVE_CTHREADS_H )
mutex_unlock( p_mutex );
/*****************************************************************************
* vlc_mutex_destroy: destroy a mutex
*****************************************************************************/
-static __inline__ int vlc_mutex_destroy( vlc_mutex_t *p_mutex )
+#ifdef DEBUG
+# define vlc_mutex_destroy( P_MUTEX ) \
+ _vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
+#else
+# define vlc_mutex_destroy( P_MUTEX ) \
+ _vlc_mutex_destroy( NULL, 0, P_MUTEX )
+#endif
+
+static __inline__ int _vlc_mutex_destroy( char * psz_file, int i_line,
+ vlc_mutex_t *p_mutex )
{
#if defined( PTH_INIT_IN_PTH_H )
return 0;
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
- return pthread_mutex_destroy( p_mutex );
+ int i_return = pthread_mutex_destroy( p_mutex );
+ if( i_return )
+ {
+ intf_ErrMsg( "thread %d error: mutex_destroy failed at %s:%d (%s)",
+ pthread_self(), psz_file, i_line, strerror(i_return) );
+ }
+ return i_return;
+
+#elif defined( HAVE_CTHREADS_H )
+ return 0;
#elif defined( HAVE_KERNEL_SCHEDULER_H )
if( p_mutex->init == 9999 )
/* Create an auto-reset event. */
p_condvar->signal = CreateEvent( NULL, /* no security */
- FALSE, /* auto-reset event */
- FALSE, /* non-signaled initially */
- NULL ); /* unnamed */
+ FALSE, /* auto-reset event */
+ FALSE, /* non-signaled initially */
+ NULL ); /* unnamed */
return( !p_condvar->signal );
/* 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 */
- while( p_condvar->i_waiting_threads )
+ 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 */
/*****************************************************************************
* vlc_cond_wait: wait until condition completion
*****************************************************************************/
-static __inline__ int vlc_cond_wait( vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex )
+#ifdef DEBUG
+# define vlc_cond_wait( P_COND, P_MUTEX ) \
+ _vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX )
+#else
+# define vlc_cond_wait( P_COND, P_MUTEX ) \
+ _vlc_cond_wait( NULL, 0, P_COND, P_MUTEX )
+#endif
+
+static __inline__ int _vlc_cond_wait( char * psz_file, int i_line,
+ vlc_cond_t *p_condvar,
+ vlc_mutex_t *p_mutex )
{
#if defined( PTH_INIT_IN_PTH_H )
return pth_cond_await( p_condvar, p_mutex, NULL );
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
+
+#ifndef DEBUG
return pthread_cond_wait( p_condvar, p_mutex );
+#else
+ /* In debug mode, timeout */
+ struct timeval now;
+ struct timespec timeout;
+ int i_result;
+
+ for( ; ; )
+ {
+ gettimeofday( &now, NULL );
+ 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 )) )
+ {
+ 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) );
+ }
+ else
+ {
+ return i_result;
+ }
+ }
+#endif
#elif defined( HAVE_CTHREADS_H )
condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
/*****************************************************************************
* vlc_cond_destroy: destroy a condition
*****************************************************************************/
-static __inline__ int vlc_cond_destroy( vlc_cond_t *p_condvar )
+#ifdef DEBUG
+# define vlc_cond_destroy( P_COND ) \
+ _vlc_cond_destroy( __FILE__, __LINE__, P_COND )
+#else
+# define vlc_cond_destroy( P_COND ) \
+ _vlc_cond_destroy( NULL, 0, P_COND )
+#endif
+
+static __inline__ int _vlc_cond_destroy( char * psz_file, int i_line,
+ vlc_cond_t *p_condvar )
{
#if defined( PTH_INIT_IN_PTH_H )
return 0;
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
- return pthread_cond_destroy( p_condvar );
+ int i_result = pthread_cond_destroy( p_condvar );
+ if( i_result )
+ {
+ intf_ErrMsg( "thread %d error: cond_destroy failed at %s:%d (%s)",
+ pthread_self(), psz_file, i_line, strerror(i_result) );
+ }
+ return i_result;
+
+#elif defined( HAVE_CTHREADS_H )
+ return 0;
#elif defined( HAVE_KERNEL_SCHEDULER_H )
p_condvar->init = 0;
/*****************************************************************************
* vlc_thread_create: create a thread
*****************************************************************************/
-static __inline__ int vlc_thread_create( vlc_thread_t *p_thread,
- char *psz_name,
- vlc_thread_func_t func,
- void *p_data )
+#ifdef DEBUG
+# define vlc_thread_create( P_THREAD, PSZ_NAME, FUNC, P_DATA ) \
+ _vlc_thread_create( __FILE__, __LINE__, P_THREAD, PSZ_NAME, FUNC, P_DATA )
+#else
+# define vlc_thread_create( P_THREAD, PSZ_NAME, FUNC, P_DATA ) \
+ _vlc_thread_create( NULL, 0, P_THREAD, PSZ_NAME, FUNC, P_DATA )
+#endif
+
+static __inline__ int _vlc_thread_create( char * psz_file, int i_line,
+ vlc_thread_t *p_thread,
+ char *psz_name,
+ vlc_thread_func_t func,
+ void *p_data )
{
int i_ret;
-#ifdef PROFILING
+#ifdef GPROF
wrapper_t wrapper;
/* Initialize the wrapper structure */
#endif
-#ifdef PROFILING
+#ifdef GPROF
if( i_ret == 0 )
{
vlc_cond_wait( &wrapper.wait, &wrapper.lock );
vlc_cond_destroy( &wrapper.wait );
#endif
+ if( i_ret == 0 )
+ {
+ intf_WarnMsg( 2, "thread info: %d (%s) has been created (%s:%d)",
+ *p_thread, psz_name, psz_file, i_line );
+ }
+ else
+ {
+ intf_ErrMsg( "thread error: %s couldn't be created at %s:%d (%s)",
+ psz_name, psz_file, i_line, strerror(i_ret) );
+ }
+
return i_ret;
}
/*****************************************************************************
* vlc_thread_join: wait until a thread exits
*****************************************************************************/
-static __inline__ void vlc_thread_join( vlc_thread_t thread )
+#ifdef DEBUG
+# define vlc_thread_join( THREAD ) \
+ _vlc_thread_join( __FILE__, __LINE__, THREAD )
+#else
+# define vlc_thread_join( THREAD ) \
+ _vlc_thread_join( NULL, 0, THREAD )
+#endif
+
+static __inline__ void _vlc_thread_join( char * psz_file, int i_line,
+ vlc_thread_t thread )
{
+ int i_ret = 0;
+
#if defined( PTH_INIT_IN_PTH_H )
- pth_join( thread, NULL );
+ i_ret = pth_join( thread, NULL );
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
- pthread_join( thread, NULL );
+ i_ret = pthread_join( thread, NULL );
#elif defined( HAVE_CTHREADS_H )
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);
+ WaitForSingleObject( thread, INFINITE );
#endif
+
+ if( i_ret )
+ {
+ intf_ErrMsg( "thread error: thread_join(%d) failed at %s:%d (%s)",
+ thread, psz_file, i_line, strerror(i_ret) );
+ }
+ else
+ {
+ intf_WarnMsg( 2, "thread info: %d has been joined (%s:%d)",
+ thread, psz_file, i_line );
+ }
}
-#ifdef PROFILING
+#ifdef GPROF
static void *vlc_thread_wrapper( void *p_wrapper )
{
/* Put user data in thread-local variables */
return func( p_data );
}
#endif
+