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