59a4684bb39d1aeff8a3491812dd3686e14bae42
[vlc.git] / include / threads.h
1 /*****************************************************************************
2  * threads.h : threads implementation for the VideoLAN client
3  * This header provides a portable threads implementation.
4  *****************************************************************************
5  * Copyright (C) 1999, 2000 VideoLAN
6  * $Id: threads.h,v 1.38 2002/03/28 10:17:06 gbazin Exp $
7  *
8  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
9  *          Samuel Hocevar <sam@via.ecp.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 #include <stdio.h>
27
28 #if defined(GPROF) || defined(DEBUG)
29 #   include <sys/time.h>
30 #endif
31
32 #if defined( PTH_INIT_IN_PTH_H )                                  /* GNU Pth */
33 #   include <pth.h>
34
35 #elif defined( ST_INIT_IN_ST_H )                            /* State threads */
36 #   include <st.h>
37
38 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )  /* pthreads (like Linux & BSD) */
39 #   include <pthread.h>
40 #   ifdef DEBUG
41 /* Needed for pthread_cond_timedwait */
42 #       include <errno.h>
43 #   endif
44 /* This is not prototyped under Linux, though it exists. */
45 int pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind );
46
47 #elif defined( HAVE_CTHREADS_H )                                  /* GNUMach */
48 #   include <cthreads.h>
49
50 #elif defined( HAVE_KERNEL_SCHEDULER_H )                             /* BeOS */
51 #   include <kernel/OS.h>
52 #   include <kernel/scheduler.h>
53 #   include <byteorder.h>
54
55 #elif defined( WIN32 )
56 #define WIN32_LEAN_AND_MEAN
57 #   include <windows.h>
58 #   include <process.h>
59
60 #else
61 #   error no threads available on your system !
62
63 #endif
64
65 /*****************************************************************************
66  * Constants
67  *****************************************************************************
68  * These constants are used by all threads in *_CreateThread() and
69  * *_DestroyThreads() functions. Since those calls are non-blocking, an integer
70  * value is used as a shared flag to represent the status of the thread.
71  *****************************************************************************/
72
73 /* Void status - this value can be used to make sure no operation is currently
74  * in progress on the concerned thread in an array of recorded threads */
75 #define THREAD_NOP          0                            /* nothing happened */
76
77 /* Creation status */
78 #define THREAD_CREATE       10                     /* thread is initializing */
79 #define THREAD_START        11                          /* thread has forked */
80 #define THREAD_READY        19                            /* thread is ready */
81
82 /* Destructions status */
83 #define THREAD_DESTROY      20            /* destruction order has been sent */
84 #define THREAD_END          21        /* destruction order has been received */
85 #define THREAD_OVER         29             /* thread does not exist any more */
86
87 /* Error status */
88 #define THREAD_ERROR        30                           /* an error occured */
89 #define THREAD_FATAL        31  /* an fatal error occured - program must end */
90
91 /*****************************************************************************
92  * Types definition
93  *****************************************************************************/
94
95 #if defined( PTH_INIT_IN_PTH_H )
96 typedef pth_t            vlc_thread_t;
97 typedef pth_mutex_t      vlc_mutex_t;
98 typedef pth_cond_t       vlc_cond_t;
99
100 #elif defined( ST_INIT_IN_ST_H )
101 typedef st_thread_t *    vlc_thread_t;
102 typedef st_mutex_t *     vlc_mutex_t;
103 typedef st_cond_t *      vlc_cond_t;
104
105 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
106 typedef pthread_t        vlc_thread_t;
107 typedef pthread_mutex_t  vlc_mutex_t;
108 typedef pthread_cond_t   vlc_cond_t;
109
110 #elif defined( HAVE_CTHREADS_H )
111 typedef cthread_t        vlc_thread_t;
112
113 /* Those structs are the ones defined in /include/cthreads.h but we need
114  * to handle (*foo) where foo is a (mutex_t) while they handle (foo) where
115  * foo is a (mutex_t*) */
116 typedef struct s_mutex {
117     spin_lock_t held;
118     spin_lock_t lock;
119     char *name;
120     struct cthread_queue queue;
121 } vlc_mutex_t;
122
123 typedef struct s_condition {
124     spin_lock_t lock;
125     struct cthread_queue queue;
126     char *name;
127     struct cond_imp *implications;
128 } vlc_cond_t;
129
130 #elif defined( HAVE_KERNEL_SCHEDULER_H )
131 /* This is the BeOS implementation of the vlc threads, note that the mutex is
132  * not a real mutex and the cond_var is not like a pthread cond_var but it is
133  * enough for what wee need */
134
135 typedef thread_id vlc_thread_t;
136
137 typedef struct
138 {
139     int32           init;
140     sem_id          lock;
141 } vlc_mutex_t;
142
143 typedef struct
144 {
145     int32           init;
146     thread_id       thread;
147 } vlc_cond_t;
148
149 #elif defined( WIN32 )
150 typedef HANDLE           vlc_thread_t;
151 typedef CRITICAL_SECTION vlc_mutex_t;
152
153 typedef struct
154 {
155     int             i_waiting_threads;
156     HANDLE          signal;
157 } vlc_cond_t;
158
159 typedef unsigned (__stdcall *PTHREAD_START) (void *);
160
161 #endif
162
163 typedef void *(*vlc_thread_func_t)(void *p_data);
164
165 /*****************************************************************************
166  * Prototypes
167  *****************************************************************************/
168
169 #ifdef GPROF
170 /* Wrapper function for profiling */
171 static void *      vlc_thread_wrapper ( void *p_wrapper );
172
173 #   ifdef WIN32
174
175 #       define ITIMER_REAL 1
176 #       define ITIMER_PROF 2
177
178 struct itimerval
179 {
180     struct timeval it_value;
181     struct timeval it_interval;
182 };
183
184 int setitimer(int kind, const struct itimerval* itnew, struct itimerval* itold);
185
186 #   endif /* WIN32 */
187
188 typedef struct wrapper_s
189 {
190     /* Data lock access */
191     vlc_mutex_t lock;
192     vlc_cond_t  wait;
193
194     /* Data used to spawn the real thread */
195     vlc_thread_func_t func;
196     void *p_data;
197
198     /* Profiling timer passed to the thread */
199     struct itimerval itimer;
200
201 } wrapper_t;
202
203 #endif /* GPROF */
204
205 /*****************************************************************************
206  * vlc_threads_init: initialize threads system
207  *****************************************************************************/
208 static __inline__ int vlc_threads_init( void )
209 {
210 #if defined( PTH_INIT_IN_PTH_H )
211     return pth_init();
212
213 #elif defined( ST_INIT_IN_ST_H )
214     return st_init();
215
216 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
217     return 0;
218
219 #elif defined( HAVE_CTHREADS_H )
220     return 0;
221
222 #elif defined( HAVE_KERNEL_SCHEDULER_H )
223     return 0;
224
225 #elif defined( WIN32 )
226     return 0;
227
228 #endif
229 }
230
231 /*****************************************************************************
232  * vlc_threads_end: stop threads system
233  *****************************************************************************/
234 static __inline__ int vlc_threads_end( void )
235 {
236 #if defined( PTH_INIT_IN_PTH_H )
237     return pth_kill();
238
239 #elif defined( ST_INIT_IN_ST_H )
240     return 0;
241
242 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
243     return 0;
244
245 #elif defined( HAVE_CTHREADS_H )
246     return 0;
247
248 #elif defined( HAVE_KERNEL_SCHEDULER_H )
249     return 0;
250
251 #elif defined( WIN32 )
252     return 0;
253
254 #endif
255 }
256
257 /*****************************************************************************
258  * vlc_mutex_init: initialize a mutex
259  *****************************************************************************/
260 static __inline__ int vlc_mutex_init( vlc_mutex_t *p_mutex )
261 {
262 #if defined( PTH_INIT_IN_PTH_H )
263     return pth_mutex_init( p_mutex );
264
265 #elif defined( ST_INIT_IN_ST_H )
266     *p_mutex = st_mutex_new();
267     return ( *p_mutex == NULL ) ? errno : 0;
268
269 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
270 #   if defined(DEBUG) && defined(SYS_LINUX)
271     /* Create error-checking mutex to detect threads problems more easily. */
272     pthread_mutexattr_t attr;
273     int                 i_result;
274
275     pthread_mutexattr_init( &attr );
276     pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ERRORCHECK_NP );
277     i_result = pthread_mutex_init( p_mutex, &attr );
278     pthread_mutexattr_destroy( &attr );
279     return( i_result );
280 #   endif
281
282     return pthread_mutex_init( p_mutex, NULL );
283
284 #elif defined( HAVE_CTHREADS_H )
285     mutex_init( p_mutex );
286     return 0;
287
288 #elif defined( HAVE_KERNEL_SCHEDULER_H )
289
290     /* check the arguments and whether it's already been initialized */
291     if( p_mutex == NULL )
292     {
293         return B_BAD_VALUE;
294     }
295
296     if( p_mutex->init == 9999 )
297     {
298         return EALREADY;
299     }
300
301     p_mutex->lock = create_sem( 1, "BeMutex" );
302     if( p_mutex->lock < B_NO_ERROR )
303     {
304         return( -1 );
305     }
306
307     p_mutex->init = 9999;
308     return B_OK;
309
310 #elif defined( WIN32 )
311     InitializeCriticalSection( p_mutex );
312     return 0;
313
314 #endif
315 }
316
317 /*****************************************************************************
318  * vlc_mutex_lock: lock a mutex
319  *****************************************************************************/
320 #ifdef DEBUG
321 #   define vlc_mutex_lock( P_MUTEX )                                        \
322         _vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
323 #else
324 #   define vlc_mutex_lock( P_MUTEX )                                        \
325         _vlc_mutex_lock( NULL, 0, P_MUTEX )
326 #endif
327
328 static __inline__ int _vlc_mutex_lock( char * psz_file, int i_line,
329                                        vlc_mutex_t *p_mutex )
330 {
331 #if defined( PTH_INIT_IN_PTH_H )
332     return pth_mutex_acquire( p_mutex, TRUE, NULL );
333
334 #elif defined( ST_INIT_IN_ST_H )
335     return st_mutex_lock( *p_mutex );
336
337 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
338     int i_return = pthread_mutex_lock( p_mutex );
339     if( i_return )
340     {
341         intf_ErrMsg( "thread %d error: mutex_lock failed at %s:%d (%s)",
342                      pthread_self(), psz_file, i_line, strerror(i_return) );
343     }
344     return i_return;
345
346 #elif defined( HAVE_CTHREADS_H )
347     mutex_lock( p_mutex );
348     return 0;
349
350 #elif defined( HAVE_KERNEL_SCHEDULER_H )
351     status_t err;
352
353     if( !p_mutex )
354     {
355         return B_BAD_VALUE;
356     }
357
358     if( p_mutex->init < 2000 )
359     {
360         return B_NO_INIT;
361     }
362
363     err = acquire_sem( p_mutex->lock );
364     return err;
365
366 #elif defined( WIN32 )
367     EnterCriticalSection( p_mutex );
368     return 0;
369
370 #endif
371 }
372
373 /*****************************************************************************
374  * vlc_mutex_unlock: unlock a mutex
375  *****************************************************************************/
376 #ifdef DEBUG
377 #   define vlc_mutex_unlock( P_MUTEX )                                      \
378         _vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
379 #else
380 #   define vlc_mutex_unlock( P_MUTEX )                                      \
381         _vlc_mutex_unlock( NULL, 0, P_MUTEX )
382 #endif
383
384 static __inline__ int _vlc_mutex_unlock( char * psz_file, int i_line,
385                                          vlc_mutex_t *p_mutex )
386 {
387 #if defined( PTH_INIT_IN_PTH_H )
388     return pth_mutex_release( p_mutex );
389
390 #elif defined( ST_INIT_IN_ST_H )
391     return st_mutex_unlock( *p_mutex );
392
393 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
394     int i_return = pthread_mutex_unlock( p_mutex );
395     if( i_return )
396     {
397         intf_ErrMsg( "thread %d error: mutex_unlock failed at %s:%d (%s)",
398                      pthread_self(), psz_file, i_line, strerror(i_return) );
399     }
400     return i_return;
401
402 #elif defined( HAVE_CTHREADS_H )
403     mutex_unlock( p_mutex );
404     return 0;
405
406 #elif defined( HAVE_KERNEL_SCHEDULER_H )
407     if( !p_mutex)
408     {
409         return B_BAD_VALUE;
410     }
411
412     if( p_mutex->init < 2000 )
413     {
414         return B_NO_INIT;
415     }
416
417     release_sem( p_mutex->lock );
418     return B_OK;
419
420 #elif defined( WIN32 )
421     LeaveCriticalSection( p_mutex );
422     return 0;
423
424 #endif
425 }
426
427 /*****************************************************************************
428  * vlc_mutex_destroy: destroy a mutex
429  *****************************************************************************/
430 #ifdef DEBUG
431 #   define vlc_mutex_destroy( P_MUTEX )                                     \
432         _vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
433 #else
434 #   define vlc_mutex_destroy( P_MUTEX )                                     \
435         _vlc_mutex_destroy( NULL, 0, P_MUTEX )
436 #endif
437
438 static __inline__ int _vlc_mutex_destroy( char * psz_file, int i_line,
439                                           vlc_mutex_t *p_mutex )
440 {
441 #if defined( PTH_INIT_IN_PTH_H )
442     return 0;
443
444 #elif defined( ST_INIT_IN_ST_H )
445     return st_mutex_destroy( *p_mutex );
446
447 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )    
448     int i_return = pthread_mutex_destroy( p_mutex );
449     if( i_return )
450     {
451         intf_ErrMsg( "thread %d error: mutex_destroy failed at %s:%d (%s)",
452                      pthread_self(), psz_file, i_line, strerror(i_return) );
453     }
454     return i_return;
455
456 #elif defined( HAVE_CTHREADS_H )
457     return 0;
458
459 #elif defined( HAVE_KERNEL_SCHEDULER_H )
460     if( p_mutex->init == 9999 )
461     {
462         delete_sem( p_mutex->lock );
463     }
464
465     p_mutex->init = 0;
466     return B_OK;
467
468 #elif defined( WIN32 )
469     DeleteCriticalSection( p_mutex );
470     return 0;
471
472 #endif    
473 }
474
475 /*****************************************************************************
476  * vlc_cond_init: initialize a condition
477  *****************************************************************************/
478 static __inline__ int vlc_cond_init( vlc_cond_t *p_condvar )
479 {
480 #if defined( PTH_INIT_IN_PTH_H )
481     return pth_cond_init( p_condvar );
482
483 #elif defined( ST_INIT_IN_ST_H )
484     *p_condvar = st_cond_new();
485     return ( *p_condvar == NULL ) ? errno : 0;
486
487 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
488     return pthread_cond_init( p_condvar, NULL );
489
490 #elif defined( HAVE_CTHREADS_H )
491     /* condition_init() */
492     spin_lock_init( &p_condvar->lock );
493     cthread_queue_init( &p_condvar->queue );
494     p_condvar->name = 0;
495     p_condvar->implications = 0;
496
497     return 0;
498
499 #elif defined( HAVE_KERNEL_SCHEDULER_H )
500     if( !p_condvar )
501     {
502         return B_BAD_VALUE;
503     }
504
505     if( p_condvar->init == 9999 )
506     {
507         return EALREADY;
508     }
509
510     p_condvar->thread = -1;
511     p_condvar->init = 9999;
512     return 0;
513
514 #elif defined( WIN32 )
515     /* initialise counter */
516     p_condvar->i_waiting_threads = 0;
517
518     /* Create an auto-reset event. */
519     p_condvar->signal = CreateEvent( NULL, /* no security */
520                                      FALSE,  /* auto-reset event */
521                                      FALSE,  /* non-signaled initially */
522                                      NULL ); /* unnamed */
523
524     return( !p_condvar->signal );
525     
526 #endif
527 }
528
529 /*****************************************************************************
530  * vlc_cond_signal: start a thread on condition completion
531  *****************************************************************************/
532 static __inline__ int vlc_cond_signal( vlc_cond_t *p_condvar )
533 {
534 #if defined( PTH_INIT_IN_PTH_H )
535     return pth_cond_notify( p_condvar, FALSE );
536
537 #elif defined( ST_INIT_IN_ST_H )
538     return st_cond_signal( *p_condvar );
539
540 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
541     return pthread_cond_signal( p_condvar );
542
543 #elif defined( HAVE_CTHREADS_H )
544     /* condition_signal() */
545     if ( p_condvar->queue.head || p_condvar->implications )
546     {
547         cond_signal( (condition_t)p_condvar );
548     }
549     return 0;
550
551 #elif defined( HAVE_KERNEL_SCHEDULER_H )
552     if( !p_condvar )
553     {
554         return B_BAD_VALUE;
555     }
556
557     if( p_condvar->init < 2000 )
558     {
559         return B_NO_INIT;
560     }
561
562     while( p_condvar->thread != -1 )
563     {
564         thread_info info;
565         if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
566         {
567             return 0;
568         }
569
570         if( info.state != B_THREAD_SUSPENDED )
571         {
572             /* The  waiting thread is not suspended so it could
573              * have been interrupted beetwen the unlock and the
574              * suspend_thread line. That is why we sleep a little
575              * before retesting p_condver->thread. */
576             snooze( 10000 );
577         }
578         else
579         {
580             /* Ok, we have to wake up that thread */
581             resume_thread( p_condvar->thread );
582             return 0;
583         }
584     }
585     return 0;
586
587 #elif defined( WIN32 )
588     /* Release one waiting thread if one is available. */
589     /* For this trick to work properly, the vlc_cond_signal must be surrounded
590      * by a mutex. This will prevent another thread from stealing the signal */
591     PulseEvent( p_condvar->signal );
592     return 0;
593
594 #endif
595 }
596
597 /*****************************************************************************
598  * vlc_cond_broadcast: start all threads waiting on condition completion
599  *****************************************************************************/
600 /*
601  * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
602  * Only works with pthreads, you need to adapt it for others
603  * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
604  */
605 static __inline__ int vlc_cond_broadcast( vlc_cond_t *p_condvar )
606 {
607 #if defined( PTH_INIT_IN_PTH_H )
608     return pth_cond_notify( p_condvar, FALSE );
609
610 #elif defined( ST_INIT_IN_ST_H )
611     return st_cond_broadcast( p_condvar );
612
613 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
614     return pthread_cond_broadcast( p_condvar );
615
616 #elif defined( HAVE_CTHREADS_H )
617     /* condition_signal() */
618     if ( p_condvar->queue.head || p_condvar->implications )
619     {
620         cond_signal( (condition_t)p_condvar );
621     }
622     return 0;
623
624 #elif defined( HAVE_KERNEL_SCHEDULER_H )
625     if( !p_condvar )
626     {
627         return B_BAD_VALUE;
628     }
629
630     if( p_condvar->init < 2000 )
631     {
632         return B_NO_INIT;
633     }
634
635     while( p_condvar->thread != -1 )
636     {
637         thread_info info;
638         if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
639         {
640             return 0;
641         }
642
643         if( info.state != B_THREAD_SUSPENDED )
644         {
645             /* The  waiting thread is not suspended so it could
646              * have been interrupted beetwen the unlock and the
647              * suspend_thread line. That is why we sleep a little
648              * before retesting p_condver->thread. */
649             snooze( 10000 );
650         }
651         else
652         {
653             /* Ok, we have to wake up that thread */
654             resume_thread( p_condvar->thread );
655             return 0;
656         }
657     }
658     return 0;
659
660 #elif defined( WIN32 )
661     /* Release all waiting threads. */
662     /* For this trick to work properly, the vlc_cond_signal must be surrounded
663      * by a mutex. This will prevent another thread from stealing the signal */
664     while( p_condvar->i_waiting_threads )
665     {
666         PulseEvent( p_condvar->signal );
667         Sleep( 0 ); /* deschedule the current thread */
668     }
669     return 0;
670
671 #endif
672 }
673
674 /*****************************************************************************
675  * vlc_cond_wait: wait until condition completion
676  *****************************************************************************/
677 #ifdef DEBUG
678 #   define vlc_cond_wait( P_COND, P_MUTEX )                                 \
679         _vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX  )
680 #else
681 #   define vlc_cond_wait( P_COND, P_MUTEX )                                 \
682         _vlc_cond_wait( NULL, 0, P_COND, P_MUTEX )
683 #endif
684
685 static __inline__ int _vlc_cond_wait( char * psz_file, int i_line,
686                                       vlc_cond_t *p_condvar,
687                                       vlc_mutex_t *p_mutex )
688 {
689 #if defined( PTH_INIT_IN_PTH_H )
690     return pth_cond_await( p_condvar, p_mutex, NULL );
691
692 #elif defined( ST_INIT_IN_ST_H )
693     int i_ret;
694
695     st_mutex_unlock( *p_mutex );
696     i_ret = st_cond_wait( *p_condvar );
697     st_mutex_lock( *p_mutex );
698
699     return i_ret;
700
701 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
702
703 #ifndef DEBUG
704     return pthread_cond_wait( p_condvar, p_mutex );
705 #else
706     /* In debug mode, timeout */
707     struct timeval now;
708     struct timespec timeout;
709     int    i_result;
710
711     for( ; ; )
712     {
713         gettimeofday( &now, NULL );
714         timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT;
715         timeout.tv_nsec = now.tv_usec * 1000;
716
717         i_result = pthread_cond_timedwait( p_condvar, p_mutex, &timeout );
718
719         if( i_result == ETIMEDOUT )
720         {
721             intf_WarnMsg( 1, "thread %d warning: Possible deadlock detected in cond_wait at %s:%d (%s)",
722                           pthread_self(), psz_file, i_line, strerror(i_result) );
723             continue;
724         }
725
726         if( i_result )
727         {
728             intf_ErrMsg( "thread %d error: cond_wait failed at %s:%d (%s)",
729                          pthread_self(), psz_file, i_line, strerror(i_result) );
730         }
731         return( i_result );
732     }
733 #endif
734
735 #elif defined( HAVE_CTHREADS_H )
736     condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
737     return 0;
738
739 #elif defined( HAVE_KERNEL_SCHEDULER_H )
740     if( !p_condvar )
741     {
742         return B_BAD_VALUE;
743     }
744
745     if( !p_mutex )
746     {
747         return B_BAD_VALUE;
748     }
749
750     if( p_condvar->init < 2000 )
751     {
752         return B_NO_INIT;
753     }
754
755     /* The p_condvar->thread var is initialized before the unlock because
756      * it enables to identify when the thread is interrupted beetwen the
757      * unlock line and the suspend_thread line */
758     p_condvar->thread = find_thread( NULL );
759     vlc_mutex_unlock( p_mutex );
760     suspend_thread( p_condvar->thread );
761     p_condvar->thread = -1;
762
763     vlc_mutex_lock( p_mutex );
764     return 0;
765
766 #elif defined( WIN32 )
767     /* The ideal would be to use a function which atomically releases the
768      * mutex and initiate the waiting.
769      * Unfortunately only the SignalObjectAndWait function does this and it's
770      * only supported on WinNT/2K, furthermore it cannot take multiple
771      * events as parameters.
772      *
773      * The solution we use should however fulfill all our needs (even though
774      * it is not a correct pthreads implementation)
775      */
776     int i_result;
777
778     p_condvar->i_waiting_threads ++;
779
780     /* Release the mutex */
781     vlc_mutex_unlock( p_mutex );
782
783     i_result = WaitForSingleObject( p_condvar->signal, INFINITE); 
784
785     /* maybe we should protect this with a mutex ? */
786     p_condvar->i_waiting_threads --;
787
788     /* Reacquire the mutex before returning. */
789     vlc_mutex_lock( p_mutex );
790
791     return( i_result == WAIT_FAILED );
792
793 #endif
794 }
795
796 /*****************************************************************************
797  * vlc_cond_destroy: destroy a condition
798  *****************************************************************************/
799 #ifdef DEBUG
800 #   define vlc_cond_destroy( P_COND )                                       \
801         _vlc_cond_destroy( __FILE__, __LINE__, P_COND )
802 #else
803 #   define vlc_cond_destroy( P_COND )                                       \
804         _vlc_cond_destroy( NULL, 0, P_COND )
805 #endif
806
807 static __inline__ int _vlc_cond_destroy( char * psz_file, int i_line,
808                                          vlc_cond_t *p_condvar )
809 {
810 #if defined( PTH_INIT_IN_PTH_H )
811     return 0;
812
813 #elif defined( ST_INIT_IN_ST_H )
814     return st_cond_destroy( *p_condvar );
815
816 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
817     int i_result = pthread_cond_destroy( p_condvar );
818     if( i_result )
819     {
820         intf_ErrMsg( "thread %d error: cond_destroy failed at %s:%d (%s)",
821                      pthread_self(), psz_file, i_line, strerror(i_result) );
822     }
823     return i_result;
824
825 #elif defined( HAVE_CTHREADS_H )
826     return 0;
827
828 #elif defined( HAVE_KERNEL_SCHEDULER_H )
829     p_condvar->init = 0;
830     return 0;
831
832 #elif defined( WIN32 )
833     return( !CloseHandle( p_condvar->signal ) );
834
835 #endif    
836 }
837
838 /*****************************************************************************
839  * vlc_thread_create: create a thread
840  *****************************************************************************/
841 #ifdef DEBUG
842 #   define vlc_thread_create( P_THREAD, PSZ_NAME, FUNC, P_DATA )            \
843         _vlc_thread_create( __FILE__, __LINE__, P_THREAD, PSZ_NAME, FUNC, P_DATA )
844 #else
845 #   define vlc_thread_create( P_THREAD, PSZ_NAME, FUNC, P_DATA )            \
846         _vlc_thread_create( NULL, 0, P_THREAD, PSZ_NAME, FUNC, P_DATA )
847 #endif
848
849 static __inline__ int _vlc_thread_create( char * psz_file, int i_line,
850                                           vlc_thread_t *p_thread,
851                                           char *psz_name,
852                                           vlc_thread_func_t func,
853                                           void *p_data )
854 {
855     int i_ret;
856
857 #ifdef GPROF
858     wrapper_t wrapper;
859
860     /* Initialize the wrapper structure */
861     wrapper.func = func;
862     wrapper.p_data = p_data;
863     getitimer( ITIMER_PROF, &wrapper.itimer );
864     vlc_mutex_init( &wrapper.lock );
865     vlc_cond_init( &wrapper.wait );
866     vlc_mutex_lock( &wrapper.lock );
867
868     /* Alter user-passed data so that we call the wrapper instead
869      * of the real function */
870     p_data = &wrapper;
871     func = vlc_thread_wrapper;
872 #endif
873
874 #if defined( PTH_INIT_IN_PTH_H )
875     *p_thread = pth_spawn( PTH_ATTR_DEFAULT, func, p_data );
876     i_ret = ( p_thread == NULL );
877
878 #elif defined( ST_INIT_IN_ST_H )
879     *p_thread = st_thread_create( func, p_data, 1, 0 );
880     i_ret = ( p_thread == NULL );
881     
882 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
883     i_ret = pthread_create( p_thread, NULL, func, p_data );
884
885 #elif defined( HAVE_CTHREADS_H )
886     *p_thread = cthread_fork( (cthread_fn_t)func, (any_t)p_data );
887     i_ret = 0;
888
889 #elif defined( HAVE_KERNEL_SCHEDULER_H )
890     *p_thread = spawn_thread( (thread_func)func, psz_name,
891                               B_NORMAL_PRIORITY, p_data );
892     i_ret = resume_thread( *p_thread );
893
894 #elif defined( WIN32 )
895 #if 0
896     DWORD threadID;
897     /* This method is not recommended when using the MSVCRT C library,
898      * so we'll have to use _beginthreadex instead */
899     *p_thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) func, 
900                              p_data, 0, &threadID);
901 #endif
902     unsigned threadID;
903     /* When using the MSVCRT C library you have to use the _beginthreadex
904      * function instead of CreateThread, otherwise you'll end up with memory
905      * leaks and the signal function not working */
906     *p_thread = (HANDLE)_beginthreadex(NULL, 0, (PTHREAD_START) func, 
907                              p_data, 0, &threadID);
908     
909     i_ret = ( *p_thread ? 0 : 1 );
910
911 #endif
912
913 #ifdef GPROF
914     if( i_ret == 0 )
915     {
916         vlc_cond_wait( &wrapper.wait, &wrapper.lock );
917     }
918
919     vlc_mutex_unlock( &wrapper.lock );
920     vlc_mutex_destroy( &wrapper.lock );
921     vlc_cond_destroy( &wrapper.wait );
922 #endif
923
924     if( i_ret == 0 )
925     {
926         intf_WarnMsg( 2, "thread info: %d (%s) has been created (%s:%d)",
927                       *p_thread, psz_name, psz_file, i_line );
928     }
929     else
930     {
931         intf_ErrMsg( "thread error: %s couldn't be created at %s:%d (%s)",
932                      psz_name, psz_file, i_line, strerror(i_ret) );
933     }
934
935     return i_ret;
936 }
937
938 /*****************************************************************************
939  * vlc_thread_exit: terminate a thread
940  *****************************************************************************/
941 static __inline__ void vlc_thread_exit( void )
942 {
943 #if defined( PTH_INIT_IN_PTH_H )
944     pth_exit( 0 );
945
946 #elif defined( ST_INIT_IN_ST_H )
947     int result;
948     st_thread_exit( &result );
949     
950 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
951     pthread_exit( 0 );
952
953 #elif defined( HAVE_CTHREADS_H )
954     int result;
955     cthread_exit( &result );
956
957 #elif defined( HAVE_KERNEL_SCHEDULER_H )
958     exit_thread( 0 );
959
960 #elif defined( WIN32 )
961 #if 0
962     ExitThread( 0 );
963 #endif
964     /* For now we don't close the thread handles (because of race conditions).
965      * Need to be looked at. */
966     _endthreadex(0);
967
968 #endif
969 }
970
971 /*****************************************************************************
972  * vlc_thread_join: wait until a thread exits
973  *****************************************************************************/
974 #ifdef DEBUG
975 #   define vlc_thread_join( THREAD )                                        \
976         _vlc_thread_join( __FILE__, __LINE__, THREAD ) 
977 #else
978 #   define vlc_thread_join( THREAD )                                        \
979         _vlc_thread_join( NULL, 0, THREAD ) 
980 #endif
981
982 static __inline__ void _vlc_thread_join( char * psz_file, int i_line,
983                                          vlc_thread_t thread )
984 {
985     int i_ret = 0;
986
987 #if defined( PTH_INIT_IN_PTH_H )
988     i_ret = pth_join( thread, NULL );
989
990 #elif defined( ST_INIT_IN_ST_H )
991     i_ret = st_thread_join( thread, NULL );
992     
993 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
994     i_ret = pthread_join( thread, NULL );
995
996 #elif defined( HAVE_CTHREADS_H )
997     cthread_join( thread );
998     i_ret = 1;
999
1000 #elif defined( HAVE_KERNEL_SCHEDULER_H )
1001     int32 exit_value;
1002     wait_for_thread( thread, &exit_value );
1003
1004 #elif defined( WIN32 )
1005     WaitForSingleObject( thread, INFINITE );
1006
1007 #endif
1008
1009     if( i_ret )
1010     {
1011         intf_ErrMsg( "thread error: thread_join(%d) failed at %s:%d (%s)",
1012                      thread, psz_file, i_line, strerror(i_ret) );
1013     }
1014     else
1015     {
1016         intf_WarnMsg( 2, "thread info: %d has been joined (%s:%d)",
1017                       thread, psz_file, i_line );
1018     }
1019 }
1020
1021 #ifdef GPROF
1022 static void *vlc_thread_wrapper( void *p_wrapper )
1023 {
1024     /* Put user data in thread-local variables */
1025     void *            p_data = ((wrapper_t*)p_wrapper)->p_data;
1026     vlc_thread_func_t func   = ((wrapper_t*)p_wrapper)->func;
1027
1028     /* Set the profile timer value */
1029     setitimer( ITIMER_PROF, &((wrapper_t*)p_wrapper)->itimer, NULL );
1030
1031     /* Tell the calling thread that we don't need its data anymore */
1032     vlc_mutex_lock( &((wrapper_t*)p_wrapper)->lock );
1033     vlc_cond_signal( &((wrapper_t*)p_wrapper)->wait );
1034     vlc_mutex_unlock( &((wrapper_t*)p_wrapper)->lock );
1035
1036     /* Call the real function */
1037     return func( p_data );
1038 }
1039 #endif
1040