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