]> git.sesse.net Git - vlc/blob - include/vlc_threads_funcs.h
* ./bootstrap : Fixed an issue with old shell versions
[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, 2002 VideoLAN
6  * $Id: vlc_threads_funcs.h,v 1.1 2002/08/29 23:53:22 massiot Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Function definitions
30  *****************************************************************************/
31 VLC_EXPORT( int,  __vlc_threads_init,  ( vlc_object_t * ) );
32 VLC_EXPORT( int,  __vlc_threads_end,   ( vlc_object_t * ) );
33 VLC_EXPORT( int,  __vlc_mutex_init,    ( vlc_object_t *, vlc_mutex_t * ) );
34 VLC_EXPORT( int,  __vlc_mutex_destroy, ( char *, int, vlc_mutex_t * ) );
35 VLC_EXPORT( int,  __vlc_cond_init,     ( vlc_object_t *, vlc_cond_t * ) );
36 VLC_EXPORT( int,  __vlc_cond_destroy,  ( char *, int, vlc_cond_t * ) );
37 VLC_EXPORT( int,  __vlc_thread_create, ( vlc_object_t *, char *, int, char *, void * ( * ) ( void * ), int, vlc_bool_t ) );
38 VLC_EXPORT( void, __vlc_thread_ready,  ( vlc_object_t * ) );
39 VLC_EXPORT( void, __vlc_thread_join,   ( vlc_object_t *, char *, int ) );
40
41 /*****************************************************************************
42  * vlc_threads_init: initialize threads system
43  *****************************************************************************/
44 #define vlc_threads_init( P_THIS )                                          \
45     __vlc_threads_init( VLC_OBJECT(P_THIS) )
46
47 /*****************************************************************************
48  * vlc_threads_end: deinitialize threads system
49  *****************************************************************************/
50 #define vlc_threads_end( P_THIS )                                           \
51     __vlc_threads_end( VLC_OBJECT(P_THIS) )
52
53 /*****************************************************************************
54  * vlc_mutex_init: initialize a mutex
55  *****************************************************************************/
56 #define vlc_mutex_init( P_THIS, P_MUTEX )                                   \
57     __vlc_mutex_init( VLC_OBJECT(P_THIS), P_MUTEX )
58
59 /*****************************************************************************
60  * vlc_mutex_lock: lock a mutex
61  *****************************************************************************/
62 #define vlc_mutex_lock( P_MUTEX )                                           \
63     __vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
64
65 static inline int __vlc_mutex_lock( char * psz_file, int i_line,
66                                     vlc_mutex_t * p_mutex )
67 {
68     int i_result;
69     /* In case of error : */
70     int i_thread = -1;
71     const char * psz_error = "";
72
73 #if defined( PTH_INIT_IN_PTH_H )
74     i_result = pth_mutex_acquire( &p_mutex->mutex, TRUE, NULL );
75
76 #elif defined( ST_INIT_IN_ST_H )
77     i_result = st_mutex_lock( *p_mutex->mutex );
78
79 #elif defined( WIN32 )
80     if( p_mutex->mutex )
81     {
82         WaitForSingleObject( p_mutex->mutex, INFINITE );
83     }
84     else
85     {
86         EnterCriticalSection( &p_mutex->csection );
87     }
88     return 0;
89
90 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
91     i_result = pthread_mutex_lock( &p_mutex->mutex );
92     if ( i_result )
93     {
94         i_thread = (int)pthread_self();
95         psz_error = strerror(i_result);
96     }
97
98 #elif defined( HAVE_CTHREADS_H )
99     mutex_lock( p_mutex->mutex );
100     return 0;
101
102 #elif defined( HAVE_KERNEL_SCHEDULER_H )
103     if( p_mutex == NULL )
104     {
105         i_result = B_BAD_VALUE;
106     }
107     else if( p_mutex->init < 2000 )
108     {
109         i_result = B_NO_INIT;
110     }
111     else
112     {
113         i_result = acquire_sem( p_mutex->lock );
114     }
115 #endif
116
117     if( i_result )
118     {
119         msg_Err( p_mutex->p_this,
120                  "thread %d: mutex_lock failed at %s:%d (%d:%s)",
121                  i_thread, psz_file, i_line, i_result, psz_error );
122     }
123     return i_result;
124 }
125
126 /*****************************************************************************
127  * vlc_mutex_unlock: unlock a mutex
128  *****************************************************************************/
129 #define vlc_mutex_unlock( P_MUTEX )                                         \
130     __vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
131
132 static inline int __vlc_mutex_unlock( char * psz_file, int i_line,
133                                       vlc_mutex_t *p_mutex )
134 {
135     int i_result;
136     /* In case of error : */
137     int i_thread = -1;
138     const char * psz_error = "";
139
140 #if defined( PTH_INIT_IN_PTH_H )
141     i_result = pth_mutex_release( &p_mutex->mutex );
142
143 #elif defined( ST_INIT_IN_ST_H )
144     i_result = st_mutex_unlock( *p_mutex->mutex );
145
146 #elif defined( WIN32 )
147     if( p_mutex->mutex )
148     {
149         ReleaseMutex( p_mutex->mutex );
150     }
151     else
152     {
153         LeaveCriticalSection( &p_mutex->csection );
154     }
155     return 0;
156
157 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
158     i_result = pthread_mutex_unlock( &p_mutex->mutex );
159     if ( i_result )
160     {
161         i_thread = (int)pthread_self();
162         psz_error = strerror(i_result);
163     }
164
165 #elif defined( HAVE_CTHREADS_H )
166     mutex_unlock( p_mutex );
167     return 0;
168
169 #elif defined( HAVE_KERNEL_SCHEDULER_H )
170     if( p_mutex == NULL )
171     {
172         i_result = B_BAD_VALUE;
173     }
174     else if( p_mutex->init < 2000 )
175     {
176         i_result = B_NO_INIT;
177     }
178     else
179     {
180         release_sem( p_mutex->lock );
181         return B_OK;
182     }
183 #endif
184
185     if( i_result )
186     {
187         msg_Err( p_mutex->p_this,
188                  "thread %d: mutex_unlock failed at %s:%d (%d:%s)",
189                  i_thread, psz_file, i_line, i_result, psz_error );
190     }
191
192     return i_result;
193 }
194
195 /*****************************************************************************
196  * vlc_mutex_destroy: destroy a mutex
197  *****************************************************************************/
198 #define vlc_mutex_destroy( P_MUTEX )                                        \
199     __vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
200
201 /*****************************************************************************
202  * vlc_cond_init: initialize a condition
203  *****************************************************************************/
204 #define vlc_cond_init( P_THIS, P_COND )                                     \
205     __vlc_cond_init( VLC_OBJECT(P_THIS), P_COND )
206
207 /*****************************************************************************
208  * vlc_cond_signal: start a thread on condition completion
209  *****************************************************************************/
210 #define vlc_cond_signal( P_COND )                                           \
211     __vlc_cond_signal( __FILE__, __LINE__, P_COND )
212
213 static inline int __vlc_cond_signal( char * psz_file, int i_line,
214                                      vlc_cond_t *p_condvar )
215 {
216     int i_result;
217     /* In case of error : */
218     int i_thread = -1;
219     const char * psz_error = "";
220
221 #if defined( PTH_INIT_IN_PTH_H )
222     i_result = pth_cond_notify( &p_condvar->cond, FALSE );
223
224 #elif defined( ST_INIT_IN_ST_H )
225     i_result = st_cond_signal( *p_condvar->cond );
226
227 #elif defined( WIN32 )
228     /* Release one waiting thread if one is available. */
229     /* For this trick to work properly, the vlc_cond_signal must be surrounded
230      * by a mutex. This will prevent another thread from stealing the signal */
231     if( !p_condvar->semaphore )
232     {
233         PulseEvent( p_condvar->event );
234     }
235     else if( p_condvar->i_win9x_cv == 1 )
236     {
237         /* Wait for the gate to be open */
238         WaitForSingleObject( p_condvar->event, INFINITE );
239
240         if( p_condvar->i_waiting_threads )
241         {
242             /* Using a semaphore exposes us to a race condition. It is
243              * possible for another thread to start waiting on the semaphore
244              * just after we signaled it and thus steal the signal.
245              * We have to prevent new threads from entering the cond_wait(). */
246             ResetEvent( p_condvar->event );
247
248             /* A semaphore is used here because Win9x doesn't have
249              * SignalObjectAndWait() and thus a race condition exists
250              * during the time we release the mutex and the time we start
251              * waiting on the event (more precisely, the signal can sometimes
252              * be missed by the waiting thread if we use PulseEvent()). */
253             ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
254         }
255     }
256     else
257     {
258         if( p_condvar->i_waiting_threads )
259         {
260             ReleaseSemaphore( p_condvar->semaphore, 1, 0 );
261
262             /* Wait for the last thread to be awakened */
263             WaitForSingleObject( p_condvar->event, INFINITE );
264         }
265     }
266     return 0;
267
268 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
269     i_result = pthread_cond_signal( &p_condvar->cond );
270     if ( i_result )
271     {
272         i_thread = (int)pthread_self();
273         psz_error = strerror(i_result);
274     }
275
276 #elif defined( HAVE_CTHREADS_H )
277     /* condition_signal() */
278     if ( p_condvar->queue.head || p_condvar->implications )
279     {
280         cond_signal( (condition_t)p_condvar );
281     }
282     return 0;
283
284 #elif defined( HAVE_KERNEL_SCHEDULER_H )
285     if( p_condvar == NULL )
286     {
287         i_result = B_BAD_VALUE;
288     }
289     else if( p_condvar->init < 2000 )
290     {
291         i_result = B_NO_INIT;
292     }
293     else
294     {
295         while( p_condvar->thread != -1 )
296         {
297             thread_info info;
298             if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
299             {
300                 return 0;
301             }
302
303             if( info.state != B_THREAD_SUSPENDED )
304             {
305                 /* The  waiting thread is not suspended so it could
306                  * have been interrupted beetwen the unlock and the
307                  * suspend_thread line. That is why we sleep a little
308                  * before retesting p_condver->thread. */
309                 snooze( 10000 );
310             }
311             else
312             {
313                 /* Ok, we have to wake up that thread */
314                 resume_thread( p_condvar->thread );
315                 return 0;
316             }
317         }
318     }
319 #endif
320
321     if( i_result )
322     {
323         msg_Err( p_condvar->p_this,
324                  "thread %d: cond_signal failed at %s:%d (%d:%s)",
325                  i_thread, psz_file, i_line, i_result, psz_error );
326     }
327
328     return i_result;
329 }
330
331 /*****************************************************************************
332  * vlc_cond_broadcast: start all threads waiting on condition completion
333  *****************************************************************************/
334 /*
335  * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
336  * Only works with pthreads, st, win32
337  * You need to adapt it for others
338  * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
339  */
340 #define vlc_cond_broadcast( P_COND )                                        \
341     __vlc_cond_broadcast( __FILE__, __LINE__, P_COND )
342
343 static inline int __vlc_cond_broadcast( char * psz_file, int i_line,
344                                         vlc_cond_t *p_condvar )
345 {
346     int i_result;
347     /* In case of error : */
348     int i_thread = -1;
349     const char * psz_error = "";
350
351 #if defined( PTH_INIT_IN_PTH_H )
352     i_result = pth_cond_notify( &p_condvar->cond, FALSE );
353
354 #elif defined( ST_INIT_IN_ST_H )
355     i_result = st_cond_broadcast( *p_condvar->cond );
356
357 #elif defined( WIN32 )
358     /* Release all waiting threads. */
359     if( !p_condvar->semaphore )
360     {
361         for( i = p_condvar->i_waiting_threads; i > 0; i-- )
362         {
363             PulseEvent( p_condvar->event );
364         }
365     }
366     else if( p_condvar->i_win9x_cv == 1 )
367     {
368         /* Wait for the gate to be open */
369         WaitForSingleObject( p_condvar->event, INFINITE );
370
371         if( p_condvar->i_waiting_threads )
372         {
373             /* Using a semaphore exposes us to a race condition. It is
374              * possible for another thread to start waiting on the semaphore
375              * just after we signaled it and thus steal the signal.
376              * We have to prevent new threads from entering the cond_wait(). */
377             ResetEvent( p_condvar->event );
378
379             /* A semaphore is used here because Win9x doesn't have
380              * SignalObjectAndWait() and thus a race condition exists
381              * during the time we release the mutex and the time we start
382              * waiting on the event (more precisely, the signal can sometimes
383              * be missed by the waiting thread if we use PulseEvent()). */
384             ReleaseSemaphore( p_condvar->semaphore,
385                               p_condvar->i_waiting_threads, 0 );
386         }
387     }
388     else
389     {
390         if( p_condvar->i_waiting_threads )
391         {
392             ReleaseSemaphore( p_condvar->semaphore,
393                               p_condvar->i_waiting_threads, 0 );
394
395             /* Wait for the last thread to be awakened */
396             WaitForSingleObject( p_condvar->event, INFINITE );
397         }
398     }
399     return 0;
400
401 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
402     i_result = pthread_cond_broadcast( &p_condvar->cond );
403     if ( i_result )
404     {
405         i_thread = (int)pthread_self();
406         psz_error = strerror(i_result);
407     }
408
409 #elif defined( HAVE_CTHREADS_H )
410     /* condition_signal() */
411     if ( p_condvar->queue.head || p_condvar->implications )
412     {
413         cond_signal( (condition_t)p_condvar );
414     }
415     return 0;
416
417 #elif defined( HAVE_KERNEL_SCHEDULER_H )
418     if( p_condvar == NULL )
419     {
420         i_result = B_BAD_VALUE;
421     }
422     else if( p_condvar->init < 2000 )
423     {
424         i_result = B_NO_INIT;
425     }
426     else
427     {
428         while( p_condvar->thread != -1 )
429         {
430             thread_info info;
431             if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
432             {
433                 return 0;
434             }
435
436             if( info.state != B_THREAD_SUSPENDED )
437             {
438                 /* The  waiting thread is not suspended so it could
439                  * have been interrupted beetwen the unlock and the
440                  * suspend_thread line. That is why we sleep a little
441                  * before retesting p_condver->thread. */
442                 snooze( 10000 );
443             }
444             else
445             {
446                 /* Ok, we have to wake up that thread */
447                 resume_thread( p_condvar->thread );
448                 return 0;
449             }
450         }
451     }
452 #endif
453
454     if( i_result )
455     {
456         msg_Err( p_condvar->p_this,
457                  "thread %d: cond_broadcast failed at %s:%d (%d:%s)",
458                  i_thread, psz_file, i_line, i_result, psz_error );
459     }
460
461     return i_result;
462 }
463
464 /*****************************************************************************
465  * vlc_cond_wait: wait until condition completion
466  *****************************************************************************/
467 #define vlc_cond_wait( P_COND, P_MUTEX )                                     \
468     __vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX  )
469
470 static inline int __vlc_cond_wait( char * psz_file, int i_line,
471                                    vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex )
472 {
473     int i_result;
474     /* In case of error : */
475     int i_thread = -1;
476     const char * psz_error = "";
477
478 #if defined( PTH_INIT_IN_PTH_H )
479     i_result = pth_cond_await( &p_condvar->cond, &p_mutex->mutex, NULL );
480
481 #elif defined( ST_INIT_IN_ST_H )
482     st_mutex_unlock( *p_mutex->mutex );
483     i_result = st_cond_wait( *p_condvar->cond );
484     st_mutex_lock( *p_mutex->mutex );
485
486 #elif defined( WIN32 )
487     if( !p_condvar->semaphore )
488     {
489         /* Increase our wait count */
490         p_condvar->i_waiting_threads++;
491
492         if( p_condvar->SignalObjectAndWait && p_mutex->mutex )
493         {
494             /* It is only possible to atomically release the mutex and
495              * initiate the waiting on WinNT/2K/XP. Win9x doesn't have
496              * SignalObjectAndWait(). */
497             p_condvar->SignalObjectAndWait( p_mutex->mutex,
498                                             p_condvar->event,
499                                             INFINITE, FALSE );
500         }
501         else
502         {
503             LeaveCriticalSection( &p_mutex->csection );
504             WaitForSingleObject( p_condvar->event, INFINITE );
505         }
506
507         p_condvar->i_waiting_threads--;
508     }
509     else if( p_condvar->i_win9x_cv == 1 )
510     {
511         int i_waiting_threads;
512
513         /* Wait for the gate to be open */
514         WaitForSingleObject( p_condvar->event, INFINITE );
515
516         /* Increase our wait count */
517         p_condvar->i_waiting_threads++;
518
519         LeaveCriticalSection( &p_mutex->csection );
520         WaitForSingleObject( p_condvar->semaphore, INFINITE );
521
522         /* Decrement and test must be atomic */
523         EnterCriticalSection( &p_condvar->csection );
524
525         /* Decrease our wait count */
526         i_waiting_threads = --p_condvar->i_waiting_threads;
527
528         LeaveCriticalSection( &p_condvar->csection );
529
530         /* Reopen the gate if we were the last waiting thread */
531         if( !i_waiting_threads )
532             SetEvent( p_condvar->event );
533     }
534     else
535     {
536         int i_waiting_threads;
537
538         /* Increase our wait count */
539         p_condvar->i_waiting_threads++;
540
541         LeaveCriticalSection( &p_mutex->csection );
542         WaitForSingleObject( p_condvar->semaphore, INFINITE );
543
544         /* Decrement and test must be atomic */
545         EnterCriticalSection( &p_condvar->csection );
546
547         /* Decrease our wait count */
548         i_waiting_threads = --p_condvar->i_waiting_threads;
549
550         LeaveCriticalSection( &p_condvar->csection );
551
552         /* Signal that the last waiting thread just went through */
553         if( !i_waiting_threads )
554             SetEvent( p_condvar->event );
555     }
556
557     /* Reacquire the mutex before returning. */
558     vlc_mutex_lock( p_mutex );
559
560     return 0;
561
562 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
563
564 #   ifdef DEBUG
565     /* In debug mode, timeout */
566     struct timeval now;
567     struct timespec timeout;
568
569     for( ; ; )
570     {
571         gettimeofday( &now, NULL );
572         timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT;
573         timeout.tv_nsec = now.tv_usec * 1000;
574
575         i_result = pthread_cond_timedwait( &p_condvar->cond, &p_mutex->mutex,
576                                            &timeout );
577
578         if( i_result == ETIMEDOUT )
579         {
580             msg_Warn( p_condvar->p_this,
581                       "thread %d: possible deadlock detected "
582                       "in cond_wait at %s:%d (%s)", pthread_self(),
583                       psz_file, i_line, strerror(i_result) );
584         }
585         else break;
586     }
587 #   else
588     i_result = pthread_cond_wait( &p_condvar->cond, &p_mutex->mutex );
589 #   endif
590
591     if ( i_result )
592     {
593         i_thread = (int)pthread_self();
594         psz_error = strerror(i_result);
595     }
596
597 #elif defined( HAVE_CTHREADS_H )
598     condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
599     return 0;
600
601 #elif defined( HAVE_KERNEL_SCHEDULER_H )
602     if( p_condvar == NULL )
603     {
604         i_result = B_BAD_VALUE;
605     }
606     else if( p_mutex == NULL )
607     {
608         i_result = B_BAD_VALUE;
609     }
610     else if( p_condvar->init < 2000 )
611     {
612         i_result = B_NO_INIT;
613     }
614
615     /* The p_condvar->thread var is initialized before the unlock because
616      * it enables to identify when the thread is interrupted beetwen the
617      * unlock line and the suspend_thread line */
618     p_condvar->thread = find_thread( NULL );
619     vlc_mutex_unlock( p_mutex );
620     suspend_thread( p_condvar->thread );
621     p_condvar->thread = -1;
622
623     vlc_mutex_lock( p_mutex );
624     return 0;
625
626 #endif
627
628     if( i_result )
629     {
630         msg_Err( p_condvar->p_this,
631                  "thread %d: cond_wait failed at %s:%d (%d:%s)",
632                  i_thread, psz_file, i_line, i_result, psz_error );
633     }
634
635     return i_result;
636 }
637
638 /*****************************************************************************
639  * vlc_cond_destroy: destroy a condition
640  *****************************************************************************/
641 #define vlc_cond_destroy( P_COND )                                          \
642     __vlc_cond_destroy( __FILE__, __LINE__, P_COND )
643
644 /*****************************************************************************
645  * vlc_thread_create: create a thread
646  *****************************************************************************/
647 #define vlc_thread_create( P_THIS, PSZ_NAME, FUNC, PRIORITY, WAIT )         \
648     __vlc_thread_create( VLC_OBJECT(P_THIS), __FILE__, __LINE__, PSZ_NAME, (void * ( * ) ( void * ))FUNC, PRIORITY, WAIT )
649
650 /*****************************************************************************
651  * vlc_thread_ready: tell the parent thread we were successfully spawned
652  *****************************************************************************/
653 #define vlc_thread_ready( P_THIS )                                          \
654     __vlc_thread_ready( VLC_OBJECT(P_THIS) )
655
656 /*****************************************************************************
657  * vlc_thread_join: wait until a thread exits
658  *****************************************************************************/
659 #define vlc_thread_join( P_THIS )                                           \
660     __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )