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-2007 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 #ifndef _VLC_THREADFUNCS_H_
33 #define _VLC_THREADFUNCS_H_
35 /*****************************************************************************
36 * Function definitions
37 *****************************************************************************/
38 VLC_EXPORT( void, vlc_threads_error, ( vlc_object_t *) );
39 VLC_EXPORT( int, __vlc_mutex_init, ( vlc_object_t *, vlc_mutex_t * ) );
40 VLC_EXPORT( int, __vlc_mutex_init_recursive, ( vlc_object_t *, vlc_mutex_t * ) );
41 VLC_EXPORT( int, __vlc_mutex_destroy, ( const char *, int, vlc_mutex_t * ) );
42 VLC_EXPORT( int, __vlc_cond_init, ( vlc_object_t *, vlc_cond_t * ) );
43 VLC_EXPORT( int, __vlc_cond_destroy, ( const char *, int, vlc_cond_t * ) );
44 VLC_EXPORT( int, __vlc_threadvar_create, (vlc_object_t *, vlc_threadvar_t * ) );
45 VLC_EXPORT( int, __vlc_thread_create, ( vlc_object_t *, const char *, int, const char *, void * ( * ) ( void * ), int, vlc_bool_t ) );
46 VLC_EXPORT( int, __vlc_thread_set_priority, ( vlc_object_t *, const char *, int, int ) );
47 VLC_EXPORT( void, __vlc_thread_ready, ( vlc_object_t * ) );
48 VLC_EXPORT( void, __vlc_thread_join, ( vlc_object_t *, const char *, int ) );
50 /*****************************************************************************
51 * vlc_threads_error: Signalize an error in the threading system
52 *****************************************************************************/
54 # define vlc_threads_error( P_THIS ) (void)0
57 /*****************************************************************************
58 * vlc_threads_init: initialize threads system
59 *****************************************************************************/
60 #define vlc_threads_init( P_THIS ) \
61 __vlc_threads_init( VLC_OBJECT(P_THIS) )
63 /*****************************************************************************
64 * vlc_threads_end: deinitialize threads system
65 *****************************************************************************/
66 #define vlc_threads_end( P_THIS ) \
67 __vlc_threads_end( VLC_OBJECT(P_THIS) )
69 /*****************************************************************************
70 * vlc_mutex_init: initialize a mutex
71 *****************************************************************************/
72 #define vlc_mutex_init( P_THIS, P_MUTEX ) \
73 __vlc_mutex_init( VLC_OBJECT(P_THIS), P_MUTEX )
75 /*****************************************************************************
76 * vlc_mutex_init: initialize a recursive mutex (Don't use it)
77 *****************************************************************************/
78 #define vlc_mutex_init_recursive( P_THIS, P_MUTEX ) \
79 __vlc_mutex_init_recursive( VLC_OBJECT(P_THIS), P_MUTEX )
81 /*****************************************************************************
82 * vlc_mutex_lock: lock a mutex
83 *****************************************************************************/
84 #define vlc_mutex_lock( P_MUTEX ) \
85 __vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
87 #if defined( PTHREAD_COND_T_IN_PTHREAD_H )
88 static inline unsigned long int CAST_PTHREAD_TO_INT (pthread_t th)
90 union { pthread_t th; unsigned long int i; } v = { };
96 static inline int __vlc_mutex_lock( const char * psz_file, int i_line,
97 vlc_mutex_t * p_mutex )
100 /* In case of error : */
101 unsigned long int i_thread = 0;
103 #if defined( UNDER_CE )
104 EnterCriticalSection( &p_mutex->csection );
107 #elif defined( WIN32 )
110 WaitForSingleObject( p_mutex->mutex, INFINITE );
114 EnterCriticalSection( &p_mutex->csection );
118 #elif defined( HAVE_KERNEL_SCHEDULER_H )
119 if( p_mutex == NULL )
121 i_result = B_BAD_VALUE;
123 else if( p_mutex->init < 2000 )
125 i_result = B_NO_INIT;
129 i_result = acquire_sem( p_mutex->lock );
132 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
133 # define vlc_assert_locked( m ) \
134 assert (pthread_mutex_lock (&((m)->mutex)) == EDEADLK)
136 i_result = pthread_mutex_lock( &p_mutex->mutex );
139 i_thread = CAST_PTHREAD_TO_INT(pthread_self());
143 #elif defined( HAVE_CTHREADS_H )
144 mutex_lock( p_mutex->mutex );
151 msg_Err( p_mutex->p_this,
152 "thread %li: mutex_lock failed at %s:%d (%d:%m)",
153 i_thread, psz_file, i_line, i_result );
154 vlc_threads_error( p_mutex->p_this );
159 #ifndef vlc_assert_locked
160 # define vlc_assert_locked( m ) (void)0
163 /*****************************************************************************
164 * vlc_mutex_unlock: unlock a mutex
165 *****************************************************************************/
166 #define vlc_mutex_unlock( P_MUTEX ) \
167 __vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
169 static inline int __vlc_mutex_unlock( const char * psz_file, int i_line,
170 vlc_mutex_t *p_mutex )
173 /* In case of error : */
174 unsigned long int i_thread = 0;
176 #if defined( UNDER_CE )
177 LeaveCriticalSection( &p_mutex->csection );
180 #elif defined( WIN32 )
183 ReleaseMutex( p_mutex->mutex );
187 LeaveCriticalSection( &p_mutex->csection );
191 #elif defined( HAVE_KERNEL_SCHEDULER_H )
192 if( p_mutex == NULL )
194 i_result = B_BAD_VALUE;
196 else if( p_mutex->init < 2000 )
198 i_result = B_NO_INIT;
202 release_sem( p_mutex->lock );
206 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
207 i_result = pthread_mutex_unlock( &p_mutex->mutex );
210 i_thread = CAST_PTHREAD_TO_INT(pthread_self());
214 #elif defined( HAVE_CTHREADS_H )
215 mutex_unlock( p_mutex );
222 msg_Err( p_mutex->p_this,
223 "thread %li: mutex_unlock failed at %s:%d (%d:%m)",
224 i_thread, psz_file, i_line, i_result );
225 vlc_threads_error( p_mutex->p_this );
231 /*****************************************************************************
232 * vlc_mutex_destroy: destroy a mutex
233 *****************************************************************************/
234 #define vlc_mutex_destroy( P_MUTEX ) \
235 __vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
237 /*****************************************************************************
238 * vlc_cond_init: initialize a condition
239 *****************************************************************************/
240 #define vlc_cond_init( P_THIS, P_COND ) \
241 __vlc_cond_init( VLC_OBJECT(P_THIS), P_COND )
243 /*****************************************************************************
244 * vlc_cond_signal: start a thread on condition completion
245 *****************************************************************************/
246 #define vlc_cond_signal( P_COND ) \
247 __vlc_cond_signal( __FILE__, __LINE__, P_COND )
249 static inline int __vlc_cond_signal( const char * psz_file, int i_line,
250 vlc_cond_t *p_condvar )
253 /* In case of error : */
254 unsigned long int i_thread = 0;
256 #if defined( UNDER_CE )
257 PulseEvent( p_condvar->event );
260 #elif defined( WIN32 )
261 /* Release one waiting thread if one is available. */
262 /* For this trick to work properly, the vlc_cond_signal must be surrounded
263 * by a mutex. This will prevent another thread from stealing the signal */
264 if( !p_condvar->semaphore )
267 ** PulseEvent() only works if none of the waiting threads is suspended.
268 ** this is particularily problematic under a debug session.
269 ** as documented in http://support.microsoft.com/kb/q173260/
271 PulseEvent( p_condvar->event );
273 else if( p_condvar->i_win9x_cv == 1 )
275 /* Wait for the gate to be open */
276 WaitForSingleObject( p_condvar->event, INFINITE );
278 if( p_condvar->i_waiting_threads )
280 /* Using a semaphore exposes us to a race condition. It is
281 * possible for another thread to start waiting on the semaphore
282 * just after we signaled it and thus steal the signal.
283 * We have to prevent new threads from entering the cond_wait(). */
284 ResetEvent( p_condvar->event );
286 /* A semaphore is used here because Win9x doesn't have
287 * SignalObjectAndWait() and thus a race condition exists
288 * during the time we release the mutex and the time we start
289 * waiting on the event (more precisely, the signal can sometimes
290 * be missed by the waiting thread if we use PulseEvent()). */
291 ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
296 if( p_condvar->i_waiting_threads )
298 ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
300 /* Wait for the last thread to be awakened */
301 WaitForSingleObject( p_condvar->event, INFINITE );
306 #elif defined( HAVE_KERNEL_SCHEDULER_H )
307 if( p_condvar == NULL )
309 i_result = B_BAD_VALUE;
311 else if( p_condvar->init < 2000 )
313 i_result = B_NO_INIT;
317 while( p_condvar->thread != -1 )
320 if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
325 if( info.state != B_THREAD_SUSPENDED )
327 /* The waiting thread is not suspended so it could
328 * have been interrupted beetwen the unlock and the
329 * suspend_thread line. That is why we sleep a little
330 * before retesting p_condver->thread. */
335 /* Ok, we have to wake up that thread */
336 resume_thread( p_condvar->thread );
343 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
344 i_result = pthread_cond_signal( &p_condvar->cond );
347 i_thread = CAST_PTHREAD_TO_INT(pthread_self());
351 #elif defined( HAVE_CTHREADS_H )
352 /* condition_signal() */
353 if ( p_condvar->queue.head || p_condvar->implications )
355 cond_signal( (condition_t)p_condvar );
363 msg_Err( p_condvar->p_this,
364 "thread %li: cond_signal failed at %s:%d (%d:%m)",
365 i_thread, psz_file, i_line, i_result );
366 vlc_threads_error( p_condvar->p_this );
372 /*****************************************************************************
373 * vlc_cond_wait: wait until condition completion
374 *****************************************************************************/
375 #define vlc_cond_wait( P_COND, P_MUTEX ) \
376 __vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX )
378 static inline int __vlc_cond_wait( const char * psz_file, int i_line,
379 vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex )
382 /* In case of error : */
383 unsigned long int i_thread = 0;
385 #if defined( UNDER_CE )
386 p_condvar->i_waiting_threads++;
387 LeaveCriticalSection( &p_mutex->csection );
388 WaitForSingleObject( p_condvar->event, INFINITE );
389 p_condvar->i_waiting_threads--;
391 /* Reacquire the mutex before returning. */
392 vlc_mutex_lock( p_mutex );
396 #elif defined( WIN32 )
397 if( !p_condvar->semaphore )
399 /* Increase our wait count */
400 p_condvar->i_waiting_threads++;
404 /* It is only possible to atomically release the mutex and
405 * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
406 * SignalObjectAndWait(). */
407 p_condvar->SignalObjectAndWait( p_mutex->mutex,
413 LeaveCriticalSection( &p_mutex->csection );
414 WaitForSingleObject( p_condvar->event, INFINITE );
417 p_condvar->i_waiting_threads--;
419 else if( p_condvar->i_win9x_cv == 1 )
421 int i_waiting_threads;
423 /* Wait for the gate to be open */
424 WaitForSingleObject( p_condvar->event, INFINITE );
426 /* Increase our wait count */
427 p_condvar->i_waiting_threads++;
429 LeaveCriticalSection( &p_mutex->csection );
430 WaitForSingleObject( p_condvar->semaphore, INFINITE );
432 /* Decrement and test must be atomic */
433 EnterCriticalSection( &p_condvar->csection );
435 /* Decrease our wait count */
436 i_waiting_threads = --p_condvar->i_waiting_threads;
438 LeaveCriticalSection( &p_condvar->csection );
440 /* Reopen the gate if we were the last waiting thread */
441 if( !i_waiting_threads )
442 SetEvent( p_condvar->event );
446 int i_waiting_threads;
448 /* Increase our wait count */
449 p_condvar->i_waiting_threads++;
451 LeaveCriticalSection( &p_mutex->csection );
452 WaitForSingleObject( p_condvar->semaphore, INFINITE );
454 /* Decrement and test must be atomic */
455 EnterCriticalSection( &p_condvar->csection );
457 /* Decrease our wait count */
458 i_waiting_threads = --p_condvar->i_waiting_threads;
460 LeaveCriticalSection( &p_condvar->csection );
462 /* Signal that the last waiting thread just went through */
463 if( !i_waiting_threads )
464 SetEvent( p_condvar->event );
467 /* Reacquire the mutex before returning. */
468 vlc_mutex_lock( p_mutex );
472 #elif defined( HAVE_KERNEL_SCHEDULER_H )
473 if( p_condvar == NULL )
475 i_result = B_BAD_VALUE;
477 else if( p_mutex == NULL )
479 i_result = B_BAD_VALUE;
481 else if( p_condvar->init < 2000 )
483 i_result = B_NO_INIT;
486 /* The p_condvar->thread var is initialized before the unlock because
487 * it enables to identify when the thread is interrupted beetwen the
488 * unlock line and the suspend_thread line */
489 p_condvar->thread = find_thread( NULL );
490 vlc_mutex_unlock( p_mutex );
491 suspend_thread( p_condvar->thread );
492 p_condvar->thread = -1;
494 vlc_mutex_lock( p_mutex );
497 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
500 /* In debug mode, timeout */
501 struct timespec timeout = {
502 (mdate() / 1000000) + THREAD_COND_TIMEOUT,
503 0 /* 1Hz precision is sufficient here :-) */
506 i_result = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex,
509 if( i_result == ETIMEDOUT )
512 msg_Dbg( p_condvar->p_this,
513 "thread %li: possible condition deadlock "
514 "at %s:%d (%m)", CAST_PTHREAD_TO_INT(pthread_self()),
517 i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
521 i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
526 i_thread = CAST_PTHREAD_TO_INT(pthread_self());
530 #elif defined( HAVE_CTHREADS_H )
531 condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
538 msg_Err( p_condvar->p_this,
539 "thread %li: cond_wait failed at %s:%d (%d:%m)",
540 i_thread, psz_file, i_line, i_result );
541 vlc_threads_error( p_condvar->p_this );
548 /*****************************************************************************
549 * vlc_cond_timedwait: wait until condition completion or expiration
550 *****************************************************************************
551 * Returns 0 if object signaled, an error code in case of timeout or error.
552 *****************************************************************************/
553 #define vlc_cond_timedwait( P_COND, P_MUTEX, DEADLINE ) \
554 __vlc_cond_timedwait( __FILE__, __LINE__, P_COND, P_MUTEX, DEADLINE )
556 static inline int __vlc_cond_timedwait( const char * psz_file, int i_line,
557 vlc_cond_t *p_condvar,
558 vlc_mutex_t *p_mutex,
562 unsigned long int i_thread = 0;
564 #if defined( UNDER_CE )
565 mtime_t delay_ms = (deadline - mdate())/1000;
571 p_condvar->i_waiting_threads++;
572 LeaveCriticalSection( &p_mutex->csection );
573 result = WaitForSingleObject( p_condvar->event, delay_ms );
574 p_condvar->i_waiting_threads--;
576 /* Reacquire the mutex before returning. */
577 vlc_mutex_lock( p_mutex );
580 if(result == WAIT_TIMEOUT)
581 return WAIT_TIMEOUT; /* this error is perfectly normal */
583 #elif defined( WIN32 )
586 mtime_t delay_ms = (deadline - mdate())/1000;
590 if( !p_condvar->semaphore )
592 /* Increase our wait count */
593 p_condvar->i_waiting_threads++;
597 /* It is only possible to atomically release the mutex and
598 * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
599 * SignalObjectAndWait(). */
600 result = p_condvar->SignalObjectAndWait( p_mutex->mutex,
606 LeaveCriticalSection( &p_mutex->csection );
607 result = WaitForSingleObject( p_condvar->event, delay_ms );
610 p_condvar->i_waiting_threads--;
612 else if( p_condvar->i_win9x_cv == 1 )
614 int i_waiting_threads;
616 /* Wait for the gate to be open */
617 result = WaitForSingleObject( p_condvar->event, delay_ms );
619 /* Increase our wait count */
620 p_condvar->i_waiting_threads++;
622 LeaveCriticalSection( &p_mutex->csection );
625 /* recaculate remaining delay */
626 delay_ms = (deadline - mdate())/1000;
630 result = WaitForSingleObject( p_condvar->semaphore, delay_ms );
633 /* Decrement and test must be atomic */
634 EnterCriticalSection( &p_condvar->csection );
636 /* Decrease our wait count */
637 i_waiting_threads = --p_condvar->i_waiting_threads;
639 LeaveCriticalSection( &p_condvar->csection );
641 /* Reopen the gate if we were the last waiting thread */
642 if( !i_waiting_threads )
643 SetEvent( p_condvar->event );
647 int i_waiting_threads;
649 /* Increase our wait count */
650 p_condvar->i_waiting_threads++;
652 LeaveCriticalSection( &p_mutex->csection );
653 result = WaitForSingleObject( p_condvar->semaphore, delay_ms );
655 /* Decrement and test must be atomic */
656 EnterCriticalSection( &p_condvar->csection );
658 /* Decrease our wait count */
659 i_waiting_threads = --p_condvar->i_waiting_threads;
661 LeaveCriticalSection( &p_condvar->csection );
663 /* Signal that the last waiting thread just went through */
664 if( !i_waiting_threads )
665 SetEvent( p_condvar->event );
668 /* Reacquire the mutex before returning. */
669 vlc_mutex_lock( p_mutex );
670 if(result == WAIT_TIMEOUT)
671 return WAIT_TIMEOUT; /* this error is perfectly normal */
675 #elif defined( HAVE_KERNEL_SCHEDULER_H )
676 # error Unimplemented
677 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
678 lldiv_t d = lldiv( deadline, 1000000 );
679 struct timespec ts = { d.quot, d.rem * 1000 };
681 i_res = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex, &ts );
682 if( i_res == ETIMEDOUT )
683 return ETIMEDOUT; /* this error is perfectly normal */
685 if ( i_res ) /* other errors = bug */
687 i_thread = CAST_PTHREAD_TO_INT(pthread_self());
691 #elif defined( HAVE_CTHREADS_H )
692 # error Unimplemented
697 msg_Err( p_condvar->p_this,
698 "thread %li: cond_wait failed at %s:%d (%d:%m)",
699 i_thread, psz_file, i_line, i_res );
700 vlc_threads_error( p_condvar->p_this );
706 /*****************************************************************************
707 * vlc_cond_destroy: destroy a condition
708 *****************************************************************************/
709 #define vlc_cond_destroy( P_COND ) \
710 __vlc_cond_destroy( __FILE__, __LINE__, P_COND )
712 /*****************************************************************************
713 * vlc_threadvar_create: create a thread-local variable
714 *****************************************************************************/
715 #define vlc_threadvar_create( PTHIS, P_TLS ) \
716 __vlc_threadvar_create( PTHIS, P_TLS )
718 /*****************************************************************************
719 * vlc_threadvar_set: create: set the value of a thread-local variable
720 *****************************************************************************/
721 static inline int vlc_threadvar_set( vlc_threadvar_t * p_tls, void *p_value )
725 #if defined( HAVE_KERNEL_SCHEDULER_H )
728 #elif defined( UNDER_CE ) || defined( WIN32 )
729 i_ret = ( TlsSetValue( p_tls->handle, p_value ) != 0 );
731 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
732 i_ret = pthread_setspecific( p_tls->handle, p_value );
734 #elif defined( HAVE_CTHREADS_H )
735 i_ret = cthread_setspecific( p_tls->handle, p_value );
741 /*****************************************************************************
742 * vlc_threadvar_get: create: get the value of a thread-local variable
743 *****************************************************************************/
744 static inline void* vlc_threadvar_get( vlc_threadvar_t * p_tls )
748 #if defined( HAVE_KERNEL_SCHEDULER_H )
750 #elif defined( UNDER_CE ) || defined( WIN32 )
751 p_ret = TlsGetValue( p_tls->handle );
753 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
754 p_ret = pthread_getspecific( p_tls->handle );
756 #elif defined( HAVE_CTHREADS_H )
757 if ( !cthread_getspecific( p_tls->handle, &p_ret ) )
766 # if defined (_POSIX_SPIN_LOCKS) && ((_POSIX_SPIN_LOCKS - 0) > 0)
769 pthread_spinlock_t spin;
773 * Initializes a spinlock.
775 static inline int vlc_spin_init (vlc_spinlock_t *spin)
777 return pthread_spin_init (&spin->spin, PTHREAD_PROCESS_PRIVATE);
781 * Acquires a spinlock.
783 static inline int vlc_spin_lock (vlc_spinlock_t *spin)
785 return pthread_spin_lock (&spin->spin);
789 * Releases a spinlock.
791 static inline int vlc_spin_unlock (vlc_spinlock_t *spin)
793 return pthread_spin_unlock (&spin->spin);
797 * Deinitializes a spinlock.
799 static inline int vlc_spin_destroy (vlc_spinlock_t *spin)
801 return pthread_spin_destroy (&spin->spin);
804 /* Fallback to plain mutexes if spinlocks are not available */
805 typedef vlc_mutex_t vlc_spinlock_t;
807 static inline int vlc_spin_init (vlc_spinlock_t *spin)
809 return __vlc_mutex_init (NULL, spin);
812 # define vlc_spin_lock vlc_mutex_lock
813 # define vlc_spin_unlock vlc_mutex_unlock
814 # define vlc_spin_destroy vlc_mutex_destroy
817 /*****************************************************************************
818 * vlc_thread_create: create a thread
819 *****************************************************************************/
820 #define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY, WAIT ) \
821 __vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, (void * ( * ) ( void * ))FUNC, PRIORITY, WAIT )
823 /*****************************************************************************
824 * vlc_thread_set_priority: set the priority of the calling thread
825 *****************************************************************************/
826 #define vlc_thread_set_priority( P_THIS, PRIORITY ) \
827 __vlc_thread_set_priority( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PRIORITY )
829 /*****************************************************************************
830 * vlc_thread_ready: tell the parent thread we were successfully spawned
831 *****************************************************************************/
832 #define vlc_thread_ready( P_THIS ) \
833 __vlc_thread_ready( VLC_OBJECT(P_THIS) )
835 /*****************************************************************************
836 * vlc_thread_join: wait until a thread exits
837 *****************************************************************************/
838 #define vlc_thread_join( P_THIS ) \
839 __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )