]> git.sesse.net Git - vlc/blob - include/vlc_threads_funcs.h
* ./include/vlc_common.h: fixed win32 plugin compilation.
[vlc] / include / vlc_threads_funcs.h
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 VideoLAN
6  * $Id: vlc_threads_funcs.h,v 1.12 2003/01/16 09:02:46 sam Exp $
7  *
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>
12  *
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.
17  *
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.
22  *
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Function definitions
30  *****************************************************************************/
31 VLC_EXPORT( int,  __vlc_threads_init,  ( vlc_object_t * ) );
32 VLC_EXPORT( int,  __vlc_threads_end,   ( vlc_object_t * ) );
33 VLC_EXPORT( int,  __vlc_mutex_init,    ( vlc_object_t *, vlc_mutex_t * ) );
34 VLC_EXPORT( int,  __vlc_mutex_destroy, ( char *, int, vlc_mutex_t * ) );
35 VLC_EXPORT( int,  __vlc_cond_init,     ( vlc_object_t *, vlc_cond_t * ) );
36 VLC_EXPORT( int,  __vlc_cond_destroy,  ( char *, int, vlc_cond_t * ) );
37 VLC_EXPORT( int,  __vlc_thread_create, ( vlc_object_t *, char *, int, char *, void * ( * ) ( void * ), int, vlc_bool_t ) );
38 VLC_EXPORT( int,  __vlc_thread_set_priority, ( vlc_object_t *, char *, int, int ) );
39 VLC_EXPORT( void, __vlc_thread_ready,  ( vlc_object_t * ) );
40 VLC_EXPORT( void, __vlc_thread_join,   ( vlc_object_t *, char *, int ) );
41
42
43 /*****************************************************************************
44  * vlc_threads_init: initialize threads system
45  *****************************************************************************/
46 #define vlc_threads_init( P_THIS )                                          \
47     __vlc_threads_init( VLC_OBJECT(P_THIS) )
48
49 /*****************************************************************************
50  * vlc_threads_end: deinitialize threads system
51  *****************************************************************************/
52 #define vlc_threads_end( P_THIS )                                           \
53     __vlc_threads_end( VLC_OBJECT(P_THIS) )
54
55 /*****************************************************************************
56  * vlc_mutex_init: initialize a mutex
57  *****************************************************************************/
58 #define vlc_mutex_init( P_THIS, P_MUTEX )                                   \
59     __vlc_mutex_init( VLC_OBJECT(P_THIS), P_MUTEX )
60
61 /*****************************************************************************
62  * vlc_mutex_lock: lock a mutex
63  *****************************************************************************/
64 #define vlc_mutex_lock( P_MUTEX )                                           \
65     __vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
66
67 static inline int __vlc_mutex_lock( char * psz_file, int i_line,
68                                     vlc_mutex_t * p_mutex )
69 {
70     int i_result;
71     /* In case of error : */
72     int i_thread = -1;
73     const char * psz_error = "";
74
75 #if defined( PTH_INIT_IN_PTH_H )
76     i_result = pth_mutex_acquire( &p_mutex->mutex, TRUE, NULL );
77
78 #elif defined( ST_INIT_IN_ST_H )
79     i_result = st_mutex_lock( p_mutex->mutex );
80
81 #elif defined( UNDER_CE )
82     EnterCriticalSection( &p_mutex->csection );
83     i_result = 0;
84
85 #elif defined( WIN32 )
86     if( p_mutex->mutex )
87     {
88         WaitForSingleObject( p_mutex->mutex, INFINITE );
89     }
90     else
91     {
92         EnterCriticalSection( &p_mutex->csection );
93     }
94     i_result = 0;
95
96 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
97     i_result = pthread_mutex_lock( &p_mutex->mutex );
98     if ( i_result )
99     {
100         i_thread = (int)pthread_self();
101         psz_error = strerror(i_result);
102     }
103
104 #elif defined( HAVE_CTHREADS_H )
105     mutex_lock( p_mutex->mutex );
106     i_result = 0;
107
108 #elif defined( HAVE_KERNEL_SCHEDULER_H )
109     if( p_mutex == NULL )
110     {
111         i_result = B_BAD_VALUE;
112     }
113     else if( p_mutex->init < 2000 )
114     {
115         i_result = B_NO_INIT;
116     }
117     else
118     {
119         i_result = acquire_sem( p_mutex->lock );
120     }
121 #endif
122
123     if( i_result )
124     {
125         msg_Err( p_mutex->p_this,
126                  "thread %d: mutex_lock failed at %s:%d (%d:%s)",
127                  i_thread, psz_file, i_line, i_result, psz_error );
128     }
129     return i_result;
130 }
131
132 /*****************************************************************************
133  * vlc_mutex_unlock: unlock a mutex
134  *****************************************************************************/
135 #define vlc_mutex_unlock( P_MUTEX )                                         \
136     __vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
137
138 static inline int __vlc_mutex_unlock( char * psz_file, int i_line,
139                                       vlc_mutex_t *p_mutex )
140 {
141     int i_result;
142     /* In case of error : */
143     int i_thread = -1;
144     const char * psz_error = "";
145
146 #if defined( PTH_INIT_IN_PTH_H )
147     i_result = pth_mutex_release( &p_mutex->mutex );
148
149 #elif defined( ST_INIT_IN_ST_H )
150     i_result = st_mutex_unlock( p_mutex->mutex );
151
152 #elif defined( UNDER_CE )
153     LeaveCriticalSection( &p_mutex->csection );
154     i_result = 0;
155
156 #elif defined( WIN32 )
157     if( p_mutex->mutex )
158     {
159         ReleaseMutex( p_mutex->mutex );
160     }
161     else
162     {
163         LeaveCriticalSection( &p_mutex->csection );
164     }
165     i_result = 0;
166
167 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
168     i_result = pthread_mutex_unlock( &p_mutex->mutex );
169     if ( i_result )
170     {
171         i_thread = (int)pthread_self();
172         psz_error = strerror(i_result);
173     }
174
175 #elif defined( HAVE_CTHREADS_H )
176     mutex_unlock( p_mutex );
177     i_result = 0;
178
179 #elif defined( HAVE_KERNEL_SCHEDULER_H )
180     if( p_mutex == NULL )
181     {
182         i_result = B_BAD_VALUE;
183     }
184     else if( p_mutex->init < 2000 )
185     {
186         i_result = B_NO_INIT;
187     }
188     else
189     {
190         release_sem( p_mutex->lock );
191         return B_OK;
192     }
193 #endif
194
195     if( i_result )
196     {
197         msg_Err( p_mutex->p_this,
198                  "thread %d: mutex_unlock failed at %s:%d (%d:%s)",
199                  i_thread, psz_file, i_line, i_result, psz_error );
200     }
201
202     return i_result;
203 }
204
205 /*****************************************************************************
206  * vlc_mutex_destroy: destroy a mutex
207  *****************************************************************************/
208 #define vlc_mutex_destroy( P_MUTEX )                                        \
209     __vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
210
211 /*****************************************************************************
212  * vlc_cond_init: initialize a condition
213  *****************************************************************************/
214 #define vlc_cond_init( P_THIS, P_COND )                                     \
215     __vlc_cond_init( VLC_OBJECT(P_THIS), P_COND )
216
217 /*****************************************************************************
218  * vlc_cond_signal: start a thread on condition completion
219  *****************************************************************************/
220 #define vlc_cond_signal( P_COND )                                           \
221     __vlc_cond_signal( __FILE__, __LINE__, P_COND )
222
223 static inline int __vlc_cond_signal( char * psz_file, int i_line,
224                                      vlc_cond_t *p_condvar )
225 {
226     int i_result;
227     /* In case of error : */
228     int i_thread = -1;
229     const char * psz_error = "";
230
231 #if defined( PTH_INIT_IN_PTH_H )
232     i_result = pth_cond_notify( &p_condvar->cond, FALSE );
233
234 #elif defined( ST_INIT_IN_ST_H )
235     i_result = st_cond_signal( p_condvar->cond );
236
237 #elif defined( UNDER_CE )
238     PulseEvent( p_condvar->event );
239     i_result = 0;
240
241 #elif defined( WIN32 )
242     /* Release one waiting thread if one is available. */
243     /* For this trick to work properly, the vlc_cond_signal must be surrounded
244      * by a mutex. This will prevent another thread from stealing the signal */
245     if( !p_condvar->semaphore )
246     {
247         PulseEvent( p_condvar->event );
248     }
249     else if( p_condvar->i_win9x_cv == 1 )
250     {
251         /* Wait for the gate to be open */
252         WaitForSingleObject( p_condvar->event, INFINITE );
253
254         if( p_condvar->i_waiting_threads )
255         {
256             /* Using a semaphore exposes us to a race condition. It is
257              * possible for another thread to start waiting on the semaphore
258              * just after we signaled it and thus steal the signal.
259              * We have to prevent new threads from entering the cond_wait(). */
260             ResetEvent( p_condvar->event );
261
262             /* A semaphore is used here because Win9x doesn't have
263              * SignalObjectAndWait() and thus a race condition exists
264              * during the time we release the mutex and the time we start
265              * waiting on the event (more precisely, the signal can sometimes
266              * be missed by the waiting thread if we use PulseEvent()). */
267             ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
268         }
269     }
270     else
271     {
272         if( p_condvar->i_waiting_threads )
273         {
274             ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
275
276             /* Wait for the last thread to be awakened */
277             WaitForSingleObject( p_condvar->event, INFINITE );
278         }
279     }
280     i_result = 0;
281
282 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
283     i_result = pthread_cond_signal( &p_condvar->cond );
284     if ( i_result )
285     {
286         i_thread = (int)pthread_self();
287         psz_error = strerror(i_result);
288     }
289
290 #elif defined( HAVE_CTHREADS_H )
291     /* condition_signal() */
292     if ( p_condvar->queue.head || p_condvar->implications )
293     {
294         cond_signal( (condition_t)p_condvar );
295     }
296     i_result = 0;
297
298 #elif defined( HAVE_KERNEL_SCHEDULER_H )
299     if( p_condvar == NULL )
300     {
301         i_result = B_BAD_VALUE;
302     }
303     else if( p_condvar->init < 2000 )
304     {
305         i_result = B_NO_INIT;
306     }
307     else
308     {
309         while( p_condvar->thread != -1 )
310         {
311             thread_info info;
312             if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
313             {
314                 return 0;
315             }
316
317             if( info.state != B_THREAD_SUSPENDED )
318             {
319                 /* The  waiting thread is not suspended so it could
320                  * have been interrupted beetwen the unlock and the
321                  * suspend_thread line. That is why we sleep a little
322                  * before retesting p_condver->thread. */
323                 snooze( 10000 );
324             }
325             else
326             {
327                 /* Ok, we have to wake up that thread */
328                 resume_thread( p_condvar->thread );
329                 return 0;
330             }
331         }
332         i_result = 0;
333     }
334 #endif
335
336     if( i_result )
337     {
338         msg_Err( p_condvar->p_this,
339                  "thread %d: cond_signal failed at %s:%d (%d:%s)",
340                  i_thread, psz_file, i_line, i_result, psz_error );
341     }
342
343     return i_result;
344 }
345
346 /*****************************************************************************
347  * vlc_cond_broadcast: start all threads waiting on condition completion
348  *****************************************************************************/
349 /*
350  * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
351  * Only works with pthreads, st, win32
352  * You need to adapt it for others
353  * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
354  */
355 #define vlc_cond_broadcast( P_COND )                                        \
356     __vlc_cond_broadcast( __FILE__, __LINE__, P_COND )
357
358 static inline int __vlc_cond_broadcast( char * psz_file, int i_line,
359                                         vlc_cond_t *p_condvar )
360 {
361     int i_result;
362     /* In case of error : */
363     int i_thread = -1;
364     const char * psz_error = "";
365
366 #if defined( PTH_INIT_IN_PTH_H )
367     i_result = pth_cond_notify( &p_condvar->cond, FALSE );
368
369 #elif defined( ST_INIT_IN_ST_H )
370     i_result = st_cond_broadcast( p_condvar->cond );
371
372 #elif defined( UNDER_CE )
373     int i;
374
375     /* Release all waiting threads. */
376     for( i = p_condvar->i_waiting_threads; i > 0; i-- )
377     {
378         PulseEvent( p_condvar->event );
379     }
380     i_result = 0;
381
382 #elif defined( WIN32 )
383     int i;
384
385     /* Release all waiting threads. */
386     if( !p_condvar->semaphore )
387     {
388         for( i = p_condvar->i_waiting_threads; i > 0; i-- )
389         {
390             PulseEvent( p_condvar->event );
391         }
392     }
393     else if( p_condvar->i_win9x_cv == 1 )
394     {
395         /* Wait for the gate to be open */
396         WaitForSingleObject( p_condvar->event, INFINITE );
397
398         if( p_condvar->i_waiting_threads )
399         {
400             /* Using a semaphore exposes us to a race condition. It is
401              * possible for another thread to start waiting on the semaphore
402              * just after we signaled it and thus steal the signal.
403              * We have to prevent new threads from entering the cond_wait(). */
404             ResetEvent( p_condvar->event );
405
406             /* A semaphore is used here because Win9x doesn't have
407              * SignalObjectAndWait() and thus a race condition exists
408              * during the time we release the mutex and the time we start
409              * waiting on the event (more precisely, the signal can sometimes
410              * be missed by the waiting thread if we use PulseEvent()). */
411             ReleaseSemaphore( p_condvar->semaphore,
412                               p_condvar->i_waiting_threads, 0 );
413         }
414     }
415     else
416     {
417         if( p_condvar->i_waiting_threads )
418         {
419             ReleaseSemaphore( p_condvar->semaphore,
420                               p_condvar->i_waiting_threads, 0 );
421
422             /* Wait for the last thread to be awakened */
423             WaitForSingleObject( p_condvar->event, INFINITE );
424         }
425     }
426     i_result = 0;
427
428 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
429     i_result = pthread_cond_broadcast( &p_condvar->cond );
430     if ( i_result )
431     {
432         i_thread = (int)pthread_self();
433         psz_error = strerror(i_result);
434     }
435
436 #elif defined( HAVE_CTHREADS_H )
437     /* condition_signal() */
438     if ( p_condvar->queue.head || p_condvar->implications )
439     {
440         cond_signal( (condition_t)p_condvar );
441     }
442     i_result = 0;
443
444 #elif defined( HAVE_KERNEL_SCHEDULER_H )
445     if( p_condvar == NULL )
446     {
447         i_result = B_BAD_VALUE;
448     }
449     else if( p_condvar->init < 2000 )
450     {
451         i_result = B_NO_INIT;
452     }
453     else
454     {
455         while( p_condvar->thread != -1 )
456         {
457             thread_info info;
458             if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
459             {
460                 return 0;
461             }
462
463             if( info.state != B_THREAD_SUSPENDED )
464             {
465                 /* The  waiting thread is not suspended so it could
466                  * have been interrupted beetwen the unlock and the
467                  * suspend_thread line. That is why we sleep a little
468                  * before retesting p_condver->thread. */
469                 snooze( 10000 );
470             }
471             else
472             {
473                 /* Ok, we have to wake up that thread */
474                 resume_thread( p_condvar->thread );
475                 return 0;
476             }
477         }
478         i_result = 0;
479     }
480 #endif
481
482     if( i_result )
483     {
484         msg_Err( p_condvar->p_this,
485                  "thread %d: cond_broadcast failed at %s:%d (%d:%s)",
486                  i_thread, psz_file, i_line, i_result, psz_error );
487     }
488
489     return i_result;
490 }
491
492 /*****************************************************************************
493  * vlc_cond_wait: wait until condition completion
494  *****************************************************************************/
495 #define vlc_cond_wait( P_COND, P_MUTEX )                                     \
496     __vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX  )
497
498 static inline int __vlc_cond_wait( char * psz_file, int i_line,
499                                    vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex )
500 {
501     int i_result;
502     /* In case of error : */
503     int i_thread = -1;
504     const char * psz_error = "";
505
506 #if defined( PTH_INIT_IN_PTH_H )
507     i_result = pth_cond_await( &p_condvar->cond, &p_mutex->mutex, NULL );
508
509 #elif defined( ST_INIT_IN_ST_H )
510     st_mutex_unlock( p_mutex->mutex );
511     i_result = st_cond_wait( p_condvar->cond );
512     st_mutex_lock( p_mutex->mutex );
513
514 #elif defined( UNDER_CE )
515     p_condvar->i_waiting_threads++;
516     LeaveCriticalSection( &p_mutex->csection );
517     WaitForSingleObject( p_condvar->event, INFINITE );
518     p_condvar->i_waiting_threads--;
519
520     /* Reacquire the mutex before returning. */
521     vlc_mutex_lock( p_mutex );
522
523     i_result = 0;
524
525 #elif defined( WIN32 )
526     if( !p_condvar->semaphore )
527     {
528         /* Increase our wait count */
529         p_condvar->i_waiting_threads++;
530
531         if( p_mutex->mutex )
532         {
533             /* It is only possible to atomically release the mutex and
534              * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
535              * SignalObjectAndWait(). */
536             p_condvar->SignalObjectAndWait( p_mutex->mutex,
537                                             p_condvar->event,
538                                             INFINITE, FALSE );
539         }
540         else
541         {
542             LeaveCriticalSection( &p_mutex->csection );
543             WaitForSingleObject( p_condvar->event, INFINITE );
544         }
545
546         p_condvar->i_waiting_threads--;
547     }
548     else if( p_condvar->i_win9x_cv == 1 )
549     {
550         int i_waiting_threads;
551
552         /* Wait for the gate to be open */
553         WaitForSingleObject( p_condvar->event, INFINITE );
554
555         /* Increase our wait count */
556         p_condvar->i_waiting_threads++;
557
558         LeaveCriticalSection( &p_mutex->csection );
559         WaitForSingleObject( p_condvar->semaphore, INFINITE );
560
561         /* Decrement and test must be atomic */
562         EnterCriticalSection( &p_condvar->csection );
563
564         /* Decrease our wait count */
565         i_waiting_threads = --p_condvar->i_waiting_threads;
566
567         LeaveCriticalSection( &p_condvar->csection );
568
569         /* Reopen the gate if we were the last waiting thread */
570         if( !i_waiting_threads )
571             SetEvent( p_condvar->event );
572     }
573     else
574     {
575         int i_waiting_threads;
576
577         /* Increase our wait count */
578         p_condvar->i_waiting_threads++;
579
580         LeaveCriticalSection( &p_mutex->csection );
581         WaitForSingleObject( p_condvar->semaphore, INFINITE );
582
583         /* Decrement and test must be atomic */
584         EnterCriticalSection( &p_condvar->csection );
585
586         /* Decrease our wait count */
587         i_waiting_threads = --p_condvar->i_waiting_threads;
588
589         LeaveCriticalSection( &p_condvar->csection );
590
591         /* Signal that the last waiting thread just went through */
592         if( !i_waiting_threads )
593             SetEvent( p_condvar->event );
594     }
595
596     /* Reacquire the mutex before returning. */
597     vlc_mutex_lock( p_mutex );
598
599     i_result = 0;
600
601 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
602
603 #   ifdef DEBUG
604     /* In debug mode, timeout */
605     struct timeval now;
606     struct timespec timeout;
607
608     for( ; ; )
609     {
610         gettimeofday( &now, NULL );
611         timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT;
612         timeout.tv_nsec = now.tv_usec * 1000;
613
614         i_result = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex,
615                                            &timeout );
616
617         if( i_result == ETIMEDOUT )
618         {
619             msg_Warn( p_condvar->p_this,
620                       "thread %d: possible deadlock detected "
621                       "in cond_wait at %s:%d (%s)", (int)pthread_self(),
622                       psz_file, i_line, strerror(i_result) );
623         }
624         else break;
625     }
626 #   else
627     i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
628 #   endif
629
630     if ( i_result )
631     {
632         i_thread = (int)pthread_self();
633         psz_error = strerror(i_result);
634     }
635
636 #elif defined( HAVE_CTHREADS_H )
637     condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
638     i_result = 0;
639
640 #elif defined( HAVE_KERNEL_SCHEDULER_H )
641     if( p_condvar == NULL )
642     {
643         i_result = B_BAD_VALUE;
644     }
645     else if( p_mutex == NULL )
646     {
647         i_result = B_BAD_VALUE;
648     }
649     else if( p_condvar->init < 2000 )
650     {
651         i_result = B_NO_INIT;
652     }
653
654     /* The p_condvar->thread var is initialized before the unlock because
655      * it enables to identify when the thread is interrupted beetwen the
656      * unlock line and the suspend_thread line */
657     p_condvar->thread = find_thread( NULL );
658     vlc_mutex_unlock( p_mutex );
659     suspend_thread( p_condvar->thread );
660     p_condvar->thread = -1;
661
662     vlc_mutex_lock( p_mutex );
663     i_result = 0;
664
665 #endif
666
667     if( i_result )
668     {
669         msg_Err( p_condvar->p_this,
670                  "thread %d: cond_wait failed at %s:%d (%d:%s)",
671                  i_thread, psz_file, i_line, i_result, psz_error );
672     }
673
674     return i_result;
675 }
676
677 /*****************************************************************************
678  * vlc_cond_destroy: destroy a condition
679  *****************************************************************************/
680 #define vlc_cond_destroy( P_COND )                                          \
681     __vlc_cond_destroy( __FILE__, __LINE__, P_COND )
682
683 /*****************************************************************************
684  * vlc_thread_create: create a thread
685  *****************************************************************************/
686 #define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY, WAIT )         \
687     __vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, (void * ( * ) ( void * ))FUNC, PRIORITY, WAIT )
688
689 /*****************************************************************************
690  * vlc_thread_set_priority: set the priority of the calling thread
691  *****************************************************************************/
692 #define vlc_thread_set_priority( P_THIS, PRIORITY )                         \
693     __vlc_thread_set_priority( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PRIORITY )
694
695 /*****************************************************************************
696  * vlc_thread_ready: tell the parent thread we were successfully spawned
697  *****************************************************************************/
698 #define vlc_thread_ready( P_THIS )                                          \
699     __vlc_thread_ready( VLC_OBJECT(P_THIS) )
700
701 /*****************************************************************************
702  * vlc_thread_join: wait until a thread exits
703  *****************************************************************************/
704 #define vlc_thread_join( P_THIS )                                           \
705     __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )