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