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