* This header provides a portable threads implementation.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: threads.h,v 1.28 2001/11/28 15:08:04 massiot Exp $
+ * $Id: threads.h,v 1.40 2002/04/05 03:27:27 sam Exp $
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr>
#if defined( PTH_INIT_IN_PTH_H ) /* GNU Pth */
# include <pth.h>
+#elif defined( ST_INIT_IN_ST_H ) /* State threads */
+# include <st.h>
+
+#elif defined( WIN32 )
+# include <process.h>
+
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) /* pthreads (like Linux & BSD) */
# include <pthread.h>
+# ifdef DEBUG
+/* Needed for pthread_cond_timedwait */
+# include <errno.h>
+# endif
/* This is not prototyped under Linux, though it exists. */
int pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind );
# include <cthreads.h>
#elif defined( HAVE_KERNEL_SCHEDULER_H ) /* BeOS */
-# undef MAX
-# undef MIN
# include <kernel/OS.h>
# include <kernel/scheduler.h>
# include <byteorder.h>
-#elif defined( WIN32 )
-#define WIN32_LEAN_AND_MEAN
-# include <windows.h>
-# include <process.h>
-
#else
# error no threads available on your system !
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;
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);
* 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 */
} 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 */
/*****************************************************************************
#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;
#elif defined( HAVE_KERNEL_SCHEDULER_H )
return 0;
-#elif defined( WIN32 )
- return 0;
-
#endif
}
#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;
#elif defined( HAVE_KERNEL_SCHEDULER_H )
return 0;
-#elif defined( WIN32 )
- return 0;
-
#endif
}
#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. */
p_mutex->init = 9999;
return B_OK;
-#elif defined( WIN32 )
- InitializeCriticalSection( p_mutex );
- return 0;
-
#endif
}
#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 )
err = acquire_sem( p_mutex->lock );
return err;
-#elif defined( WIN32 )
- EnterCriticalSection( p_mutex );
- return 0;
-
#endif
}
#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 )
release_sem( p_mutex->lock );
return B_OK;
-#elif defined( WIN32 )
- LeaveCriticalSection( p_mutex );
- return 0;
-
#endif
}
#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 )
p_mutex->init = 0;
return B_OK;
-#elif defined( WIN32 )
- DeleteCriticalSection( p_mutex );
- return 0;
-
#endif
}
#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 );
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
}
#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 );
}
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
}
#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 );
}
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
}
#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
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
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
}
#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 )
p_condvar->init = 0;
return 0;
-#elif defined( WIN32 )
- return( !CloseHandle( p_condvar->signal ) );
-
#endif
}
*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 );
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
#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 );
#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
}
#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 )
return func( p_data );
}
#endif
-
-#ifdef PLUGIN
-# undef intf_WarnMsg
-# undef intf_ErrMsg
-#endif