X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=include%2Fthreads.h;h=bf67af4f193989cc2d9c1850bbb7db7ed7e30296;hb=8dee1230d87abff97f5f0682d7ac7fedfd194776;hp=56c5e7d5e72d7e7f04c5cc4cec3e77c41de0705c;hpb=ac08ae30411f18fccf735b337927ee7abd04a009;p=vlc diff --git a/include/threads.h b/include/threads.h index 56c5e7d5e7..bf67af4f19 100644 --- a/include/threads.h +++ b/include/threads.h @@ -1,41 +1,49 @@ /***************************************************************************** - * threads.h : thread implementation for VideoLAN client - * This header is supposed to provide a portable threads implementation. - * Currently, it is a wrapper to either the POSIX pthreads library, or - * the Mach cthreads (for the GNU/Hurd). + * threads.h : threads implementation for the VideoLAN client + * This header provides a portable threads implementation. ***************************************************************************** * Copyright (C) 1999, 2000 VideoLAN + * $Id: threads.h,v 1.17 2001/04/28 03:36:25 sam Exp $ * - * Authors: + * Authors: Jean-Marc Dressler + * Samuel Hocevar * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * 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-1307, USA. + * 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. *****************************************************************************/ +#include + +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) /* pthreads (like Linux & BSD) */ +#include -#ifdef SYS_GNU +#elif defined(HAVE_CTHREADS_H) /* GNUMach */ #include -#endif -#ifdef SYS_BEOS +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_H) /* BeOS */ +#undef MAX +#undef MIN #include #include -#endif +#include -#if defined(SYS_LINUX) || defined(SYS_BSD) -#include +#elif defined(WIN32) /* Win32 with MinGW32 compiler */ +#include +#include + +#else +#error no threads available on your system ! #endif /***************************************************************************** @@ -46,8 +54,8 @@ * value is used as a shared flag to represent the status of the thread. *****************************************************************************/ -/* Void status - this value can be used to be sure, in an array of recorded - * threads, that no operation is currently in progress on the concerned thread */ +/* Void status - this value can be used to make sure no operation is currently + * in progress on the concerned thread in an array of recorded threads */ #define THREAD_NOP 0 /* nothing happened */ /* Creation status */ @@ -68,12 +76,17 @@ * Types definition *****************************************************************************/ -#ifdef SYS_GNU +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) +typedef pthread_t vlc_thread_t; +typedef pthread_mutex_t vlc_mutex_t; +typedef pthread_cond_t vlc_cond_t; +#elif defined(HAVE_CTHREADS_H) typedef cthread_t vlc_thread_t; -/* those structs are the ones defined in /include/cthreads.h but we need - * * to handle *foo where foo is a mutex_t */ +/* Those structs are the ones defined in /include/cthreads.h but we need + * to handle (*foo) where foo is a (mutex_t) while they handle (foo) where + * foo is a (mutex_t*) */ typedef struct s_mutex { spin_lock_t held; spin_lock_t lock; @@ -88,9 +101,10 @@ typedef struct s_condition { struct cond_imp *implications; } vlc_cond_t; -#endif /* SYS_GNU */ - -#ifdef SYS_BEOS +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_H) +/* This is the BeOS implementation of the vlc threads, note that the mutex is + * not a real mutex and the cond_var is not like a pthread cond_var but it is + * enough for what wee need */ typedef thread_id vlc_thread_t; @@ -98,28 +112,21 @@ typedef struct { int32 init; sem_id lock; - thread_id owner; } vlc_mutex_t; typedef struct { int32 init; - sem_id sem; - sem_id handshakeSem; - sem_id signalSem; - volatile int32 nw; - volatile int32 ns; + thread_id thread; } vlc_cond_t; -#endif /* SYS_BEOS */ - -#if defined(SYS_LINUX) || defined(SYS_BSD) +#elif defined(WIN32) +typedef HANDLE vlc_thread_t; +typedef HANDLE vlc_mutex_t; +typedef HANDLE vlc_cond_t; +typedef unsigned (__stdcall *PTHREAD_START) (void *); -typedef pthread_t vlc_thread_t; -typedef pthread_mutex_t vlc_mutex_t; -typedef pthread_cond_t vlc_cond_t; - -#endif /* SYS_LINUX || SYS_BSD */ +#endif typedef void *(*vlc_thread_func_t)(void *p_data); @@ -127,22 +134,24 @@ typedef void *(*vlc_thread_func_t)(void *p_data); * Prototypes *****************************************************************************/ -static __inline__ int vlc_thread_create( vlc_thread_t *p_thread, char *psz_name, - vlc_thread_func_t func, void *p_data ); -static __inline__ void vlc_thread_exit ( void ); -static __inline__ void vlc_thread_join ( vlc_thread_t thread ); +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 ); -static __inline__ int vlc_mutex_init ( vlc_mutex_t *p_mutex ); -static __inline__ int vlc_mutex_lock ( vlc_mutex_t *p_mutex ); -static __inline__ int vlc_mutex_unlock ( vlc_mutex_t *p_mutex ); +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 * ); -static __inline__ int vlc_cond_init ( vlc_cond_t *p_condvar ); -static __inline__ int vlc_cond_signal ( vlc_cond_t *p_condvar ); -static __inline__ int vlc_cond_wait ( vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex ); +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 * ); #if 0 -static _inline__ int vlc_cond_timedwait ( vlc_cond_t * condvar, vlc_mutex_t * mutex, - mtime_t absoute_timeout_time ); +static __inline__ int vlc_cond_timedwait( vlc_cond_t *, vlc_mutex_t *, + mtime_t ); #endif /***************************************************************************** @@ -152,18 +161,35 @@ static __inline__ int vlc_thread_create( vlc_thread_t *p_thread, char *psz_name, vlc_thread_func_t func, void *p_data) { -#ifdef SYS_GNU +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) + return pthread_create( p_thread, NULL, func, p_data ); + +#elif defined(HAVE_CTHREADS_H) *p_thread = cthread_fork( (cthread_fn_t)func, (any_t)p_data ); - return( 0 ); -#endif + return 0; -#ifdef SYS_BEOS - *p_thread = spawn_thread( (thread_func)func, psz_name, B_NORMAL_PRIORITY, p_data ); +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_H) + *p_thread = spawn_thread( (thread_func)func, psz_name, + B_NORMAL_PRIORITY, p_data ); return resume_thread( *p_thread ); -#endif -#if defined(SYS_LINUX) || defined(SYS_BSD) - return pthread_create( p_thread, NULL, func, p_data ); +#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); + + return( *p_thread ? 0 : 1 ); + #endif } @@ -172,17 +198,24 @@ static __inline__ int vlc_thread_create( vlc_thread_t *p_thread, *****************************************************************************/ static __inline__ void vlc_thread_exit( void ) { -#ifdef SYS_GNU +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) + pthread_exit( 0 ); + +#elif defined(HAVE_CTHREADS_H) int result; cthread_exit( &result ); -#endif -#ifdef SYS_BEOS +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_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); -#if defined(SYS_LINUX) || defined(SYS_BSD) - pthread_exit( 0 ); #endif } @@ -191,59 +224,60 @@ static __inline__ void vlc_thread_exit( void ) *****************************************************************************/ static __inline__ void vlc_thread_join( vlc_thread_t thread ) { -#ifdef SYS_GNU +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) + pthread_join( thread, NULL ); + +#elif defined(HAVE_CTHREADS_H) cthread_join( thread ); -#endif -#ifdef SYS_BEOS - int32 exit_value; +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_H) + int32 exit_value; wait_for_thread( thread, &exit_value ); -#endif -#if defined(SYS_LINUX) || defined(SYS_BSD) - pthread_join( thread, NULL ); -#endif -} +#elif defined(WIN32) + WaitForSingleObject( thread, INFINITE); -#ifdef SYS_BEOS -/* lazy_init_mutex */ -static __inline__ void lazy_init_mutex(vlc_mutex_t* p_mutex) -{ - int32 v = atomic_or( &p_mutex->init, 1 ); - if( 2000 == v ) // we're the first, so do the init - { - vlc_mutex_init( p_mutex ); - } - else // we're not the first, so wait until the init is finished - { - while( p_mutex->init != 9999 ) snooze( 10000 ); - } -} #endif +} /***************************************************************************** * vlc_mutex_init: initialize a mutex *****************************************************************************/ static __inline__ int vlc_mutex_init( vlc_mutex_t *p_mutex ) { -#ifdef SYS_GNU +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) + return pthread_mutex_init( p_mutex, NULL ); + +#elif defined(HAVE_CTHREADS_H) mutex_init( p_mutex ); - return( 0 ); -#endif + return 0; + +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_H) -#ifdef SYS_BEOS - // check the arguments and whether it's already been initialized - if( !p_mutex ) return B_BAD_VALUE; - if( p_mutex->init == 9999 ) return EALREADY; + /* 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" ); - p_mutex->owner = -1; + if( p_mutex->lock < B_NO_ERROR ) + { + return( -1 ); + } + p_mutex->init = 9999; return B_OK; -#endif -#if defined(SYS_LINUX) || defined(SYS_BSD) - return pthread_mutex_init( p_mutex, NULL ); +#elif defined(WIN32) + *p_mutex = CreateMutex(0,FALSE,0); + return (*p_mutex?0:1); + #endif } @@ -252,25 +286,33 @@ static __inline__ int vlc_mutex_init( vlc_mutex_t *p_mutex ) *****************************************************************************/ static __inline__ int vlc_mutex_lock( vlc_mutex_t *p_mutex ) { -#ifdef SYS_GNU +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) + return pthread_mutex_lock( p_mutex ); + +#elif defined(HAVE_CTHREADS_H) mutex_lock( p_mutex ); - return( 0 ); -#endif + return 0; -#ifdef SYS_BEOS +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_H) status_t err; - if( !p_mutex ) return B_BAD_VALUE; - if( p_mutex->init < 2000 ) return B_NO_INIT; - lazy_init_mutex( p_mutex ); + if( !p_mutex ) + { + return B_BAD_VALUE; + } + + if( p_mutex->init < 2000 ) + { + return B_NO_INIT; + } err = acquire_sem( p_mutex->lock ); - if( !err ) p_mutex->owner = find_thread( NULL ); return err; -#endif -#if defined(SYS_LINUX) || defined(SYS_BSD) - return pthread_mutex_lock( p_mutex ); +#elif defined(WIN32) + WaitForSingleObject( *p_mutex, INFINITE ); + return 0; + #endif } @@ -279,72 +321,99 @@ static __inline__ int vlc_mutex_lock( vlc_mutex_t *p_mutex ) *****************************************************************************/ static __inline__ int vlc_mutex_unlock( vlc_mutex_t *p_mutex ) { -#ifdef SYS_GNU +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) + return pthread_mutex_unlock( p_mutex ); + +#elif defined(HAVE_CTHREADS_H) mutex_unlock( p_mutex ); - return( 0 ); -#endif + return 0; -#ifdef SYS_BEOS - if(! p_mutex) return B_BAD_VALUE; - if( p_mutex->init < 2000 ) return B_NO_INIT; - lazy_init_mutex( p_mutex ); +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_H) + if( !p_mutex) + { + return B_BAD_VALUE; + } + + if( p_mutex->init < 2000 ) + { + return B_NO_INIT; + } - if( p_mutex->owner != find_thread(NULL) ) return ENOLCK; - p_mutex->owner = -1; release_sem( p_mutex->lock ); return B_OK; -#endif -#if defined(SYS_LINUX) || defined(SYS_BSD) - return pthread_mutex_unlock( p_mutex ); +#elif defined(WIN32) + ReleaseMutex( *p_mutex ); + return 0; + #endif } -#ifdef SYS_BEOS -/* lazy_init_cond */ -static __inline__ void lazy_init_cond( vlc_cond_t* p_condvar ) +/***************************************************************************** + * vlc_mutex_destroy: destroy a mutex + *****************************************************************************/ +static __inline__ int vlc_mutex_destroy( vlc_mutex_t *p_mutex ) { - int32 v = atomic_or( &p_condvar->init, 1 ); - if( 2000 == v ) // we're the first, so do the init - { - vlc_cond_init( p_condvar ); - } - else // we're not the first, so wait until the init is finished +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) + return pthread_mutex_destroy( p_mutex ); + +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_H) + if( p_mutex->init == 9999 ) { - while( p_condvar->init != 9999 ) snooze( 10000 ); + delete_sem( p_mutex->lock ); } + + p_mutex->init = 0; + return B_OK; + +#elif defined(WIN32) + CloseHandle(*p_mutex); + return 0; + +#endif } -#endif /***************************************************************************** * vlc_cond_init: initialize a condition *****************************************************************************/ static __inline__ int vlc_cond_init( vlc_cond_t *p_condvar ) { -#ifdef SYS_GNU +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) + return pthread_cond_init( p_condvar, NULL ); + +#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; - return( 0 ); -#endif + return 0; -#ifdef SYS_BEOS - if( !p_condvar ) return B_BAD_VALUE; - if( p_condvar->init == 9999 ) return EALREADY; +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_H) + if( !p_condvar ) + { + return B_BAD_VALUE; + } + + if( p_condvar->init == 9999 ) + { + return EALREADY; + } - p_condvar->sem = create_sem( 0, "CVSem" ); - p_condvar->handshakeSem = create_sem( 0, "CVHandshake" ); - p_condvar->signalSem = create_sem( 1, "CVSignal" ); - p_condvar->ns = p_condvar->nw = 0; + p_condvar->thread = -1; p_condvar->init = 9999; - return B_OK; -#endif + return 0; -#if defined(SYS_LINUX) || defined(SYS_BSD) - return pthread_cond_init( p_condvar, NULL ); +#elif defined(WIN32) + /* Create an auto-reset event. */ + *p_condvar = CreateEvent( NULL, /* no security */ + FALSE, /* auto-reset event */ + FALSE, /* non-signaled initially */ + NULL ); /* unnamed */ + + return( *p_condvar ? 0 : 1 ); + #endif } @@ -353,41 +422,58 @@ static __inline__ int vlc_cond_init( vlc_cond_t *p_condvar ) *****************************************************************************/ static __inline__ int vlc_cond_signal( vlc_cond_t *p_condvar ) { -#ifdef SYS_GNU +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) + return pthread_cond_signal( p_condvar ); + +#elif defined(HAVE_CTHREADS_H) /* condition_signal() */ if ( p_condvar->queue.head || p_condvar->implications ) { cond_signal( (condition_t)p_condvar ); } - return( 0 ); -#endif - -#ifdef SYS_BEOS - status_t err = B_OK; + return 0; - if( !p_condvar ) return B_BAD_VALUE; - if( p_condvar->init < 2000 ) return B_NO_INIT; - lazy_init_cond( p_condvar ); - - if( acquire_sem(p_condvar->signalSem) == B_INTERRUPTED) return B_INTERRUPTED; +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_H) + if( !p_condvar ) + { + return B_BAD_VALUE; + } - if( p_condvar->nw > p_condvar->ns ) + if( p_condvar->init < 2000 ) { - p_condvar->ns += 1; - release_sem( p_condvar->sem ); - release_sem( p_condvar->signalSem ); - while( acquire_sem(p_condvar->handshakeSem) == B_INTERRUPTED ) - { err = B_INTERRUPTED; } + return B_NO_INIT; } - else + + while( p_condvar->thread != -1 ) { - release_sem( p_condvar->signalSem ); + thread_info info; + if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE ) + { + return 0; + } + + if( info.state != B_THREAD_SUSPENDED ) + { + /* The waiting thread is not suspended so it could + * have been interrupted beetwen the unlock and the + * suspend_thread line. That is why we sleep a little + * before retesting p_condver->thread. */ + snooze( 10000 ); + } + else + { + /* Ok, we have to wake up that thread */ + resume_thread( p_condvar->thread ); + return 0; + } } - return err; -#endif + return 0; + +#elif defined(WIN32) + /* Try to release one waiting thread. */ + PulseEvent ( *p_condvar ); + return 0; -#if defined(SYS_LINUX) || defined(SYS_BSD) - return pthread_cond_signal( p_condvar ); #endif } @@ -396,42 +482,71 @@ static __inline__ int vlc_cond_signal( vlc_cond_t *p_condvar ) *****************************************************************************/ static __inline__ int vlc_cond_wait( vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex ) { -#ifdef SYS_GNU +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) + return pthread_cond_wait( p_condvar, p_mutex ); + +#elif defined(HAVE_CTHREADS_H) condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex ); - return( 0 ); -#endif + return 0; -#ifdef SYS_BEOS - status_t err; +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_H) + if( !p_condvar ) + { + return B_BAD_VALUE; + } - if( !p_condvar ) return B_BAD_VALUE; - if( !p_mutex ) return B_BAD_VALUE; - if( p_condvar->init < 2000 ) return B_NO_INIT; - lazy_init_cond( p_condvar ); + if( !p_mutex ) + { + return B_BAD_VALUE; + } - if( acquire_sem(p_condvar->signalSem) == B_INTERRUPTED ) return B_INTERRUPTED; - p_condvar->nw += 1; - release_sem( p_condvar->signalSem ); + if( p_condvar->init < 2000 ) + { + return B_NO_INIT; + } + /* The p_condvar->thread var is initialized before the unlock because + * it enables to identify when the thread is interrupted beetwen the + * unlock line and the suspend_thread line */ + p_condvar->thread = find_thread( NULL ); vlc_mutex_unlock( p_mutex ); - err = acquire_sem( p_condvar->sem ); + suspend_thread( p_condvar->thread ); + p_condvar->thread = -1; - while( acquire_sem(p_condvar->signalSem) == B_INTERRUPTED) - { err = B_INTERRUPTED; } - if( p_condvar->ns > 0 ) - { - release_sem( p_condvar->handshakeSem ); - p_condvar->ns -= 1; - } - p_condvar->nw -= 1; - release_sem( p_condvar->signalSem ); + vlc_mutex_lock( p_mutex ); + return 0; - while( vlc_mutex_lock(p_mutex) == B_INTERRUPTED) - { err = B_INTERRUPTED; } - return err; -#endif +#elif defined(WIN32) + /* Release the here and wait for the event + * to become signaled, due to being + * called. */ + vlc_mutex_unlock( p_mutex ); + + WaitForSingleObject( *p_condvar, INFINITE ); + + /* Reacquire the mutex before returning. */ + vlc_mutex_lock( p_mutex ); + return 0; -#if defined(SYS_LINUX) || defined(SYS_BSD) - return pthread_cond_wait( p_condvar, p_mutex ); #endif } + +/***************************************************************************** + * vlc_cond_destroy: destroy a condition + *****************************************************************************/ +static __inline__ int vlc_cond_destroy( vlc_cond_t *p_condvar ) +{ +#if defined(PTHREAD_COND_T_IN_PTHREAD_H) + return pthread_cond_destroy( p_condvar ); + +#elif defined(HAVE_KERNEL_SCHEDULER_H) && defined(HAVE_KERNEL_OS_H) + p_condvar->init = 0; + return 0; + +#elif defined(WIN32) + CloseHandle( *p_condvar ); + return 0; + +#endif +} +