* This header provides a portable threads implementation.
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
- * $Id: threads_funcs.h,v 1.4 2002/05/19 23:51:37 massiot Exp $
+ * $Id: threads_funcs.h,v 1.4.2.4 2002/07/30 07:54:05 gbazin Exp $
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr>
* 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->p_sys->b_fast_pthread )
+ if( p_main->p_sys->SignalObjectAndWait && !p_main->p_sys->b_fast_mutex )
{
/* We are running on NT/2K/XP, we can use SignalObjectAndWait */
p_mutex->mutex = CreateMutex( 0, FALSE, 0 );
}
else
{
- InitializeCriticalSection( &p_mutex->csection );
p_mutex->mutex = NULL;
+ InitializeCriticalSection( &p_mutex->csection );
return 0;
}
return ( *p_condvar == NULL ) ? errno : 0;
#elif defined( WIN32 )
- /* initialise counter */
+ /* Initialize 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 */
+ if( p_main->p_sys->i_win9x_cv == 0 )
+ {
+ /* Create an auto-reset event. */
+ p_condvar->event = CreateEvent( NULL, /* no security */
+ FALSE, /* auto-reset event */
+ FALSE, /* start non-signaled */
+ NULL ); /* unnamed */
+
+ p_condvar->semaphore = NULL;
+ return !p_condvar->event;
+ }
+ else
+ {
+ p_condvar->semaphore = CreateSemaphore( NULL, /* no security */
+ 0, /* initial count */
+ 0x7fffffff, /* max count */
+ NULL ); /* unnamed */
+
+ if( p_main->p_sys->i_win9x_cv == 1 )
+ /* Create a manual-reset event initially signaled. */
+ p_condvar->event = CreateEvent( NULL, TRUE, TRUE, NULL );
+ else
+ /* Create a auto-reset event. */
+ p_condvar->event = CreateEvent( NULL, FALSE, FALSE, NULL );
- return( !p_condvar->signal );
+ InitializeCriticalSection( &p_condvar->csection );
+
+ return !p_condvar->semaphore || !p_condvar->event;
+ }
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
return pthread_cond_init( p_condvar, NULL );
/* 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 );
+
+ if( !p_condvar->semaphore )
+ {
+ PulseEvent( p_condvar->event );
+ }
+ else if( p_main->p_sys->i_win9x_cv == 1 )
+ {
+ /* Wait for the gate to be open */
+ WaitForSingleObject( p_condvar->event, INFINITE );
+
+ if( p_condvar->i_waiting_threads )
+ {
+ /* Using a semaphore exposes us to a race condition. It is
+ * possible for another thread to start waiting on the semaphore
+ * just after we signaled it and thus steal the signal.
+ * We have to prevent new threads from entering the cond_wait(). */
+ ResetEvent( p_condvar->event );
+
+ /* A semaphore is used here because Win9x doesn't have
+ * SignalObjectAndWait() and thus a race condition exists
+ * during the time we release the mutex and the time we start
+ * waiting on the event (more precisely, the signal can sometimes
+ * be missed by the waiting thread if we use PulseEvent()). */
+ ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
+ }
+ }
+ else
+ {
+ if( p_condvar->i_waiting_threads )
+ {
+ ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
+
+ /* Wait for the last thread to be awakened */
+ WaitForSingleObject( p_condvar->event, INFINITE );
+ }
+ }
return 0;
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
#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 )
+ int i;
+
+ if( !p_condvar->semaphore )
+ for( i = p_condvar->i_waiting_threads; i > 0; i-- )
+ PulseEvent( p_condvar->event );
+ else if( p_main->p_sys->i_win9x_cv == 1 )
{
- PulseEvent( p_condvar->signal );
- Sleep( 1 ); /* deschedule the current thread */
+ /* Wait for the gate to be open */
+ WaitForSingleObject( p_condvar->event, INFINITE );
+
+ if( p_condvar->i_waiting_threads )
+ {
+ /* close gate */
+ ResetEvent( p_condvar->event );
+
+ ReleaseSemaphore( p_condvar->semaphore,
+ p_condvar->i_waiting_threads, 0 );
+ }
}
+ else
+ {
+ if( p_condvar->i_waiting_threads )
+ {
+ ReleaseSemaphore( p_condvar->semaphore,
+ p_condvar->i_waiting_threads, 0 );
+ /* Wait for the last thread to be awakened */
+ WaitForSingleObject( p_condvar->event, INFINITE );
+ }
+ }
+
return 0;
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
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_condvar->semaphore )
+ {
+ /* Increase our wait count */
+ p_condvar->i_waiting_threads++;
+
+ if( p_main->p_sys->SignalObjectAndWait && p_mutex->mutex )
+ /* It is only possible to atomically release the mutex and initiate the
+ * waiting on WinNT/2K/XP. Win9x doesn't have SignalObjectAndWait(). */
+ p_main->p_sys->SignalObjectAndWait( p_mutex->mutex,
+ p_condvar->event,
+ INFINITE, FALSE );
+ else
+ {
+ LeaveCriticalSection( &p_mutex->csection );
+ WaitForSingleObject( p_condvar->event, INFINITE );
+ }
- if( p_mutex->mutex )
+ p_condvar->i_waiting_threads--;
+ }
+ else if( p_main->p_sys->i_win9x_cv == 1 )
{
- p_main->p_sys->SignalObjectAndWait( p_mutex->mutex, p_condvar->signal,
- INFINITE, FALSE );
+ int i_waiting_threads;
+
+ /* Wait for the gate to be open */
+ WaitForSingleObject( p_condvar->event, INFINITE );
+
+ /* Increase our wait count */
+ p_condvar->i_waiting_threads++;
+
+ LeaveCriticalSection( &p_mutex->csection );
+ WaitForSingleObject( p_condvar->semaphore, INFINITE );
+
+ /* Decrement and test must be atomic */
+ EnterCriticalSection( &p_condvar->csection );
+
+ /* Decrease our wait count */
+ i_waiting_threads = --p_condvar->i_waiting_threads;
+
+ LeaveCriticalSection( &p_condvar->csection );
+
+ /* Reopen the gate if we were the last waiting thread */
+ if( !i_waiting_threads )
+ SetEvent( p_condvar->event );
}
else
{
- /* Release the mutex */
- vlc_mutex_unlock( p_mutex );
- i_result = WaitForSingleObject( p_condvar->signal, INFINITE);
- p_condvar->i_waiting_threads --;
+ int i_waiting_threads;
+
+ /* Increase our wait count */
+ p_condvar->i_waiting_threads++;
+
+ LeaveCriticalSection( &p_mutex->csection );
+ WaitForSingleObject( p_condvar->semaphore, INFINITE );
+
+ /* Decrement and test must be atomic */
+ EnterCriticalSection( &p_condvar->csection );
+
+ /* Decrease our wait count */
+ i_waiting_threads = --p_condvar->i_waiting_threads;
+
+ LeaveCriticalSection( &p_condvar->csection );
+
+ /* Signal that the last waiting thread just went through */
+ if( !i_waiting_threads )
+ SetEvent( p_condvar->event );
}
/* Reacquire the mutex before returning. */
vlc_mutex_lock( p_mutex );
- return( i_result == WAIT_FAILED );
+ return 0;
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
return st_cond_destroy( *p_condvar );
#elif defined( WIN32 )
- return( !CloseHandle( p_condvar->signal ) );
+ if( !p_condvar->semaphore )
+ return !CloseHandle( p_condvar->event );
+ else
+ return !CloseHandle( p_condvar->event )
+ || !CloseHandle( p_condvar->semaphore );
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
int i_result = pthread_cond_destroy( p_condvar );