]> git.sesse.net Git - vlc/blob - include/vlc_threads_funcs.h
696b39f758c1c5775ea64c9c1e053d28d52d6b80
[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 #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 #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( PTHREAD_COND_T_IN_PTHREAD_H )
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( PTHREAD_COND_T_IN_PTHREAD_H )
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( PTHREAD_COND_T_IN_PTHREAD_H )
482
483 #   ifdef DEBUG
484     /* In debug mode, timeout */
485     struct timespec timeout = {
486         (mdate() / 1000000) + THREAD_COND_TIMEOUT,
487         0 /* 1Hz precision is sufficient here :-) */
488     };
489
490     i_result = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex,
491                                        &timeout );
492
493     if( i_result == ETIMEDOUT )
494     {
495         errno = ETIMEDOUT;
496         msg_Dbg( p_condvar->p_this,
497                   "thread %li: possible condition deadlock "
498                   "at %s:%d (%m)", CAST_PTHREAD_TO_INT(pthread_self()),
499                   psz_file, i_line );
500
501         i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
502     }
503
504 #   else
505     i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
506 #   endif
507
508     if ( i_result )
509     {
510         i_thread = CAST_PTHREAD_TO_INT(pthread_self());
511         errno = i_result;
512     }
513
514 #endif
515
516     if( i_result )
517     {
518         msg_Err( p_condvar->p_this,
519                  "thread %li: cond_wait failed at %s:%d (%d:%m)",
520                  i_thread, psz_file, i_line, i_result );
521         vlc_threads_error( p_condvar->p_this );
522     }
523
524     return i_result;
525 }
526
527
528 /*****************************************************************************
529  * vlc_cond_timedwait: wait until condition completion or expiration
530  *****************************************************************************
531  * Returns 0 if object signaled, an error code in case of timeout or error.
532  *****************************************************************************/
533 #define vlc_cond_timedwait( P_COND, P_MUTEX, DEADLINE )                      \
534     __vlc_cond_timedwait( __FILE__, __LINE__, P_COND, P_MUTEX, DEADLINE  )
535
536 static inline int __vlc_cond_timedwait( const char * psz_file, int i_line,
537                                         vlc_cond_t *p_condvar,
538                                         vlc_mutex_t *p_mutex,
539                                         mtime_t deadline )
540 {
541     int i_res;
542     unsigned long int i_thread = 0;
543
544 #if defined( UNDER_CE )
545     mtime_t delay_ms = (deadline - mdate())/1000;
546
547     DWORD result;
548     if( delay_ms < 0 )
549         delay_ms = 0;
550
551     p_condvar->i_waiting_threads++;
552     LeaveCriticalSection( &p_mutex->csection );
553     result = WaitForSingleObject( p_condvar->event, delay_ms );
554     p_condvar->i_waiting_threads--;
555
556     /* Reacquire the mutex before returning. */
557     vlc_mutex_lock( p_mutex );
558
559     i_res = (int)result;
560     if(result == WAIT_TIMEOUT)
561        return WAIT_TIMEOUT; /* this error is perfectly normal */
562
563 #elif defined( WIN32 )
564     DWORD result;
565
566     mtime_t delay_ms = (deadline - mdate())/1000;
567     if( delay_ms < 0 )
568         delay_ms = 0;
569
570     if( !p_condvar->semaphore )
571     {
572         /* Increase our wait count */
573         p_condvar->i_waiting_threads++;
574
575         if( p_mutex->mutex )
576         {
577             /* It is only possible to atomically release the mutex and
578              * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
579              * SignalObjectAndWait(). */
580             result = p_condvar->SignalObjectAndWait( p_mutex->mutex,
581                                             p_condvar->event,
582                                             delay_ms, FALSE );
583         }
584         else
585         {
586             LeaveCriticalSection( &p_mutex->csection );
587             result = WaitForSingleObject( p_condvar->event, delay_ms );
588         }
589
590         p_condvar->i_waiting_threads--;
591     }
592     else if( p_condvar->i_win9x_cv == 1 )
593     {
594         int i_waiting_threads;
595
596         /* Wait for the gate to be open */
597         result = WaitForSingleObject( p_condvar->event, delay_ms );
598
599         /* Increase our wait count */
600         p_condvar->i_waiting_threads++;
601
602         LeaveCriticalSection( &p_mutex->csection );
603         if( !result )
604         {
605             /* recaculate remaining delay */
606             delay_ms = (deadline - mdate())/1000;
607             if( delay_ms < 0 )
608                 delay_ms = 0;
609
610             result = WaitForSingleObject( p_condvar->semaphore, delay_ms );
611         }
612
613         /* Decrement and test must be atomic */
614         EnterCriticalSection( &p_condvar->csection );
615
616         /* Decrease our wait count */
617         i_waiting_threads = --p_condvar->i_waiting_threads;
618
619         LeaveCriticalSection( &p_condvar->csection );
620
621         /* Reopen the gate if we were the last waiting thread */
622         if( !i_waiting_threads )
623             SetEvent( p_condvar->event );
624     }
625     else
626     {
627         int i_waiting_threads;
628
629         /* Increase our wait count */
630         p_condvar->i_waiting_threads++;
631
632         LeaveCriticalSection( &p_mutex->csection );
633         result = WaitForSingleObject( p_condvar->semaphore, delay_ms );
634
635         /* Decrement and test must be atomic */
636         EnterCriticalSection( &p_condvar->csection );
637
638         /* Decrease our wait count */
639         i_waiting_threads = --p_condvar->i_waiting_threads;
640
641         LeaveCriticalSection( &p_condvar->csection );
642
643         /* Signal that the last waiting thread just went through */
644         if( !i_waiting_threads )
645             SetEvent( p_condvar->event );
646     }
647
648     /* Reacquire the mutex before returning. */
649     vlc_mutex_lock( p_mutex );
650     if(result == WAIT_TIMEOUT)
651        return WAIT_TIMEOUT; /* this error is perfectly normal */
652
653     i_res = (int)result;
654
655 #elif defined( HAVE_KERNEL_SCHEDULER_H )
656 #   error Unimplemented
657 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
658     lldiv_t d = lldiv( deadline, 1000000 );
659     struct timespec ts = { d.quot, d.rem * 1000 };
660
661     i_res = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex, &ts );
662     if( i_res == ETIMEDOUT )
663         return ETIMEDOUT; /* this error is perfectly normal */
664     else
665     if ( i_res ) /* other errors = bug */
666     {
667         i_thread = CAST_PTHREAD_TO_INT(pthread_self());
668         errno = i_res;
669     }
670
671 #endif
672
673     if( i_res )
674     {
675         msg_Err( p_condvar->p_this,
676                  "thread %li: cond_wait failed at %s:%d (%d:%m)",
677                  i_thread, psz_file, i_line, i_res );
678         vlc_threads_error( p_condvar->p_this );
679     }
680
681     return i_res;
682 }
683
684 /*****************************************************************************
685  * vlc_cond_destroy: destroy a condition
686  *****************************************************************************/
687 #define vlc_cond_destroy( P_COND )                                          \
688     __vlc_cond_destroy( __FILE__, __LINE__, P_COND )
689
690 /*****************************************************************************
691  * vlc_threadvar_create: create a thread-local variable
692  *****************************************************************************/
693 #define vlc_threadvar_create( PTHIS, P_TLS )                                 \
694    __vlc_threadvar_create( PTHIS, P_TLS )
695
696 /*****************************************************************************
697  * vlc_threadvar_set: create: set the value of a thread-local variable
698  *****************************************************************************/
699 static inline int vlc_threadvar_set( vlc_threadvar_t * p_tls, void *p_value )
700 {
701     int i_ret;
702
703 #if defined( HAVE_KERNEL_SCHEDULER_H )
704     return -1;
705
706 #elif defined( UNDER_CE ) || defined( WIN32 )
707     i_ret = ( TlsSetValue( p_tls->handle, p_value ) != 0 );
708
709 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
710     i_ret = pthread_setspecific( p_tls->handle, p_value );
711
712 #endif
713
714     return i_ret;
715 }
716
717 /*****************************************************************************
718  * vlc_threadvar_get: create: get the value of a thread-local variable
719  *****************************************************************************/
720 static inline void* vlc_threadvar_get( vlc_threadvar_t * p_tls )
721 {
722     void* p_ret;
723
724 #if defined( HAVE_KERNEL_SCHEDULER_H )
725     p_ret = NULL;
726 #elif defined( UNDER_CE ) || defined( WIN32 )
727     p_ret = TlsGetValue( p_tls->handle );
728
729 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
730     p_ret = pthread_getspecific( p_tls->handle );
731
732 #endif
733
734     return p_ret;
735 }
736
737 # if defined (_POSIX_SPIN_LOCKS) && ((_POSIX_SPIN_LOCKS - 0) > 0)
738 typedef struct
739 {
740     pthread_spinlock_t  spin;
741 } vlc_spinlock_t;
742
743 /**
744  * Initializes a spinlock.
745  */
746 static inline int vlc_spin_init (vlc_spinlock_t *spin)
747 {
748     return pthread_spin_init (&spin->spin, PTHREAD_PROCESS_PRIVATE);
749 }
750
751 /**
752  * Acquires a spinlock.
753  */
754 static inline int vlc_spin_lock (vlc_spinlock_t *spin)
755 {
756     return pthread_spin_lock (&spin->spin);
757 }
758
759 /**
760  * Releases a spinlock.
761  */
762 static inline int vlc_spin_unlock (vlc_spinlock_t *spin)
763 {
764     return pthread_spin_unlock (&spin->spin);
765 }
766
767 /**
768  * Deinitializes a spinlock.
769  */
770 static inline int vlc_spin_destroy (vlc_spinlock_t *spin)
771 {
772     return pthread_spin_destroy (&spin->spin);
773 }
774
775 #elif defined( WIN32 )
776
777 typedef CRITICAL_SECTION vlc_spinlock_t;
778
779 /**
780  * Initializes a spinlock.
781  */
782 static inline int vlc_spin_init (vlc_spinlock_t *spin)
783 {
784     return !InitializeCriticalSectionAndSpinCount(spin, 4000);
785 }
786
787 /**
788  * Acquires a spinlock.
789  */
790 static inline int vlc_spin_lock (vlc_spinlock_t *spin)
791 {
792     EnterCriticalSection(spin);
793     return 0;
794 }
795
796 /**
797  * Releases a spinlock.
798  */
799 static inline int vlc_spin_unlock (vlc_spinlock_t *spin)
800 {
801     LeaveCriticalSection(spin);
802     return 0;
803 }
804
805 /**
806  * Deinitializes a spinlock.
807  */
808 static inline int vlc_spin_destroy (vlc_spinlock_t *spin)
809 {
810     DeleteCriticalSection(spin);
811     return 0;
812 }
813
814
815 #else
816
817
818 /* Fallback to plain mutexes if spinlocks are not available */
819 typedef vlc_mutex_t vlc_spinlock_t;
820
821 static inline int vlc_spin_init (vlc_spinlock_t *spin)
822 {
823     return __vlc_mutex_init (NULL, spin);
824 }
825
826 # define vlc_spin_lock    vlc_mutex_lock
827 # define vlc_spin_unlock  vlc_mutex_unlock
828 # define vlc_spin_destroy vlc_mutex_destroy
829 #endif
830
831 /*****************************************************************************
832  * vlc_thread_create: create a thread
833  *****************************************************************************/
834 #define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY, WAIT )         \
835     __vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, (void * ( * ) ( void * ))FUNC, PRIORITY, WAIT )
836
837 /*****************************************************************************
838  * vlc_thread_set_priority: set the priority of the calling thread
839  *****************************************************************************/
840 #define vlc_thread_set_priority( P_THIS, PRIORITY )                         \
841     __vlc_thread_set_priority( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PRIORITY )
842
843 /*****************************************************************************
844  * vlc_thread_ready: tell the parent thread we were successfully spawned
845  *****************************************************************************/
846 #define vlc_thread_ready( P_THIS )                                          \
847     __vlc_thread_ready( VLC_OBJECT(P_THIS) )
848
849 /*****************************************************************************
850  * vlc_thread_join: wait until a thread exits
851  *****************************************************************************/
852 #define vlc_thread_join( P_THIS )                                           \
853     __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )
854
855 #endif