1 /*****************************************************************************
2 * vlc_threads_funcs.h : threads implementation for the VideoLAN client
3 * This header provides a portable threads implementation.
4 *****************************************************************************
5 * Copyright (C) 1999, 2002 the VideoLAN team
8 * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
9 * Samuel Hocevar <sam@via.ecp.fr>
10 * Gildas Bazin <gbazin@netcourrier.com>
11 * Christophe Massiot <massiot@via.ecp.fr>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 #if !defined( __LIBVLC__ )
29 #error You are not libvlc or one of its plugins. You cannot include this file
32 /*****************************************************************************
33 * Function definitions
34 *****************************************************************************/
35 VLC_EXPORT( int, __vlc_threads_init, ( vlc_object_t * ) );
36 VLC_EXPORT( int, __vlc_threads_end, ( vlc_object_t * ) );
37 VLC_EXPORT( int, __vlc_mutex_init, ( vlc_object_t *, vlc_mutex_t * ) );
38 VLC_EXPORT( int, __vlc_mutex_destroy, ( const char *, int, vlc_mutex_t * ) );
39 VLC_EXPORT( int, __vlc_cond_init, ( vlc_object_t *, vlc_cond_t * ) );
40 VLC_EXPORT( int, __vlc_cond_destroy, ( const char *, int, vlc_cond_t * ) );
41 VLC_EXPORT( int, __vlc_thread_create, ( vlc_object_t *, const char *, int, const char *, void * ( * ) ( void * ), int, vlc_bool_t ) );
42 VLC_EXPORT( int, __vlc_thread_set_priority, ( vlc_object_t *, const char *, int, int ) );
43 VLC_EXPORT( void, __vlc_thread_ready, ( vlc_object_t * ) );
44 VLC_EXPORT( void, __vlc_thread_join, ( vlc_object_t *, const char *, int ) );
47 /*****************************************************************************
48 * vlc_threads_init: initialize threads system
49 *****************************************************************************/
50 #define vlc_threads_init( P_THIS ) \
51 __vlc_threads_init( VLC_OBJECT(P_THIS) )
53 /*****************************************************************************
54 * vlc_threads_end: deinitialize threads system
55 *****************************************************************************/
56 #define vlc_threads_end( P_THIS ) \
57 __vlc_threads_end( VLC_OBJECT(P_THIS) )
59 /*****************************************************************************
60 * vlc_mutex_init: initialize a mutex
61 *****************************************************************************/
62 #define vlc_mutex_init( P_THIS, P_MUTEX ) \
63 __vlc_mutex_init( VLC_OBJECT(P_THIS), P_MUTEX )
65 /*****************************************************************************
66 * vlc_mutex_lock: lock a mutex
67 *****************************************************************************/
68 #define vlc_mutex_lock( P_MUTEX ) \
69 __vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
72 # define CAST_PTHREAD_TO_INT(t) (unsigned long int)(uintptr_t)(void *)t
74 # define CAST_PTHREAD_TO_INT(t) (unsigned long int)t
77 static inline int __vlc_mutex_lock( const char * psz_file, int i_line,
78 vlc_mutex_t * p_mutex )
81 /* In case of error : */
82 unsigned long int i_thread = 0;
83 const char * psz_error = "";
85 #if defined( PTH_INIT_IN_PTH_H )
86 i_result = ( pth_mutex_acquire( &p_mutex->mutex, FALSE, NULL ) == FALSE );
88 #elif defined( ST_INIT_IN_ST_H )
89 i_result = st_mutex_lock( p_mutex->mutex );
91 #elif defined( UNDER_CE )
92 EnterCriticalSection( &p_mutex->csection );
95 #elif defined( WIN32 )
98 WaitForSingleObject( p_mutex->mutex, INFINITE );
102 EnterCriticalSection( &p_mutex->csection );
106 #elif defined( HAVE_KERNEL_SCHEDULER_H )
107 if( p_mutex == NULL )
109 i_result = B_BAD_VALUE;
111 else if( p_mutex->init < 2000 )
113 i_result = B_NO_INIT;
117 i_result = acquire_sem( p_mutex->lock );
120 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
121 i_result = pthread_mutex_lock( &p_mutex->mutex );
124 i_thread = CAST_PTHREAD_TO_INT(pthread_self());
125 psz_error = strerror(i_result);
128 #elif defined( HAVE_CTHREADS_H )
129 mutex_lock( p_mutex->mutex );
136 msg_Err( p_mutex->p_this,
137 "thread %li: mutex_lock failed at %s:%d (%d:%s)",
138 i_thread, psz_file, i_line, i_result, psz_error );
143 /*****************************************************************************
144 * vlc_mutex_unlock: unlock a mutex
145 *****************************************************************************/
146 #define vlc_mutex_unlock( P_MUTEX ) \
147 __vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
149 static inline int __vlc_mutex_unlock( const char * psz_file, int i_line,
150 vlc_mutex_t *p_mutex )
153 /* In case of error : */
154 unsigned long int i_thread = 0;
155 const char * psz_error = "";
157 #if defined( PTH_INIT_IN_PTH_H )
158 i_result = ( pth_mutex_release( &p_mutex->mutex ) == FALSE );
160 #elif defined( ST_INIT_IN_ST_H )
161 i_result = st_mutex_unlock( p_mutex->mutex );
163 #elif defined( UNDER_CE )
164 LeaveCriticalSection( &p_mutex->csection );
167 #elif defined( WIN32 )
170 ReleaseMutex( p_mutex->mutex );
174 LeaveCriticalSection( &p_mutex->csection );
178 #elif defined( HAVE_KERNEL_SCHEDULER_H )
179 if( p_mutex == NULL )
181 i_result = B_BAD_VALUE;
183 else if( p_mutex->init < 2000 )
185 i_result = B_NO_INIT;
189 release_sem( p_mutex->lock );
193 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
194 i_result = pthread_mutex_unlock( &p_mutex->mutex );
197 i_thread = CAST_PTHREAD_TO_INT(pthread_self());
198 psz_error = strerror(i_result);
201 #elif defined( HAVE_CTHREADS_H )
202 mutex_unlock( p_mutex );
209 msg_Err( p_mutex->p_this,
210 "thread %li: mutex_unlock failed at %s:%d (%d:%s)",
211 i_thread, psz_file, i_line, i_result, psz_error );
217 /*****************************************************************************
218 * vlc_mutex_destroy: destroy a mutex
219 *****************************************************************************/
220 #define vlc_mutex_destroy( P_MUTEX ) \
221 __vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
223 /*****************************************************************************
224 * vlc_cond_init: initialize a condition
225 *****************************************************************************/
226 #define vlc_cond_init( P_THIS, P_COND ) \
227 __vlc_cond_init( VLC_OBJECT(P_THIS), P_COND )
229 /*****************************************************************************
230 * vlc_cond_signal: start a thread on condition completion
231 *****************************************************************************/
232 #define vlc_cond_signal( P_COND ) \
233 __vlc_cond_signal( __FILE__, __LINE__, P_COND )
235 static inline int __vlc_cond_signal( const char * psz_file, int i_line,
236 vlc_cond_t *p_condvar )
239 /* In case of error : */
240 unsigned long int i_thread = 0;
241 const char * psz_error = "";
243 #if defined( PTH_INIT_IN_PTH_H )
244 i_result = ( pth_cond_notify( &p_condvar->cond, FALSE ) == FALSE );
246 #elif defined( ST_INIT_IN_ST_H )
247 i_result = st_cond_signal( p_condvar->cond );
249 #elif defined( UNDER_CE )
250 PulseEvent( p_condvar->event );
253 #elif defined( WIN32 )
254 /* Release one waiting thread if one is available. */
255 /* For this trick to work properly, the vlc_cond_signal must be surrounded
256 * by a mutex. This will prevent another thread from stealing the signal */
257 if( !p_condvar->semaphore )
259 PulseEvent( p_condvar->event );
261 else if( p_condvar->i_win9x_cv == 1 )
263 /* Wait for the gate to be open */
264 WaitForSingleObject( p_condvar->event, INFINITE );
266 if( p_condvar->i_waiting_threads )
268 /* Using a semaphore exposes us to a race condition. It is
269 * possible for another thread to start waiting on the semaphore
270 * just after we signaled it and thus steal the signal.
271 * We have to prevent new threads from entering the cond_wait(). */
272 ResetEvent( p_condvar->event );
274 /* A semaphore is used here because Win9x doesn't have
275 * SignalObjectAndWait() and thus a race condition exists
276 * during the time we release the mutex and the time we start
277 * waiting on the event (more precisely, the signal can sometimes
278 * be missed by the waiting thread if we use PulseEvent()). */
279 ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
284 if( p_condvar->i_waiting_threads )
286 ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
288 /* Wait for the last thread to be awakened */
289 WaitForSingleObject( p_condvar->event, INFINITE );
294 #elif defined( HAVE_KERNEL_SCHEDULER_H )
295 if( p_condvar == NULL )
297 i_result = B_BAD_VALUE;
299 else if( p_condvar->init < 2000 )
301 i_result = B_NO_INIT;
305 while( p_condvar->thread != -1 )
308 if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
313 if( info.state != B_THREAD_SUSPENDED )
315 /* The waiting thread is not suspended so it could
316 * have been interrupted beetwen the unlock and the
317 * suspend_thread line. That is why we sleep a little
318 * before retesting p_condver->thread. */
323 /* Ok, we have to wake up that thread */
324 resume_thread( p_condvar->thread );
331 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
332 i_result = pthread_cond_signal( &p_condvar->cond );
335 i_thread = CAST_PTHREAD_TO_INT(pthread_self());
336 psz_error = strerror(i_result);
339 #elif defined( HAVE_CTHREADS_H )
340 /* condition_signal() */
341 if ( p_condvar->queue.head || p_condvar->implications )
343 cond_signal( (condition_t)p_condvar );
351 msg_Err( p_condvar->p_this,
352 "thread %li: cond_signal failed at %s:%d (%d:%s)",
353 i_thread, psz_file, i_line, i_result, psz_error );
359 /*****************************************************************************
360 * vlc_cond_wait: wait until condition completion
361 *****************************************************************************/
362 #define vlc_cond_wait( P_COND, P_MUTEX ) \
363 __vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX )
365 static inline int __vlc_cond_wait( const char * psz_file, int i_line,
366 vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex )
369 /* In case of error : */
370 unsigned long int i_thread = 0;
371 const char * psz_error = "";
373 #if defined( PTH_INIT_IN_PTH_H )
374 i_result = ( pth_cond_await( &p_condvar->cond, &p_mutex->mutex, NULL )
377 #elif defined( ST_INIT_IN_ST_H )
378 st_mutex_unlock( p_mutex->mutex );
379 i_result = st_cond_wait( p_condvar->cond );
380 st_mutex_lock( p_mutex->mutex );
382 #elif defined( UNDER_CE )
383 p_condvar->i_waiting_threads++;
384 LeaveCriticalSection( &p_mutex->csection );
385 WaitForSingleObject( p_condvar->event, INFINITE );
386 p_condvar->i_waiting_threads--;
388 /* Reacquire the mutex before returning. */
389 vlc_mutex_lock( p_mutex );
393 #elif defined( WIN32 )
394 if( !p_condvar->semaphore )
396 /* Increase our wait count */
397 p_condvar->i_waiting_threads++;
401 /* It is only possible to atomically release the mutex and
402 * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
403 * SignalObjectAndWait(). */
404 p_condvar->SignalObjectAndWait( p_mutex->mutex,
410 LeaveCriticalSection( &p_mutex->csection );
411 WaitForSingleObject( p_condvar->event, INFINITE );
414 p_condvar->i_waiting_threads--;
416 else if( p_condvar->i_win9x_cv == 1 )
418 int i_waiting_threads;
420 /* Wait for the gate to be open */
421 WaitForSingleObject( p_condvar->event, INFINITE );
423 /* Increase our wait count */
424 p_condvar->i_waiting_threads++;
426 LeaveCriticalSection( &p_mutex->csection );
427 WaitForSingleObject( p_condvar->semaphore, INFINITE );
429 /* Decrement and test must be atomic */
430 EnterCriticalSection( &p_condvar->csection );
432 /* Decrease our wait count */
433 i_waiting_threads = --p_condvar->i_waiting_threads;
435 LeaveCriticalSection( &p_condvar->csection );
437 /* Reopen the gate if we were the last waiting thread */
438 if( !i_waiting_threads )
439 SetEvent( p_condvar->event );
443 int i_waiting_threads;
445 /* Increase our wait count */
446 p_condvar->i_waiting_threads++;
448 LeaveCriticalSection( &p_mutex->csection );
449 WaitForSingleObject( p_condvar->semaphore, INFINITE );
451 /* Decrement and test must be atomic */
452 EnterCriticalSection( &p_condvar->csection );
454 /* Decrease our wait count */
455 i_waiting_threads = --p_condvar->i_waiting_threads;
457 LeaveCriticalSection( &p_condvar->csection );
459 /* Signal that the last waiting thread just went through */
460 if( !i_waiting_threads )
461 SetEvent( p_condvar->event );
464 /* Reacquire the mutex before returning. */
465 vlc_mutex_lock( p_mutex );
469 #elif defined( HAVE_KERNEL_SCHEDULER_H )
470 if( p_condvar == NULL )
472 i_result = B_BAD_VALUE;
474 else if( p_mutex == NULL )
476 i_result = B_BAD_VALUE;
478 else if( p_condvar->init < 2000 )
480 i_result = B_NO_INIT;
483 /* The p_condvar->thread var is initialized before the unlock because
484 * it enables to identify when the thread is interrupted beetwen the
485 * unlock line and the suspend_thread line */
486 p_condvar->thread = find_thread( NULL );
487 vlc_mutex_unlock( p_mutex );
488 suspend_thread( p_condvar->thread );
489 p_condvar->thread = -1;
491 vlc_mutex_lock( p_mutex );
494 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
497 /* In debug mode, timeout */
499 struct timespec timeout;
501 gettimeofday( &now, NULL );
502 timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT;
503 timeout.tv_nsec = now.tv_usec * 1000;
505 i_result = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex,
508 if( i_result == ETIMEDOUT )
510 msg_Dbg( p_condvar->p_this,
511 "thread %li: probable condition deadlock "
512 "at %s:%d (%s)", CAST_PTHREAD_TO_INT(pthread_self()),
513 psz_file, i_line, strerror(i_result) );
515 i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
519 i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
524 i_thread = CAST_PTHREAD_TO_INT(pthread_self());
525 psz_error = strerror(i_result);
528 #elif defined( HAVE_CTHREADS_H )
529 condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
536 msg_Err( p_condvar->p_this,
537 "thread %li: cond_wait failed at %s:%d (%d:%s)",
538 i_thread, psz_file, i_line, i_result, psz_error );
544 /*****************************************************************************
545 * vlc_cond_destroy: destroy a condition
546 *****************************************************************************/
547 #define vlc_cond_destroy( P_COND ) \
548 __vlc_cond_destroy( __FILE__, __LINE__, P_COND )
550 /*****************************************************************************
551 * vlc_thread_create: create a thread
552 *****************************************************************************/
553 #define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY, WAIT ) \
554 __vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, (void * ( * ) ( void * ))FUNC, PRIORITY, WAIT )
556 /*****************************************************************************
557 * vlc_thread_set_priority: set the priority of the calling thread
558 *****************************************************************************/
559 #define vlc_thread_set_priority( P_THIS, PRIORITY ) \
560 __vlc_thread_set_priority( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PRIORITY )
562 /*****************************************************************************
563 * vlc_thread_ready: tell the parent thread we were successfully spawned
564 *****************************************************************************/
565 #define vlc_thread_ready( P_THIS ) \
566 __vlc_thread_ready( VLC_OBJECT(P_THIS) )
568 /*****************************************************************************
569 * vlc_thread_join: wait until a thread exits
570 *****************************************************************************/
571 #define vlc_thread_join( P_THIS ) \
572 __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )