]> git.sesse.net Git - vlc/blob - include/threads.h
Input III (Episode 1).
[vlc] / 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.37 2002/03/01 00:33:18 massiot 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     int i_waiting_threads = p_condvar->i_waiting_threads;
592     while( p_condvar->i_waiting_threads
593            && p_condvar->i_waiting_threads == i_waiting_threads )
594     {
595         PulseEvent( p_condvar->signal );
596         Sleep( 0 ); /* deschedule the current thread */
597     }
598     return 0;
599
600 #endif
601 }
602
603 /*****************************************************************************
604  * vlc_cond_broadcast: start all threads waiting on condition completion
605  *****************************************************************************/
606 /*
607  * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
608  * Only works with pthreads, you need to adapt it for others
609  * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
610  */
611 static __inline__ int vlc_cond_broadcast( vlc_cond_t *p_condvar )
612 {
613 #if defined( PTH_INIT_IN_PTH_H )
614     return pth_cond_notify( p_condvar, FALSE );
615
616 #elif defined( ST_INIT_IN_ST_H )
617     return st_cond_broadcast( p_condvar );
618
619 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
620     return pthread_cond_broadcast( p_condvar );
621
622 #elif defined( HAVE_CTHREADS_H )
623     /* condition_signal() */
624     if ( p_condvar->queue.head || p_condvar->implications )
625     {
626         cond_signal( (condition_t)p_condvar );
627     }
628     return 0;
629
630 #elif defined( HAVE_KERNEL_SCHEDULER_H )
631     if( !p_condvar )
632     {
633         return B_BAD_VALUE;
634     }
635
636     if( p_condvar->init < 2000 )
637     {
638         return B_NO_INIT;
639     }
640
641     while( p_condvar->thread != -1 )
642     {
643         thread_info info;
644         if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
645         {
646             return 0;
647         }
648
649         if( info.state != B_THREAD_SUSPENDED )
650         {
651             /* The  waiting thread is not suspended so it could
652              * have been interrupted beetwen the unlock and the
653              * suspend_thread line. That is why we sleep a little
654              * before retesting p_condver->thread. */
655             snooze( 10000 );
656         }
657         else
658         {
659             /* Ok, we have to wake up that thread */
660             resume_thread( p_condvar->thread );
661             return 0;
662         }
663     }
664     return 0;
665
666 #elif defined( WIN32 )
667     /* Release all waiting threads. */
668     /* For this trick to work properly, the vlc_cond_signal must be surrounded
669      * by a mutex. This will prevent another thread from stealing the signal */
670     while( p_condvar->i_waiting_threads )
671     {
672         PulseEvent( p_condvar->signal );
673         Sleep( 0 ); /* deschedule the current thread */
674     }
675     return 0;
676
677 #endif
678 }
679
680 /*****************************************************************************
681  * vlc_cond_wait: wait until condition completion
682  *****************************************************************************/
683 #ifdef DEBUG
684 #   define vlc_cond_wait( P_COND, P_MUTEX )                                 \
685         _vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX  )
686 #else
687 #   define vlc_cond_wait( P_COND, P_MUTEX )                                 \
688         _vlc_cond_wait( NULL, 0, P_COND, P_MUTEX )
689 #endif
690
691 static __inline__ int _vlc_cond_wait( char * psz_file, int i_line,
692                                       vlc_cond_t *p_condvar,
693                                       vlc_mutex_t *p_mutex )
694 {
695 #if defined( PTH_INIT_IN_PTH_H )
696     return pth_cond_await( p_condvar, p_mutex, NULL );
697
698 #elif defined( ST_INIT_IN_ST_H )
699     int i_ret;
700
701     st_mutex_unlock( *p_mutex );
702     i_ret = st_cond_wait( *p_condvar );
703     st_mutex_lock( *p_mutex );
704
705     return i_ret;
706
707 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
708
709 #ifndef DEBUG
710     return pthread_cond_wait( p_condvar, p_mutex );
711 #else
712     /* In debug mode, timeout */
713     struct timeval now;
714     struct timespec timeout;
715     int    i_result;
716
717     for( ; ; )
718     {
719         gettimeofday( &now, NULL );
720         timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT;
721         timeout.tv_nsec = now.tv_usec * 1000;
722
723         i_result = pthread_cond_timedwait( p_condvar, p_mutex, &timeout );
724
725         if( i_result == ETIMEDOUT )
726         {
727             intf_WarnMsg( 1, "thread %d warning: Possible deadlock detected in cond_wait at %s:%d (%s)",
728                           pthread_self(), psz_file, i_line, strerror(i_result) );
729             continue;
730         }
731
732         if( i_result )
733         {
734             intf_ErrMsg( "thread %d error: cond_wait failed at %s:%d (%s)",
735                          pthread_self(), psz_file, i_line, strerror(i_result) );
736         }
737         return( i_result );
738     }
739 #endif
740
741 #elif defined( HAVE_CTHREADS_H )
742     condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
743     return 0;
744
745 #elif defined( HAVE_KERNEL_SCHEDULER_H )
746     if( !p_condvar )
747     {
748         return B_BAD_VALUE;
749     }
750
751     if( !p_mutex )
752     {
753         return B_BAD_VALUE;
754     }
755
756     if( p_condvar->init < 2000 )
757     {
758         return B_NO_INIT;
759     }
760
761     /* The p_condvar->thread var is initialized before the unlock because
762      * it enables to identify when the thread is interrupted beetwen the
763      * unlock line and the suspend_thread line */
764     p_condvar->thread = find_thread( NULL );
765     vlc_mutex_unlock( p_mutex );
766     suspend_thread( p_condvar->thread );
767     p_condvar->thread = -1;
768
769     vlc_mutex_lock( p_mutex );
770     return 0;
771
772 #elif defined( WIN32 )
773     /* The ideal would be to use a function which atomically releases the
774      * mutex and initiate the waiting.
775      * Unfortunately only the SignalObjectAndWait function does this and it's
776      * only supported on WinNT/2K, furthermore it cannot take multiple
777      * events as parameters.
778      *
779      * The solution we use should however fulfill all our needs (even though
780      * it is not a correct pthreads implementation)
781      */
782     int i_result;
783
784     p_condvar->i_waiting_threads ++;
785
786     /* Release the mutex */
787     vlc_mutex_unlock( p_mutex );
788
789     i_result = WaitForSingleObject( p_condvar->signal, INFINITE); 
790
791     /* maybe we should protect this with a mutex ? */
792     p_condvar->i_waiting_threads --;
793
794     /* Reacquire the mutex before returning. */
795     vlc_mutex_lock( p_mutex );
796
797     return( i_result == WAIT_FAILED );
798
799 #endif
800 }
801
802 /*****************************************************************************
803  * vlc_cond_destroy: destroy a condition
804  *****************************************************************************/
805 #ifdef DEBUG
806 #   define vlc_cond_destroy( P_COND )                                       \
807         _vlc_cond_destroy( __FILE__, __LINE__, P_COND )
808 #else
809 #   define vlc_cond_destroy( P_COND )                                       \
810         _vlc_cond_destroy( NULL, 0, P_COND )
811 #endif
812
813 static __inline__ int _vlc_cond_destroy( char * psz_file, int i_line,
814                                          vlc_cond_t *p_condvar )
815 {
816 #if defined( PTH_INIT_IN_PTH_H )
817     return 0;
818
819 #elif defined( ST_INIT_IN_ST_H )
820     return st_cond_destroy( *p_condvar );
821
822 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
823     int i_result = pthread_cond_destroy( p_condvar );
824     if( i_result )
825     {
826         intf_ErrMsg( "thread %d error: cond_destroy failed at %s:%d (%s)",
827                      pthread_self(), psz_file, i_line, strerror(i_result) );
828     }
829     return i_result;
830
831 #elif defined( HAVE_CTHREADS_H )
832     return 0;
833
834 #elif defined( HAVE_KERNEL_SCHEDULER_H )
835     p_condvar->init = 0;
836     return 0;
837
838 #elif defined( WIN32 )
839     return( !CloseHandle( p_condvar->signal ) );
840
841 #endif    
842 }
843
844 /*****************************************************************************
845  * vlc_thread_create: create a thread
846  *****************************************************************************/
847 #ifdef DEBUG
848 #   define vlc_thread_create( P_THREAD, PSZ_NAME, FUNC, P_DATA )            \
849         _vlc_thread_create( __FILE__, __LINE__, P_THREAD, PSZ_NAME, FUNC, P_DATA )
850 #else
851 #   define vlc_thread_create( P_THREAD, PSZ_NAME, FUNC, P_DATA )            \
852         _vlc_thread_create( NULL, 0, P_THREAD, PSZ_NAME, FUNC, P_DATA )
853 #endif
854
855 static __inline__ int _vlc_thread_create( char * psz_file, int i_line,
856                                           vlc_thread_t *p_thread,
857                                           char *psz_name,
858                                           vlc_thread_func_t func,
859                                           void *p_data )
860 {
861     int i_ret;
862
863 #ifdef GPROF
864     wrapper_t wrapper;
865
866     /* Initialize the wrapper structure */
867     wrapper.func = func;
868     wrapper.p_data = p_data;
869     getitimer( ITIMER_PROF, &wrapper.itimer );
870     vlc_mutex_init( &wrapper.lock );
871     vlc_cond_init( &wrapper.wait );
872     vlc_mutex_lock( &wrapper.lock );
873
874     /* Alter user-passed data so that we call the wrapper instead
875      * of the real function */
876     p_data = &wrapper;
877     func = vlc_thread_wrapper;
878 #endif
879
880 #if defined( PTH_INIT_IN_PTH_H )
881     *p_thread = pth_spawn( PTH_ATTR_DEFAULT, func, p_data );
882     i_ret = ( p_thread == NULL );
883
884 #elif defined( ST_INIT_IN_ST_H )
885     *p_thread = st_thread_create( func, p_data, 1, 0 );
886     i_ret = ( p_thread == NULL );
887     
888 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
889     i_ret = pthread_create( p_thread, NULL, func, p_data );
890
891 #elif defined( HAVE_CTHREADS_H )
892     *p_thread = cthread_fork( (cthread_fn_t)func, (any_t)p_data );
893     i_ret = 0;
894
895 #elif defined( HAVE_KERNEL_SCHEDULER_H )
896     *p_thread = spawn_thread( (thread_func)func, psz_name,
897                               B_NORMAL_PRIORITY, p_data );
898     i_ret = resume_thread( *p_thread );
899
900 #elif defined( WIN32 )
901 #if 0
902     DWORD threadID;
903     /* This method is not recommended when using the MSVCRT C library,
904      * so we'll have to use _beginthreadex instead */
905     *p_thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) func, 
906                              p_data, 0, &threadID);
907 #endif
908     unsigned threadID;
909     /* When using the MSVCRT C library you have to use the _beginthreadex
910      * function instead of CreateThread, otherwise you'll end up with memory
911      * leaks and the signal function not working */
912     *p_thread = (HANDLE)_beginthreadex(NULL, 0, (PTHREAD_START) func, 
913                              p_data, 0, &threadID);
914     
915     i_ret = ( *p_thread ? 0 : 1 );
916
917 #endif
918
919 #ifdef GPROF
920     if( i_ret == 0 )
921     {
922         vlc_cond_wait( &wrapper.wait, &wrapper.lock );
923     }
924
925     vlc_mutex_unlock( &wrapper.lock );
926     vlc_mutex_destroy( &wrapper.lock );
927     vlc_cond_destroy( &wrapper.wait );
928 #endif
929
930     if( i_ret == 0 )
931     {
932         intf_WarnMsg( 2, "thread info: %d (%s) has been created (%s:%d)",
933                       *p_thread, psz_name, psz_file, i_line );
934     }
935     else
936     {
937         intf_ErrMsg( "thread error: %s couldn't be created at %s:%d (%s)",
938                      psz_name, psz_file, i_line, strerror(i_ret) );
939     }
940
941     return i_ret;
942 }
943
944 /*****************************************************************************
945  * vlc_thread_exit: terminate a thread
946  *****************************************************************************/
947 static __inline__ void vlc_thread_exit( void )
948 {
949 #if defined( PTH_INIT_IN_PTH_H )
950     pth_exit( 0 );
951
952 #elif defined( ST_INIT_IN_ST_H )
953     int result;
954     st_thread_exit( &result );
955     
956 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
957     pthread_exit( 0 );
958
959 #elif defined( HAVE_CTHREADS_H )
960     int result;
961     cthread_exit( &result );
962
963 #elif defined( HAVE_KERNEL_SCHEDULER_H )
964     exit_thread( 0 );
965
966 #elif defined( WIN32 )
967 #if 0
968     ExitThread( 0 );
969 #endif
970     /* For now we don't close the thread handles (because of race conditions).
971      * Need to be looked at. */
972     _endthreadex(0);
973
974 #endif
975 }
976
977 /*****************************************************************************
978  * vlc_thread_join: wait until a thread exits
979  *****************************************************************************/
980 #ifdef DEBUG
981 #   define vlc_thread_join( THREAD )                                        \
982         _vlc_thread_join( __FILE__, __LINE__, THREAD ) 
983 #else
984 #   define vlc_thread_join( THREAD )                                        \
985         _vlc_thread_join( NULL, 0, THREAD ) 
986 #endif
987
988 static __inline__ void _vlc_thread_join( char * psz_file, int i_line,
989                                          vlc_thread_t thread )
990 {
991     int i_ret = 0;
992
993 #if defined( PTH_INIT_IN_PTH_H )
994     i_ret = pth_join( thread, NULL );
995
996 #elif defined( ST_INIT_IN_ST_H )
997     i_ret = st_thread_join( thread, NULL );
998     
999 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
1000     i_ret = pthread_join( thread, NULL );
1001
1002 #elif defined( HAVE_CTHREADS_H )
1003     cthread_join( thread );
1004     i_ret = 1;
1005
1006 #elif defined( HAVE_KERNEL_SCHEDULER_H )
1007     int32 exit_value;
1008     wait_for_thread( thread, &exit_value );
1009
1010 #elif defined( WIN32 )
1011     WaitForSingleObject( thread, INFINITE );
1012
1013 #endif
1014
1015     if( i_ret )
1016     {
1017         intf_ErrMsg( "thread error: thread_join(%d) failed at %s:%d (%s)",
1018                      thread, psz_file, i_line, strerror(i_ret) );
1019     }
1020     else
1021     {
1022         intf_WarnMsg( 2, "thread info: %d has been joined (%s:%d)",
1023                       thread, psz_file, i_line );
1024     }
1025 }
1026
1027 #ifdef GPROF
1028 static void *vlc_thread_wrapper( void *p_wrapper )
1029 {
1030     /* Put user data in thread-local variables */
1031     void *            p_data = ((wrapper_t*)p_wrapper)->p_data;
1032     vlc_thread_func_t func   = ((wrapper_t*)p_wrapper)->func;
1033
1034     /* Set the profile timer value */
1035     setitimer( ITIMER_PROF, &((wrapper_t*)p_wrapper)->itimer, NULL );
1036
1037     /* Tell the calling thread that we don't need its data anymore */
1038     vlc_mutex_lock( &((wrapper_t*)p_wrapper)->lock );
1039     vlc_cond_signal( &((wrapper_t*)p_wrapper)->wait );
1040     vlc_mutex_unlock( &((wrapper_t*)p_wrapper)->lock );
1041
1042     /* Call the real function */
1043     return func( p_data );
1044 }
1045 #endif
1046