vlc_threads: document gibalou's comment, and fix a small bug in win32 vlc_cond_timedw...
[vlc.git] / 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-2007 the VideoLAN team
6  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 #if !defined( __LIBVLC__ )
29   #error You are not libvlc or one of its plugins. You cannot include this file
30 #endif
31
32 #ifndef _VLC_THREADFUNCS_H_
33 #define _VLC_THREADFUNCS_H_
34
35 /*****************************************************************************
36  * Function definitions
37  *****************************************************************************/
38 VLC_EXPORT( int,  __vlc_mutex_init,    ( vlc_object_t *, vlc_mutex_t * ) );
39 VLC_EXPORT( int,  __vlc_mutex_destroy, ( const char *, int, vlc_mutex_t * ) );
40 VLC_EXPORT( int,  __vlc_cond_init,     ( vlc_object_t *, vlc_cond_t * ) );
41 VLC_EXPORT( int,  __vlc_cond_destroy,  ( const char *, int, vlc_cond_t * ) );
42 VLC_EXPORT( int, __vlc_threadvar_create, (vlc_object_t *, vlc_threadvar_t * ) );
43 VLC_EXPORT( int,  __vlc_thread_create, ( vlc_object_t *, const char *, int, const char *, void * ( * ) ( void * ), int, vlc_bool_t ) );
44 VLC_EXPORT( int,  __vlc_thread_set_priority, ( vlc_object_t *, const char *, int, int ) );
45 VLC_EXPORT( void, __vlc_thread_ready,  ( vlc_object_t * ) );
46 VLC_EXPORT( void, __vlc_thread_join,   ( vlc_object_t *, const char *, int ) );
47
48 /*****************************************************************************
49  * vlc_threads_init: initialize threads system
50  *****************************************************************************/
51 #define vlc_threads_init( P_THIS )                                          \
52     __vlc_threads_init( VLC_OBJECT(P_THIS) )
53
54 /*****************************************************************************
55  * vlc_threads_end: deinitialize threads system
56  *****************************************************************************/
57 #define vlc_threads_end( P_THIS )                                           \
58     __vlc_threads_end( VLC_OBJECT(P_THIS) )
59
60 /*****************************************************************************
61  * vlc_mutex_init: initialize a mutex
62  *****************************************************************************/
63 #define vlc_mutex_init( P_THIS, P_MUTEX )                                   \
64     __vlc_mutex_init( VLC_OBJECT(P_THIS), P_MUTEX )
65
66 /*****************************************************************************
67  * vlc_mutex_lock: lock a mutex
68  *****************************************************************************/
69 #define vlc_mutex_lock( P_MUTEX )                                           \
70     __vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
71
72 #ifdef __APPLE__
73 #   define CAST_PTHREAD_TO_INT(t) (unsigned long int)(uintptr_t)(void *)t
74 #else
75 #   define CAST_PTHREAD_TO_INT(t) (unsigned long int)t
76 #endif
77
78 static inline int __vlc_mutex_lock( const char * psz_file, int i_line,
79                                     vlc_mutex_t * p_mutex )
80 {
81     int i_result;
82     /* In case of error : */
83     unsigned long int i_thread = 0;
84
85 #if defined( PTH_INIT_IN_PTH_H )
86     i_result = ( pth_mutex_acquire( &p_mutex->mutex, FALSE, NULL ) == FALSE );
87
88 #elif defined( ST_INIT_IN_ST_H )
89     i_result = st_mutex_lock( p_mutex->mutex );
90
91 #elif defined( UNDER_CE )
92     EnterCriticalSection( &p_mutex->csection );
93     i_result = 0;
94
95 #elif defined( WIN32 )
96     if( p_mutex->mutex )
97     {
98         WaitForSingleObject( p_mutex->mutex, INFINITE );
99     }
100     else
101     {
102         EnterCriticalSection( &p_mutex->csection );
103     }
104     i_result = 0;
105
106 #elif defined( HAVE_KERNEL_SCHEDULER_H )
107     if( p_mutex == NULL )
108     {
109         i_result = B_BAD_VALUE;
110     }
111     else if( p_mutex->init < 2000 )
112     {
113         i_result = B_NO_INIT;
114     }
115     else
116     {
117         i_result = acquire_sem( p_mutex->lock );
118     }
119
120 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
121 #   define vlc_assert_locked( m ) \
122            assert (pthread_mutex_lock (&((m)->mutex)) == EDEADLK)
123
124     i_result = pthread_mutex_lock( &p_mutex->mutex );
125     if ( i_result )
126     {
127         i_thread = CAST_PTHREAD_TO_INT(pthread_self());
128         errno = i_result;
129     }
130
131 #elif defined( HAVE_CTHREADS_H )
132     mutex_lock( p_mutex->mutex );
133     i_result = 0;
134
135 #endif
136
137     if( i_result )
138     {
139         msg_Err( p_mutex->p_this,
140                  "thread %li: mutex_lock failed at %s:%d (%d:%m)",
141                  i_thread, psz_file, i_line, i_result );
142     }
143     return i_result;
144 }
145
146 #ifndef vlc_assert_locked
147 # define vlc_assert_locked( m ) (void)0
148 #endif
149
150 /*****************************************************************************
151  * vlc_mutex_unlock: unlock a mutex
152  *****************************************************************************/
153 #define vlc_mutex_unlock( P_MUTEX )                                         \
154     __vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
155
156 static inline int __vlc_mutex_unlock( const char * psz_file, int i_line,
157                                       vlc_mutex_t *p_mutex )
158 {
159     int i_result;
160     /* In case of error : */
161     unsigned long int i_thread = 0;
162
163 #if defined( PTH_INIT_IN_PTH_H )
164     i_result = ( pth_mutex_release( &p_mutex->mutex ) == FALSE );
165
166 #elif defined( ST_INIT_IN_ST_H )
167     i_result = st_mutex_unlock( p_mutex->mutex );
168
169 #elif defined( UNDER_CE )
170     LeaveCriticalSection( &p_mutex->csection );
171     i_result = 0;
172
173 #elif defined( WIN32 )
174     if( p_mutex->mutex )
175     {
176         ReleaseMutex( p_mutex->mutex );
177     }
178     else
179     {
180         LeaveCriticalSection( &p_mutex->csection );
181     }
182     i_result = 0;
183
184 #elif defined( HAVE_KERNEL_SCHEDULER_H )
185     if( p_mutex == NULL )
186     {
187         i_result = B_BAD_VALUE;
188     }
189     else if( p_mutex->init < 2000 )
190     {
191         i_result = B_NO_INIT;
192     }
193     else
194     {
195         release_sem( p_mutex->lock );
196         return B_OK;
197     }
198
199 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
200     i_result = pthread_mutex_unlock( &p_mutex->mutex );
201     if ( i_result )
202     {
203         i_thread = CAST_PTHREAD_TO_INT(pthread_self());
204         errno = i_result;
205     }
206
207 #elif defined( HAVE_CTHREADS_H )
208     mutex_unlock( p_mutex );
209     i_result = 0;
210
211 #endif
212
213     if( i_result )
214     {
215         msg_Err( p_mutex->p_this,
216                  "thread %li: mutex_unlock failed at %s:%d (%d:%m)",
217                  i_thread, psz_file, i_line, i_result );
218     }
219
220     return i_result;
221 }
222
223 /*****************************************************************************
224  * vlc_mutex_destroy: destroy a mutex
225  *****************************************************************************/
226 #define vlc_mutex_destroy( P_MUTEX )                                        \
227     __vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
228
229 /*****************************************************************************
230  * vlc_cond_init: initialize a condition
231  *****************************************************************************/
232 #define vlc_cond_init( P_THIS, P_COND )                                     \
233     __vlc_cond_init( VLC_OBJECT(P_THIS), P_COND )
234
235 /*****************************************************************************
236  * vlc_cond_signal: start a thread on condition completion
237  *****************************************************************************/
238 #define vlc_cond_signal( P_COND )                                           \
239     __vlc_cond_signal( __FILE__, __LINE__, P_COND )
240
241 static inline int __vlc_cond_signal( const char * psz_file, int i_line,
242                                      vlc_cond_t *p_condvar )
243 {
244     int i_result;
245     /* In case of error : */
246     unsigned long int i_thread = 0;
247
248 #if defined( PTH_INIT_IN_PTH_H )
249     i_result = ( pth_cond_notify( &p_condvar->cond, FALSE ) == FALSE );
250
251 #elif defined( ST_INIT_IN_ST_H )
252     i_result = st_cond_signal( p_condvar->cond );
253
254 #elif defined( UNDER_CE )
255     PulseEvent( p_condvar->event );
256     i_result = 0;
257
258 #elif defined( WIN32 )
259     /* Release one waiting thread if one is available. */
260     /* For this trick to work properly, the vlc_cond_signal must be surrounded
261      * by a mutex. This will prevent another thread from stealing the signal */
262     if( !p_condvar->semaphore )
263     {
264         /*
265         ** PulseEvent() only works if none of the waiting threads is suspended.
266         ** this is particularily problematic under a debug session. 
267         ** as documented in http://support.microsoft.com/kb/q173260/
268         */
269         PulseEvent( p_condvar->event );
270     }
271     else if( p_condvar->i_win9x_cv == 1 )
272     {
273         /* Wait for the gate to be open */
274         WaitForSingleObject( p_condvar->event, INFINITE );
275
276         if( p_condvar->i_waiting_threads )
277         {
278             /* Using a semaphore exposes us to a race condition. It is
279              * possible for another thread to start waiting on the semaphore
280              * just after we signaled it and thus steal the signal.
281              * We have to prevent new threads from entering the cond_wait(). */
282             ResetEvent( p_condvar->event );
283
284             /* A semaphore is used here because Win9x doesn't have
285              * SignalObjectAndWait() and thus a race condition exists
286              * during the time we release the mutex and the time we start
287              * waiting on the event (more precisely, the signal can sometimes
288              * be missed by the waiting thread if we use PulseEvent()). */
289             ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
290         }
291     }
292     else
293     {
294         if( p_condvar->i_waiting_threads )
295         {
296             ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
297
298             /* Wait for the last thread to be awakened */
299             WaitForSingleObject( p_condvar->event, INFINITE );
300         }
301     }
302     i_result = 0;
303
304 #elif defined( HAVE_KERNEL_SCHEDULER_H )
305     if( p_condvar == NULL )
306     {
307         i_result = B_BAD_VALUE;
308     }
309     else if( p_condvar->init < 2000 )
310     {
311         i_result = B_NO_INIT;
312     }
313     else
314     {
315         while( p_condvar->thread != -1 )
316         {
317             thread_info info;
318             if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
319             {
320                 return 0;
321             }
322
323             if( info.state != B_THREAD_SUSPENDED )
324             {
325                 /* The  waiting thread is not suspended so it could
326                  * have been interrupted beetwen the unlock and the
327                  * suspend_thread line. That is why we sleep a little
328                  * before retesting p_condver->thread. */
329                 snooze( 10000 );
330             }
331             else
332             {
333                 /* Ok, we have to wake up that thread */
334                 resume_thread( p_condvar->thread );
335                 return 0;
336             }
337         }
338         i_result = 0;
339     }
340
341 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
342     i_result = pthread_cond_signal( &p_condvar->cond );
343     if ( i_result )
344     {
345         i_thread = CAST_PTHREAD_TO_INT(pthread_self());
346         errno = i_result;
347     }
348
349 #elif defined( HAVE_CTHREADS_H )
350     /* condition_signal() */
351     if ( p_condvar->queue.head || p_condvar->implications )
352     {
353         cond_signal( (condition_t)p_condvar );
354     }
355     i_result = 0;
356
357 #endif
358
359     if( i_result )
360     {
361         msg_Err( p_condvar->p_this,
362                  "thread %li: cond_signal failed at %s:%d (%d:%m)",
363                  i_thread, psz_file, i_line, i_result );
364     }
365
366     return i_result;
367 }
368
369 /*****************************************************************************
370  * vlc_cond_wait: wait until condition completion
371  *****************************************************************************/
372 #define vlc_cond_wait( P_COND, P_MUTEX )                                     \
373     __vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX  )
374
375 static inline int __vlc_cond_wait( const char * psz_file, int i_line,
376                                    vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex )
377 {
378     int i_result;
379     /* In case of error : */
380     unsigned long int i_thread = 0;
381
382 #if defined( PTH_INIT_IN_PTH_H )
383     i_result = ( pth_cond_await( &p_condvar->cond, &p_mutex->mutex, NULL )
384                  == FALSE );
385
386 #elif defined( ST_INIT_IN_ST_H )
387     st_mutex_unlock( p_mutex->mutex );
388     i_result = st_cond_wait( p_condvar->cond );
389     st_mutex_lock( p_mutex->mutex );
390
391 #elif defined( UNDER_CE )
392     p_condvar->i_waiting_threads++;
393     LeaveCriticalSection( &p_mutex->csection );
394     WaitForSingleObject( p_condvar->event, INFINITE );
395     p_condvar->i_waiting_threads--;
396
397     /* Reacquire the mutex before returning. */
398     vlc_mutex_lock( p_mutex );
399
400     i_result = 0;
401
402 #elif defined( WIN32 )
403     if( !p_condvar->semaphore )
404     {
405         /* Increase our wait count */
406         p_condvar->i_waiting_threads++;
407
408         if( p_mutex->mutex )
409         {
410             /* It is only possible to atomically release the mutex and
411              * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
412              * SignalObjectAndWait(). */
413             p_condvar->SignalObjectAndWait( p_mutex->mutex,
414                                             p_condvar->event,
415                                             INFINITE, FALSE );
416         }
417         else
418         {
419             LeaveCriticalSection( &p_mutex->csection );
420             WaitForSingleObject( p_condvar->event, INFINITE );
421         }
422
423         p_condvar->i_waiting_threads--;
424     }
425     else if( p_condvar->i_win9x_cv == 1 )
426     {
427         int i_waiting_threads;
428
429         /* Wait for the gate to be open */
430         WaitForSingleObject( p_condvar->event, INFINITE );
431
432         /* Increase our wait count */
433         p_condvar->i_waiting_threads++;
434
435         LeaveCriticalSection( &p_mutex->csection );
436         WaitForSingleObject( p_condvar->semaphore, INFINITE );
437
438         /* Decrement and test must be atomic */
439         EnterCriticalSection( &p_condvar->csection );
440
441         /* Decrease our wait count */
442         i_waiting_threads = --p_condvar->i_waiting_threads;
443
444         LeaveCriticalSection( &p_condvar->csection );
445
446         /* Reopen the gate if we were the last waiting thread */
447         if( !i_waiting_threads )
448             SetEvent( p_condvar->event );
449     }
450     else
451     {
452         int i_waiting_threads;
453
454         /* Increase our wait count */
455         p_condvar->i_waiting_threads++;
456
457         LeaveCriticalSection( &p_mutex->csection );
458         WaitForSingleObject( p_condvar->semaphore, INFINITE );
459
460         /* Decrement and test must be atomic */
461         EnterCriticalSection( &p_condvar->csection );
462
463         /* Decrease our wait count */
464         i_waiting_threads = --p_condvar->i_waiting_threads;
465
466         LeaveCriticalSection( &p_condvar->csection );
467
468         /* Signal that the last waiting thread just went through */
469         if( !i_waiting_threads )
470             SetEvent( p_condvar->event );
471     }
472
473     /* Reacquire the mutex before returning. */
474     vlc_mutex_lock( p_mutex );
475
476     i_result = 0;
477
478 #elif defined( HAVE_KERNEL_SCHEDULER_H )
479     if( p_condvar == NULL )
480     {
481         i_result = B_BAD_VALUE;
482     }
483     else if( p_mutex == NULL )
484     {
485         i_result = B_BAD_VALUE;
486     }
487     else if( p_condvar->init < 2000 )
488     {
489         i_result = B_NO_INIT;
490     }
491
492     /* The p_condvar->thread var is initialized before the unlock because
493      * it enables to identify when the thread is interrupted beetwen the
494      * unlock line and the suspend_thread line */
495     p_condvar->thread = find_thread( NULL );
496     vlc_mutex_unlock( p_mutex );
497     suspend_thread( p_condvar->thread );
498     p_condvar->thread = -1;
499
500     vlc_mutex_lock( p_mutex );
501     i_result = 0;
502
503 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
504
505 #   ifdef DEBUG
506     /* In debug mode, timeout */
507     struct timespec timeout = {
508         (mdate() / 1000000) + THREAD_COND_TIMEOUT,
509         0 /* 1Hz precision is sufficient here :-) */
510     };
511
512     i_result = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex,
513                                        &timeout );
514
515     if( i_result == ETIMEDOUT )
516     {
517         errno = ETIMEDOUT;
518         msg_Dbg( p_condvar->p_this,
519                   "thread %li: possible condition deadlock "
520                   "at %s:%d (%m)", CAST_PTHREAD_TO_INT(pthread_self()),
521                   psz_file, i_line );
522
523         i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
524     }
525
526 #   else
527     i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
528 #   endif
529
530     if ( i_result )
531     {
532         i_thread = CAST_PTHREAD_TO_INT(pthread_self());
533         errno = i_result;
534     }
535
536 #elif defined( HAVE_CTHREADS_H )
537     condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
538     i_result = 0;
539
540 #endif
541
542     if( i_result )
543     {
544         msg_Err( p_condvar->p_this,
545                  "thread %li: cond_wait failed at %s:%d (%d:%m)",
546                  i_thread, psz_file, i_line, i_result );
547     }
548
549     return i_result;
550 }
551
552
553 /*****************************************************************************
554  * vlc_cond_timedwait: wait until condition completion or expiration
555  *****************************************************************************
556  * Returns 0 if object signaled, an error code in case of timeout or error.
557  *****************************************************************************/
558 #define vlc_cond_timedwait( P_COND, P_MUTEX, DEADLINE )                      \
559     __vlc_cond_timedwait( __FILE__, __LINE__, P_COND, P_MUTEX, DEADLINE  )
560
561 static inline int __vlc_cond_timedwait( const char * psz_file, int i_line,
562                                         vlc_cond_t *p_condvar,
563                                         vlc_mutex_t *p_mutex,
564                                         mtime_t deadline )
565 {
566     int i_res;
567     unsigned long int i_thread = 0;
568
569 #if defined( PTH_INIT_IN_PTH_H )
570 #   error Unimplemented
571 #elif defined( ST_INIT_IN_ST_H )
572 #   error Unimplemented
573 #elif defined( UNDER_CE )
574     mtime_t delay_ms = (deadline - mdate())/1000;
575
576     DWORD result;
577     if( delay_ms < 0 )
578         delay_ms = 0;
579
580     p_condvar->i_waiting_threads++;
581     LeaveCriticalSection( &p_mutex->csection );
582     result = WaitForSingleObject( p_condvar->event, delay_ms );
583     p_condvar->i_waiting_threads--;
584
585     /* Reacquire the mutex before returning. */
586     vlc_mutex_lock( p_mutex );
587
588     i_res = (int)result;
589
590 #elif defined( WIN32 )
591     DWORD result;
592
593     mtime_t delay_ms = (deadline - mdate())/1000;
594     if( delay_ms < 0 )
595         delay_ms = 0;
596
597     if( !p_condvar->semaphore )
598     {
599         /* Increase our wait count */
600         p_condvar->i_waiting_threads++;
601
602         if( p_mutex->mutex )
603         {
604             /* It is only possible to atomically release the mutex and
605              * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
606              * SignalObjectAndWait(). */
607             result = p_condvar->SignalObjectAndWait( p_mutex->mutex,
608                                             p_condvar->event,
609                                             delay_ms, FALSE );
610         }
611         else
612         {
613             LeaveCriticalSection( &p_mutex->csection );
614             result = WaitForSingleObject( p_condvar->event, delay_ms );
615         }
616
617         p_condvar->i_waiting_threads--;
618     }
619     else if( p_condvar->i_win9x_cv == 1 )
620     {
621         int i_waiting_threads;
622
623         /* Wait for the gate to be open */
624         result = WaitForSingleObject( p_condvar->event, delay_ms );
625
626         /* Increase our wait count */
627         p_condvar->i_waiting_threads++;
628
629         LeaveCriticalSection( &p_mutex->csection );
630         if( !result )
631         {
632             /* recaculate remaining delay */
633             delay_ms = (deadline - mdate())/1000;
634             if( delay_ms < 0 )
635                 delay_ms = 0;
636
637             result = WaitForSingleObject( p_condvar->semaphore, delay_ms );
638         }
639
640         /* Decrement and test must be atomic */
641         EnterCriticalSection( &p_condvar->csection );
642
643         /* Decrease our wait count */
644         i_waiting_threads = --p_condvar->i_waiting_threads;
645
646         LeaveCriticalSection( &p_condvar->csection );
647
648         /* Reopen the gate if we were the last waiting thread */
649         if( !i_waiting_threads )
650             SetEvent( p_condvar->event );
651     }
652     else
653     {
654         int i_waiting_threads;
655
656         /* Increase our wait count */
657         p_condvar->i_waiting_threads++;
658
659         LeaveCriticalSection( &p_mutex->csection );
660         result = WaitForSingleObject( p_condvar->semaphore, delay_ms );
661
662         /* Decrement and test must be atomic */
663         EnterCriticalSection( &p_condvar->csection );
664
665         /* Decrease our wait count */
666         i_waiting_threads = --p_condvar->i_waiting_threads;
667
668         LeaveCriticalSection( &p_condvar->csection );
669
670         /* Signal that the last waiting thread just went through */
671         if( !i_waiting_threads )
672             SetEvent( p_condvar->event );
673     }
674
675     /* Reacquire the mutex before returning. */
676     vlc_mutex_lock( p_mutex );
677
678     i_res = (int)result;
679
680 #elif defined( HAVE_KERNEL_SCHEDULER_H )
681 #   error Unimplemented
682 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
683     lldiv_t d = lldiv( deadline, 1000000 );
684     struct timespec ts = { d.quot, d.rem * 1000 };
685
686     i_res = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex, &ts );
687     if( i_res == ETIMEDOUT )
688         return ETIMEDOUT; /* this error is perfectly normal */
689     else
690     if ( i_res ) /* other errors = bug */
691     {
692         i_thread = CAST_PTHREAD_TO_INT(pthread_self());
693         errno = i_res;
694     }
695
696 #elif defined( HAVE_CTHREADS_H )
697 #   error Unimplemented
698 #endif
699
700     if( i_res )
701     {
702         msg_Err( p_condvar->p_this,
703                  "thread %li: cond_wait failed at %s:%d (%d:%m)",
704                  i_thread, psz_file, i_line, i_res );
705     }
706
707     return i_res;
708 }
709
710 /*****************************************************************************
711  * vlc_cond_destroy: destroy a condition
712  *****************************************************************************/
713 #define vlc_cond_destroy( P_COND )                                          \
714     __vlc_cond_destroy( __FILE__, __LINE__, P_COND )
715
716 /*****************************************************************************
717  * vlc_threadvar_create: create a thread-local variable
718  *****************************************************************************/
719 #define vlc_threadvar_create( PTHIS, P_TLS )                                 \
720    __vlc_threadvar_create( PTHIS, P_TLS )
721
722 /*****************************************************************************
723  * vlc_threadvar_set: create: set the value of a thread-local variable
724  *****************************************************************************/
725 static inline int vlc_threadvar_set( vlc_threadvar_t * p_tls, void *p_value )
726 {
727     int i_ret;
728
729 #if defined( PTH_INIT_IN_PTH_H )
730     return pth_key_setdata( p_tls->handle, p_value );
731 #elif  defined( ST_INIT_IN_ST_H )
732     return st_thread_setspecific( p_tls->handle, p_value );
733 #elif defined( HAVE_KERNEL_SCHEDULER_H )
734     return -1;
735
736 #elif defined( UNDER_CE ) || defined( WIN32 )
737     i_ret = ( TlsSetValue( p_tls->handle, p_value ) != 0 );
738
739 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
740     i_ret = pthread_setspecific( p_tls->handle, p_value );
741
742 #elif defined( HAVE_CTHREADS_H )
743     i_ret = cthread_setspecific( p_tls->handle, p_value );
744 #endif
745
746     return i_ret;
747 }
748
749 /*****************************************************************************
750  * vlc_threadvar_get: create: get the value of a thread-local variable
751  *****************************************************************************/
752 static inline void* vlc_threadvar_get( vlc_threadvar_t * p_tls )
753 {
754     void* p_ret;
755
756 #if defined( PTH_INIT_IN_PTH_H )
757     p_ret = pth_key_getdata( p_handle->key );
758 #elif defined( ST_INIT_IN_ST_H )
759     p_ret = st_thread_getspecific( p_handle->key );
760 #elif defined( HAVE_KERNEL_SCHEDULER_H )
761     p_ret = NULL;
762 #elif defined( UNDER_CE ) || defined( WIN32 )
763     p_ret = TlsGetValue( p_tls->handle );
764
765 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
766     p_ret = pthread_getspecific( p_tls->handle );
767
768 #elif defined( HAVE_CTHREADS_H )
769     if ( !cthread_getspecific( p_tls->handle, &p_ret ) )
770     {
771         p_ret = NULL;
772     }
773 #endif
774
775     return p_ret;
776 }
777
778 /*****************************************************************************
779  * vlc_thread_create: create a thread
780  *****************************************************************************/
781 #define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY, WAIT )         \
782     __vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, (void * ( * ) ( void * ))FUNC, PRIORITY, WAIT )
783
784 /*****************************************************************************
785  * vlc_thread_set_priority: set the priority of the calling thread
786  *****************************************************************************/
787 #define vlc_thread_set_priority( P_THIS, PRIORITY )                         \
788     __vlc_thread_set_priority( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PRIORITY )
789
790 /*****************************************************************************
791  * vlc_thread_ready: tell the parent thread we were successfully spawned
792  *****************************************************************************/
793 #define vlc_thread_ready( P_THIS )                                          \
794     __vlc_thread_ready( VLC_OBJECT(P_THIS) )
795
796 /*****************************************************************************
797  * vlc_thread_join: wait until a thread exits
798  *****************************************************************************/
799 #define vlc_thread_join( P_THIS )                                           \
800     __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )
801
802 #endif