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.31 2001/12/03 13:58:59 massiot Exp $
8 * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
9 * Samuel Hocevar <sam@via.ecp.fr>
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.
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.
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 *****************************************************************************/
28 #if defined(GPROF) || defined(DEBUG)
29 # include <sys/time.h>
32 #if defined( PTH_INIT_IN_PTH_H ) /* GNU Pth */
35 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) /* pthreads (like Linux & BSD) */
37 /* This is not prototyped under Linux, though it exists. */
38 int pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind );
40 #elif defined( HAVE_CTHREADS_H ) /* GNUMach */
41 # include <cthreads.h>
43 #elif defined( HAVE_KERNEL_SCHEDULER_H ) /* BeOS */
46 # include <kernel/OS.h>
47 # include <kernel/scheduler.h>
48 # include <byteorder.h>
50 #elif defined( WIN32 )
51 #define WIN32_LEAN_AND_MEAN
56 # error no threads available on your system !
60 /*****************************************************************************
62 *****************************************************************************
63 * These constants are used by all threads in *_CreateThread() and
64 * *_DestroyThreads() functions. Since those calls are non-blocking, an integer
65 * value is used as a shared flag to represent the status of the thread.
66 *****************************************************************************/
68 /* Void status - this value can be used to make sure no operation is currently
69 * in progress on the concerned thread in an array of recorded threads */
70 #define THREAD_NOP 0 /* nothing happened */
73 #define THREAD_CREATE 10 /* thread is initializing */
74 #define THREAD_START 11 /* thread has forked */
75 #define THREAD_READY 19 /* thread is ready */
77 /* Destructions status */
78 #define THREAD_DESTROY 20 /* destruction order has been sent */
79 #define THREAD_END 21 /* destruction order has been received */
80 #define THREAD_OVER 29 /* thread does not exist any more */
83 #define THREAD_ERROR 30 /* an error occured */
84 #define THREAD_FATAL 31 /* an fatal error occured - program must end */
86 /*****************************************************************************
88 *****************************************************************************/
90 #if defined( PTH_INIT_IN_PTH_H )
91 typedef pth_t vlc_thread_t;
92 typedef pth_mutex_t vlc_mutex_t;
93 typedef pth_cond_t vlc_cond_t;
95 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
96 typedef pthread_t vlc_thread_t;
97 typedef pthread_mutex_t vlc_mutex_t;
98 typedef pthread_cond_t vlc_cond_t;
100 #elif defined( HAVE_CTHREADS_H )
101 typedef cthread_t vlc_thread_t;
103 /* Those structs are the ones defined in /include/cthreads.h but we need
104 * to handle (*foo) where foo is a (mutex_t) while they handle (foo) where
105 * foo is a (mutex_t*) */
106 typedef struct s_mutex {
110 struct cthread_queue queue;
113 typedef struct s_condition {
115 struct cthread_queue queue;
117 struct cond_imp *implications;
120 #elif defined( HAVE_KERNEL_SCHEDULER_H )
121 /* This is the BeOS implementation of the vlc threads, note that the mutex is
122 * not a real mutex and the cond_var is not like a pthread cond_var but it is
123 * enough for what wee need */
125 typedef thread_id vlc_thread_t;
139 #elif defined( WIN32 )
140 typedef HANDLE vlc_thread_t;
141 typedef CRITICAL_SECTION vlc_mutex_t;
145 int i_waiting_threads;
149 typedef unsigned (__stdcall *PTHREAD_START) (void *);
153 typedef void *(*vlc_thread_func_t)(void *p_data);
155 /*****************************************************************************
157 *****************************************************************************/
159 /* Message functions - this is kludgy because we are included before
160 * modules_export.h */
162 # define intf_ErrMsg p_symbols->intf_ErrMsg
163 # define intf_WarnMsg p_symbols->intf_WarnMsg
167 /* Wrapper function for profiling */
168 static void * vlc_thread_wrapper ( void *p_wrapper );
170 typedef struct wrapper_s
172 /* Data lock access */
176 /* Data used to spawn the real thread */
177 vlc_thread_func_t func;
180 /* Profiling timer passed to the thread */
181 struct itimerval itimer;
188 struct timeval it_value;
189 struct timeval it_interval;
192 int setitimer(int kind, const struct itimerval* itnew,
193 struct itimerval* itold);
195 #define ITIMER_REAL 1
196 #define ITIMER_PROF 2
202 /*****************************************************************************
203 * vlc_threads_init: initialize threads system
204 *****************************************************************************/
205 static __inline__ int vlc_threads_init( void )
207 #if defined( PTH_INIT_IN_PTH_H )
210 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
213 #elif defined( HAVE_CTHREADS_H )
216 #elif defined( HAVE_KERNEL_SCHEDULER_H )
219 #elif defined( WIN32 )
225 /*****************************************************************************
226 * vlc_threads_end: stop threads system
227 *****************************************************************************/
228 static __inline__ int vlc_threads_end( void )
230 #if defined( PTH_INIT_IN_PTH_H )
233 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
236 #elif defined( HAVE_CTHREADS_H )
239 #elif defined( HAVE_KERNEL_SCHEDULER_H )
242 #elif defined( WIN32 )
248 /*****************************************************************************
249 * vlc_mutex_init: initialize a mutex
250 *****************************************************************************/
251 static __inline__ int vlc_mutex_init( vlc_mutex_t *p_mutex )
253 #if defined( PTH_INIT_IN_PTH_H )
254 return pth_mutex_init( p_mutex );
256 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
257 # if defined(DEBUG) && defined(SYS_LINUX)
258 /* Create error-checking mutex to detect threads problems more easily. */
259 pthread_mutexattr_t attr;
262 pthread_mutexattr_init( &attr );
263 pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ERRORCHECK_NP );
264 i_result = pthread_mutex_init( p_mutex, &attr );
265 pthread_mutexattr_destroy( &attr );
269 return pthread_mutex_init( p_mutex, NULL );
271 #elif defined( HAVE_CTHREADS_H )
272 mutex_init( p_mutex );
275 #elif defined( HAVE_KERNEL_SCHEDULER_H )
277 /* check the arguments and whether it's already been initialized */
278 if( p_mutex == NULL )
283 if( p_mutex->init == 9999 )
288 p_mutex->lock = create_sem( 1, "BeMutex" );
289 if( p_mutex->lock < B_NO_ERROR )
294 p_mutex->init = 9999;
297 #elif defined( WIN32 )
298 InitializeCriticalSection( p_mutex );
304 /*****************************************************************************
305 * vlc_mutex_lock: lock a mutex
306 *****************************************************************************/
308 # define vlc_mutex_lock( P_MUTEX ) \
309 _vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
311 # define vlc_mutex_lock( P_MUTEX ) \
312 _vlc_mutex_lock( NULL, 0, P_MUTEX )
315 static __inline__ int _vlc_mutex_lock( char * psz_file, int i_line,
316 vlc_mutex_t *p_mutex )
318 #if defined( PTH_INIT_IN_PTH_H )
319 return pth_mutex_acquire( p_mutex, TRUE, NULL );
321 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
322 int i_return = pthread_mutex_lock( p_mutex );
325 intf_ErrMsg( "thread %d error: mutex_lock failed at %s:%d (%s)",
326 pthread_self(), psz_file, i_line, strerror(i_return) );
330 #elif defined( HAVE_CTHREADS_H )
331 mutex_lock( p_mutex );
334 #elif defined( HAVE_KERNEL_SCHEDULER_H )
342 if( p_mutex->init < 2000 )
347 err = acquire_sem( p_mutex->lock );
350 #elif defined( WIN32 )
351 EnterCriticalSection( p_mutex );
357 /*****************************************************************************
358 * vlc_mutex_unlock: unlock a mutex
359 *****************************************************************************/
361 # define vlc_mutex_unlock( P_MUTEX ) \
362 _vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
364 # define vlc_mutex_unlock( P_MUTEX ) \
365 _vlc_mutex_unlock( NULL, 0, P_MUTEX )
368 static __inline__ int _vlc_mutex_unlock( char * psz_file, int i_line,
369 vlc_mutex_t *p_mutex )
371 #if defined( PTH_INIT_IN_PTH_H )
372 return pth_mutex_release( p_mutex );
374 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
375 int i_return = pthread_mutex_unlock( p_mutex );
378 intf_ErrMsg( "thread %d error: mutex_unlock failed at %s:%d (%s)",
379 pthread_self(), psz_file, i_line, strerror(i_return) );
383 #elif defined( HAVE_CTHREADS_H )
384 mutex_unlock( p_mutex );
387 #elif defined( HAVE_KERNEL_SCHEDULER_H )
393 if( p_mutex->init < 2000 )
398 release_sem( p_mutex->lock );
401 #elif defined( WIN32 )
402 LeaveCriticalSection( p_mutex );
408 /*****************************************************************************
409 * vlc_mutex_destroy: destroy a mutex
410 *****************************************************************************/
412 # define vlc_mutex_destroy( P_MUTEX ) \
413 _vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
415 # define vlc_mutex_destroy( P_MUTEX ) \
416 _vlc_mutex_destroy( NULL, 0, P_MUTEX )
419 static __inline__ int _vlc_mutex_destroy( char * psz_file, int i_line,
420 vlc_mutex_t *p_mutex )
422 #if defined( PTH_INIT_IN_PTH_H )
425 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
426 int i_return = pthread_mutex_destroy( p_mutex );
429 intf_ErrMsg( "thread %d error: mutex_destroy failed at %s:%d (%s)",
430 pthread_self(), psz_file, i_line, strerror(i_return) );
434 #elif defined( HAVE_CTHREADS_H )
437 #elif defined( HAVE_KERNEL_SCHEDULER_H )
438 if( p_mutex->init == 9999 )
440 delete_sem( p_mutex->lock );
446 #elif defined( WIN32 )
447 DeleteCriticalSection( p_mutex );
453 /*****************************************************************************
454 * vlc_cond_init: initialize a condition
455 *****************************************************************************/
456 static __inline__ int vlc_cond_init( vlc_cond_t *p_condvar )
458 #if defined( PTH_INIT_IN_PTH_H )
459 return pth_cond_init( p_condvar );
461 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
462 return pthread_cond_init( p_condvar, NULL );
464 #elif defined( HAVE_CTHREADS_H )
465 /* condition_init() */
466 spin_lock_init( &p_condvar->lock );
467 cthread_queue_init( &p_condvar->queue );
469 p_condvar->implications = 0;
473 #elif defined( HAVE_KERNEL_SCHEDULER_H )
479 if( p_condvar->init == 9999 )
484 p_condvar->thread = -1;
485 p_condvar->init = 9999;
488 #elif defined( WIN32 )
489 /* initialise counter */
490 p_condvar->i_waiting_threads = 0;
492 /* Create an auto-reset event. */
493 p_condvar->signal = CreateEvent( NULL, /* no security */
494 FALSE, /* auto-reset event */
495 FALSE, /* non-signaled initially */
496 NULL ); /* unnamed */
498 return( !p_condvar->signal );
503 /*****************************************************************************
504 * vlc_cond_signal: start a thread on condition completion
505 *****************************************************************************/
506 static __inline__ int vlc_cond_signal( vlc_cond_t *p_condvar )
508 #if defined( PTH_INIT_IN_PTH_H )
509 return pth_cond_notify( p_condvar, FALSE );
511 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
512 return pthread_cond_signal( p_condvar );
514 #elif defined( HAVE_CTHREADS_H )
515 /* condition_signal() */
516 if ( p_condvar->queue.head || p_condvar->implications )
518 cond_signal( (condition_t)p_condvar );
522 #elif defined( HAVE_KERNEL_SCHEDULER_H )
528 if( p_condvar->init < 2000 )
533 while( p_condvar->thread != -1 )
536 if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
541 if( info.state != B_THREAD_SUSPENDED )
543 /* The waiting thread is not suspended so it could
544 * have been interrupted beetwen the unlock and the
545 * suspend_thread line. That is why we sleep a little
546 * before retesting p_condver->thread. */
551 /* Ok, we have to wake up that thread */
552 resume_thread( p_condvar->thread );
558 #elif defined( WIN32 )
559 /* Release one waiting thread if one is available. */
560 /* For this trick to work properly, the vlc_cond_signal must be surrounded
561 * by a mutex. This will prevent another thread from stealing the signal */
562 int i_waiting_threads = p_condvar->i_waiting_threads;
563 while( p_condvar->i_waiting_threads
564 && p_condvar->i_waiting_threads == i_waiting_threads )
566 PulseEvent( p_condvar->signal );
567 Sleep( 0 ); /* deschedule the current thread */
574 /*****************************************************************************
575 * vlc_cond_broadcast: start all threads waiting on condition completion
576 *****************************************************************************/
578 * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
579 * Only works with pthreads, you need to adapt it for others
580 * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
582 static __inline__ int vlc_cond_broadcast( vlc_cond_t *p_condvar )
584 #if defined( PTH_INIT_IN_PTH_H )
585 return pth_cond_notify( p_condvar, FALSE );
587 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
588 return pthread_cond_broadcast( p_condvar );
590 #elif defined( HAVE_CTHREADS_H )
591 /* condition_signal() */
592 if ( p_condvar->queue.head || p_condvar->implications )
594 cond_signal( (condition_t)p_condvar );
598 #elif defined( HAVE_KERNEL_SCHEDULER_H )
604 if( p_condvar->init < 2000 )
609 while( p_condvar->thread != -1 )
612 if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
617 if( info.state != B_THREAD_SUSPENDED )
619 /* The waiting thread is not suspended so it could
620 * have been interrupted beetwen the unlock and the
621 * suspend_thread line. That is why we sleep a little
622 * before retesting p_condver->thread. */
627 /* Ok, we have to wake up that thread */
628 resume_thread( p_condvar->thread );
634 #elif defined( WIN32 )
635 /* Release all waiting threads. */
636 /* For this trick to work properly, the vlc_cond_signal must be surrounded
637 * by a mutex. This will prevent another thread from stealing the signal */
638 while( p_condvar->i_waiting_threads )
640 PulseEvent( p_condvar->signal );
641 Sleep( 0 ); /* deschedule the current thread */
648 /*****************************************************************************
649 * vlc_cond_wait: wait until condition completion
650 *****************************************************************************/
652 # define vlc_cond_wait( P_COND, P_MUTEX ) \
653 _vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX )
655 # define vlc_cond_wait( P_COND, P_MUTEX ) \
656 _vlc_cond_wait( NULL, 0, P_COND, P_MUTEX )
659 static __inline__ int _vlc_cond_wait( char * psz_file, int i_line,
660 vlc_cond_t *p_condvar,
661 vlc_mutex_t *p_mutex )
663 #if defined( PTH_INIT_IN_PTH_H )
664 return pth_cond_await( p_condvar, p_mutex, NULL );
666 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
669 return pthread_cond_wait( p_condvar, p_mutex );
671 /* In debug mode, timeout */
673 struct timespec timeout;
678 gettimeofday( &now, NULL );
679 timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT;
680 timeout.tv_nsec = now.tv_usec * 1000;
682 if( (i_result = pthread_cond_timedwait( p_condvar, p_mutex, &timeout )) )
684 intf_WarnMsg( 1, "thread %d warning: Possible deadlock detected in cond_wait at %s:%d (%s)",
685 pthread_self(), psz_file, i_line, strerror(i_result) );
694 #elif defined( HAVE_CTHREADS_H )
695 condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
698 #elif defined( HAVE_KERNEL_SCHEDULER_H )
709 if( p_condvar->init < 2000 )
714 /* The p_condvar->thread var is initialized before the unlock because
715 * it enables to identify when the thread is interrupted beetwen the
716 * unlock line and the suspend_thread line */
717 p_condvar->thread = find_thread( NULL );
718 vlc_mutex_unlock( p_mutex );
719 suspend_thread( p_condvar->thread );
720 p_condvar->thread = -1;
722 vlc_mutex_lock( p_mutex );
725 #elif defined( WIN32 )
726 /* The ideal would be to use a function which atomically releases the
727 * mutex and initiate the waiting.
728 * Unfortunately only the SignalObjectAndWait function does this and it's
729 * only supported on WinNT/2K, furthermore it cannot take multiple
730 * events as parameters.
732 * The solution we use should however fulfill all our needs (even though
733 * it is not a correct pthreads implementation)
737 p_condvar->i_waiting_threads ++;
739 /* Release the mutex */
740 vlc_mutex_unlock( p_mutex );
742 i_result = WaitForSingleObject( p_condvar->signal, INFINITE);
744 /* maybe we should protect this with a mutex ? */
745 p_condvar->i_waiting_threads --;
747 /* Reacquire the mutex before returning. */
748 vlc_mutex_lock( p_mutex );
750 return( i_result == WAIT_FAILED );
755 /*****************************************************************************
756 * vlc_cond_destroy: destroy a condition
757 *****************************************************************************/
759 # define vlc_cond_destroy( P_COND ) \
760 _vlc_cond_destroy( __FILE__, __LINE__, P_COND )
762 # define vlc_cond_destroy( P_COND ) \
763 _vlc_cond_destroy( NULL, 0, P_COND )
766 static __inline__ int _vlc_cond_destroy( char * psz_file, int i_line,
767 vlc_cond_t *p_condvar )
769 #if defined( PTH_INIT_IN_PTH_H )
772 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
773 int i_result = pthread_cond_destroy( p_condvar );
776 intf_ErrMsg( "thread %d error: cond_destroy failed at %s:%d (%s)",
777 pthread_self(), psz_file, i_line, strerror(i_result) );
781 #elif defined( HAVE_CTHREADS_H )
784 #elif defined( HAVE_KERNEL_SCHEDULER_H )
788 #elif defined( WIN32 )
789 return( !CloseHandle( p_condvar->signal ) );
794 /*****************************************************************************
795 * vlc_thread_create: create a thread
796 *****************************************************************************/
798 # define vlc_thread_create( P_THREAD, PSZ_NAME, FUNC, P_DATA ) \
799 _vlc_thread_create( __FILE__, __LINE__, P_THREAD, PSZ_NAME, FUNC, P_DATA )
801 # define vlc_thread_create( P_THREAD, PSZ_NAME, FUNC, P_DATA ) \
802 _vlc_thread_create( NULL, 0, P_THREAD, PSZ_NAME, FUNC, P_DATA )
805 static __inline__ int _vlc_thread_create( char * psz_file, int i_line,
806 vlc_thread_t *p_thread,
808 vlc_thread_func_t func,
816 /* Initialize the wrapper structure */
818 wrapper.p_data = p_data;
819 getitimer( ITIMER_PROF, &wrapper.itimer );
820 vlc_mutex_init( &wrapper.lock );
821 vlc_cond_init( &wrapper.wait );
822 vlc_mutex_lock( &wrapper.lock );
824 /* Alter user-passed data so that we call the wrapper instead
825 * of the real function */
827 func = vlc_thread_wrapper;
830 #if defined( PTH_INIT_IN_PTH_H )
831 *p_thread = pth_spawn( PTH_ATTR_DEFAULT, func, p_data );
832 i_ret = ( p_thread == NULL );
834 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
835 i_ret = pthread_create( p_thread, NULL, func, p_data );
837 #elif defined( HAVE_CTHREADS_H )
838 *p_thread = cthread_fork( (cthread_fn_t)func, (any_t)p_data );
841 #elif defined( HAVE_KERNEL_SCHEDULER_H )
842 *p_thread = spawn_thread( (thread_func)func, psz_name,
843 B_NORMAL_PRIORITY, p_data );
844 i_ret = resume_thread( *p_thread );
846 #elif defined( WIN32 )
849 /* This method is not recommended when using the MSVCRT C library,
850 * so we'll have to use _beginthreadex instead */
851 *p_thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) func,
852 p_data, 0, &threadID);
855 /* When using the MSVCRT C library you have to use the _beginthreadex
856 * function instead of CreateThread, otherwise you'll end up with memory
857 * leaks and the signal function not working */
858 *p_thread = (HANDLE)_beginthreadex(NULL, 0, (PTHREAD_START) func,
859 p_data, 0, &threadID);
861 i_ret = ( *p_thread ? 0 : 1 );
868 vlc_cond_wait( &wrapper.wait, &wrapper.lock );
871 vlc_mutex_unlock( &wrapper.lock );
872 vlc_mutex_destroy( &wrapper.lock );
873 vlc_cond_destroy( &wrapper.wait );
878 intf_WarnMsg( 2, "thread info: %d (%s) has been created (%s:%d)",
879 *p_thread, psz_name, psz_file, i_line );
883 intf_ErrMsg( "thread error: %s couldn't be created at %s:%d (%s)",
884 psz_name, psz_file, i_line, strerror(i_ret) );
890 /*****************************************************************************
891 * vlc_thread_exit: terminate a thread
892 *****************************************************************************/
893 static __inline__ void vlc_thread_exit( void )
895 #if defined( PTH_INIT_IN_PTH_H )
898 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
901 #elif defined( HAVE_CTHREADS_H )
903 cthread_exit( &result );
905 #elif defined( HAVE_KERNEL_SCHEDULER_H )
908 #elif defined( WIN32 )
912 /* For now we don't close the thread handles (because of race conditions).
913 * Need to be looked at. */
919 /*****************************************************************************
920 * vlc_thread_join: wait until a thread exits
921 *****************************************************************************/
923 # define vlc_thread_join( THREAD ) \
924 _vlc_thread_join( __FILE__, __LINE__, THREAD )
926 # define vlc_thread_join( THREAD ) \
927 _vlc_thread_join( NULL, 0, THREAD )
930 static __inline__ void _vlc_thread_join( char * psz_file, int i_line,
931 vlc_thread_t thread )
935 #if defined( PTH_INIT_IN_PTH_H )
936 i_ret = pth_join( thread, NULL );
938 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
939 i_ret = pthread_join( thread, NULL );
941 #elif defined( HAVE_CTHREADS_H )
942 i_ret = cthread_join( thread );
944 #elif defined( HAVE_KERNEL_SCHEDULER_H )
946 wait_for_thread( thread, &exit_value );
948 #elif defined( WIN32 )
949 WaitForSingleObject( thread, INFINITE );
955 intf_ErrMsg( "thread error: thread_join(%d) failed at %s:%d (%s)",
956 thread, psz_file, i_line, strerror(i_ret) );
960 intf_WarnMsg( 2, "thread info: %d has been joined (%s:%d)",
961 thread, psz_file, i_line );
966 static void *vlc_thread_wrapper( void *p_wrapper )
968 /* Put user data in thread-local variables */
969 void * p_data = ((wrapper_t*)p_wrapper)->p_data;
970 vlc_thread_func_t func = ((wrapper_t*)p_wrapper)->func;
972 /* Set the profile timer value */
973 setitimer( ITIMER_PROF, &((wrapper_t*)p_wrapper)->itimer, NULL );
975 /* Tell the calling thread that we don't need its data anymore */
976 vlc_mutex_lock( &((wrapper_t*)p_wrapper)->lock );
977 vlc_cond_signal( &((wrapper_t*)p_wrapper)->wait );
978 vlc_mutex_unlock( &((wrapper_t*)p_wrapper)->lock );
980 /* Call the real function */
981 return func( p_data );