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