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