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.34 2002/01/04 14:01:34 sam 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 *****************************************************************************/
160 /* Wrapper function for profiling */
161 static void * vlc_thread_wrapper ( void *p_wrapper );
165 # define ITIMER_REAL 1
166 # define ITIMER_PROF 2
170 struct timeval it_value;
171 struct timeval it_interval;
174 int setitimer(int kind, const struct itimerval* itnew, struct itimerval* itold);
178 typedef struct wrapper_s
180 /* Data lock access */
184 /* Data used to spawn the real thread */
185 vlc_thread_func_t func;
188 /* Profiling timer passed to the thread */
189 struct itimerval itimer;
195 /*****************************************************************************
196 * vlc_threads_init: initialize threads system
197 *****************************************************************************/
198 static __inline__ int vlc_threads_init( void )
200 #if defined( PTH_INIT_IN_PTH_H )
203 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
206 #elif defined( HAVE_CTHREADS_H )
209 #elif defined( HAVE_KERNEL_SCHEDULER_H )
212 #elif defined( WIN32 )
218 /*****************************************************************************
219 * vlc_threads_end: stop threads system
220 *****************************************************************************/
221 static __inline__ int vlc_threads_end( void )
223 #if defined( PTH_INIT_IN_PTH_H )
226 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
229 #elif defined( HAVE_CTHREADS_H )
232 #elif defined( HAVE_KERNEL_SCHEDULER_H )
235 #elif defined( WIN32 )
241 /*****************************************************************************
242 * vlc_mutex_init: initialize a mutex
243 *****************************************************************************/
244 static __inline__ int vlc_mutex_init( vlc_mutex_t *p_mutex )
246 #if defined( PTH_INIT_IN_PTH_H )
247 return pth_mutex_init( p_mutex );
249 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
250 # if defined(DEBUG) && defined(SYS_LINUX)
251 /* Create error-checking mutex to detect threads problems more easily. */
252 pthread_mutexattr_t attr;
255 pthread_mutexattr_init( &attr );
256 pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ERRORCHECK_NP );
257 i_result = pthread_mutex_init( p_mutex, &attr );
258 pthread_mutexattr_destroy( &attr );
262 return pthread_mutex_init( p_mutex, NULL );
264 #elif defined( HAVE_CTHREADS_H )
265 mutex_init( p_mutex );
268 #elif defined( HAVE_KERNEL_SCHEDULER_H )
270 /* check the arguments and whether it's already been initialized */
271 if( p_mutex == NULL )
276 if( p_mutex->init == 9999 )
281 p_mutex->lock = create_sem( 1, "BeMutex" );
282 if( p_mutex->lock < B_NO_ERROR )
287 p_mutex->init = 9999;
290 #elif defined( WIN32 )
291 InitializeCriticalSection( p_mutex );
297 /*****************************************************************************
298 * vlc_mutex_lock: lock a mutex
299 *****************************************************************************/
301 # define vlc_mutex_lock( P_MUTEX ) \
302 _vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
304 # define vlc_mutex_lock( P_MUTEX ) \
305 _vlc_mutex_lock( NULL, 0, P_MUTEX )
308 static __inline__ int _vlc_mutex_lock( char * psz_file, int i_line,
309 vlc_mutex_t *p_mutex )
311 #if defined( PTH_INIT_IN_PTH_H )
312 return pth_mutex_acquire( p_mutex, TRUE, NULL );
314 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
315 int i_return = pthread_mutex_lock( p_mutex );
318 intf_ErrMsg( "thread %d error: mutex_lock failed at %s:%d (%s)",
319 pthread_self(), psz_file, i_line, strerror(i_return) );
323 #elif defined( HAVE_CTHREADS_H )
324 mutex_lock( p_mutex );
327 #elif defined( HAVE_KERNEL_SCHEDULER_H )
335 if( p_mutex->init < 2000 )
340 err = acquire_sem( p_mutex->lock );
343 #elif defined( WIN32 )
344 EnterCriticalSection( p_mutex );
350 /*****************************************************************************
351 * vlc_mutex_unlock: unlock a mutex
352 *****************************************************************************/
354 # define vlc_mutex_unlock( P_MUTEX ) \
355 _vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
357 # define vlc_mutex_unlock( P_MUTEX ) \
358 _vlc_mutex_unlock( NULL, 0, P_MUTEX )
361 static __inline__ int _vlc_mutex_unlock( char * psz_file, int i_line,
362 vlc_mutex_t *p_mutex )
364 #if defined( PTH_INIT_IN_PTH_H )
365 return pth_mutex_release( p_mutex );
367 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
368 int i_return = pthread_mutex_unlock( p_mutex );
371 intf_ErrMsg( "thread %d error: mutex_unlock failed at %s:%d (%s)",
372 pthread_self(), psz_file, i_line, strerror(i_return) );
376 #elif defined( HAVE_CTHREADS_H )
377 mutex_unlock( p_mutex );
380 #elif defined( HAVE_KERNEL_SCHEDULER_H )
386 if( p_mutex->init < 2000 )
391 release_sem( p_mutex->lock );
394 #elif defined( WIN32 )
395 LeaveCriticalSection( p_mutex );
401 /*****************************************************************************
402 * vlc_mutex_destroy: destroy a mutex
403 *****************************************************************************/
405 # define vlc_mutex_destroy( P_MUTEX ) \
406 _vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
408 # define vlc_mutex_destroy( P_MUTEX ) \
409 _vlc_mutex_destroy( NULL, 0, P_MUTEX )
412 static __inline__ int _vlc_mutex_destroy( char * psz_file, int i_line,
413 vlc_mutex_t *p_mutex )
415 #if defined( PTH_INIT_IN_PTH_H )
418 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
419 int i_return = pthread_mutex_destroy( p_mutex );
422 intf_ErrMsg( "thread %d error: mutex_destroy failed at %s:%d (%s)",
423 pthread_self(), psz_file, i_line, strerror(i_return) );
427 #elif defined( HAVE_CTHREADS_H )
430 #elif defined( HAVE_KERNEL_SCHEDULER_H )
431 if( p_mutex->init == 9999 )
433 delete_sem( p_mutex->lock );
439 #elif defined( WIN32 )
440 DeleteCriticalSection( p_mutex );
446 /*****************************************************************************
447 * vlc_cond_init: initialize a condition
448 *****************************************************************************/
449 static __inline__ int vlc_cond_init( vlc_cond_t *p_condvar )
451 #if defined( PTH_INIT_IN_PTH_H )
452 return pth_cond_init( p_condvar );
454 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
455 return pthread_cond_init( p_condvar, NULL );
457 #elif defined( HAVE_CTHREADS_H )
458 /* condition_init() */
459 spin_lock_init( &p_condvar->lock );
460 cthread_queue_init( &p_condvar->queue );
462 p_condvar->implications = 0;
466 #elif defined( HAVE_KERNEL_SCHEDULER_H )
472 if( p_condvar->init == 9999 )
477 p_condvar->thread = -1;
478 p_condvar->init = 9999;
481 #elif defined( WIN32 )
482 /* initialise counter */
483 p_condvar->i_waiting_threads = 0;
485 /* Create an auto-reset event. */
486 p_condvar->signal = CreateEvent( NULL, /* no security */
487 FALSE, /* auto-reset event */
488 FALSE, /* non-signaled initially */
489 NULL ); /* unnamed */
491 return( !p_condvar->signal );
496 /*****************************************************************************
497 * vlc_cond_signal: start a thread on condition completion
498 *****************************************************************************/
499 static __inline__ int vlc_cond_signal( vlc_cond_t *p_condvar )
501 #if defined( PTH_INIT_IN_PTH_H )
502 return pth_cond_notify( p_condvar, FALSE );
504 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
505 return pthread_cond_signal( p_condvar );
507 #elif defined( HAVE_CTHREADS_H )
508 /* condition_signal() */
509 if ( p_condvar->queue.head || p_condvar->implications )
511 cond_signal( (condition_t)p_condvar );
515 #elif defined( HAVE_KERNEL_SCHEDULER_H )
521 if( p_condvar->init < 2000 )
526 while( p_condvar->thread != -1 )
529 if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
534 if( info.state != B_THREAD_SUSPENDED )
536 /* The waiting thread is not suspended so it could
537 * have been interrupted beetwen the unlock and the
538 * suspend_thread line. That is why we sleep a little
539 * before retesting p_condver->thread. */
544 /* Ok, we have to wake up that thread */
545 resume_thread( p_condvar->thread );
551 #elif defined( WIN32 )
552 /* Release one waiting thread if one is available. */
553 /* For this trick to work properly, the vlc_cond_signal must be surrounded
554 * by a mutex. This will prevent another thread from stealing the signal */
555 int i_waiting_threads = p_condvar->i_waiting_threads;
556 while( p_condvar->i_waiting_threads
557 && p_condvar->i_waiting_threads == i_waiting_threads )
559 PulseEvent( p_condvar->signal );
560 Sleep( 0 ); /* deschedule the current thread */
567 /*****************************************************************************
568 * vlc_cond_broadcast: start all threads waiting on condition completion
569 *****************************************************************************/
571 * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
572 * Only works with pthreads, you need to adapt it for others
573 * FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
575 static __inline__ int vlc_cond_broadcast( vlc_cond_t *p_condvar )
577 #if defined( PTH_INIT_IN_PTH_H )
578 return pth_cond_notify( p_condvar, FALSE );
580 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
581 return pthread_cond_broadcast( p_condvar );
583 #elif defined( HAVE_CTHREADS_H )
584 /* condition_signal() */
585 if ( p_condvar->queue.head || p_condvar->implications )
587 cond_signal( (condition_t)p_condvar );
591 #elif defined( HAVE_KERNEL_SCHEDULER_H )
597 if( p_condvar->init < 2000 )
602 while( p_condvar->thread != -1 )
605 if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
610 if( info.state != B_THREAD_SUSPENDED )
612 /* The waiting thread is not suspended so it could
613 * have been interrupted beetwen the unlock and the
614 * suspend_thread line. That is why we sleep a little
615 * before retesting p_condver->thread. */
620 /* Ok, we have to wake up that thread */
621 resume_thread( p_condvar->thread );
627 #elif defined( WIN32 )
628 /* Release all waiting threads. */
629 /* For this trick to work properly, the vlc_cond_signal must be surrounded
630 * by a mutex. This will prevent another thread from stealing the signal */
631 while( p_condvar->i_waiting_threads )
633 PulseEvent( p_condvar->signal );
634 Sleep( 0 ); /* deschedule the current thread */
641 /*****************************************************************************
642 * vlc_cond_wait: wait until condition completion
643 *****************************************************************************/
645 # define vlc_cond_wait( P_COND, P_MUTEX ) \
646 _vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX )
648 # define vlc_cond_wait( P_COND, P_MUTEX ) \
649 _vlc_cond_wait( NULL, 0, P_COND, P_MUTEX )
652 static __inline__ int _vlc_cond_wait( char * psz_file, int i_line,
653 vlc_cond_t *p_condvar,
654 vlc_mutex_t *p_mutex )
656 #if defined( PTH_INIT_IN_PTH_H )
657 return pth_cond_await( p_condvar, p_mutex, NULL );
659 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
662 return pthread_cond_wait( p_condvar, p_mutex );
664 /* In debug mode, timeout */
666 struct timespec timeout;
671 gettimeofday( &now, NULL );
672 timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT;
673 timeout.tv_nsec = now.tv_usec * 1000;
675 if( (i_result = pthread_cond_timedwait( p_condvar, p_mutex, &timeout )) )
677 intf_WarnMsg( 1, "thread %d warning: Possible deadlock detected in cond_wait at %s:%d (%s)",
678 pthread_self(), psz_file, i_line, strerror(i_result) );
687 #elif defined( HAVE_CTHREADS_H )
688 condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
691 #elif defined( HAVE_KERNEL_SCHEDULER_H )
702 if( p_condvar->init < 2000 )
707 /* The p_condvar->thread var is initialized before the unlock because
708 * it enables to identify when the thread is interrupted beetwen the
709 * unlock line and the suspend_thread line */
710 p_condvar->thread = find_thread( NULL );
711 vlc_mutex_unlock( p_mutex );
712 suspend_thread( p_condvar->thread );
713 p_condvar->thread = -1;
715 vlc_mutex_lock( p_mutex );
718 #elif defined( WIN32 )
719 /* The ideal would be to use a function which atomically releases the
720 * mutex and initiate the waiting.
721 * Unfortunately only the SignalObjectAndWait function does this and it's
722 * only supported on WinNT/2K, furthermore it cannot take multiple
723 * events as parameters.
725 * The solution we use should however fulfill all our needs (even though
726 * it is not a correct pthreads implementation)
730 p_condvar->i_waiting_threads ++;
732 /* Release the mutex */
733 vlc_mutex_unlock( p_mutex );
735 i_result = WaitForSingleObject( p_condvar->signal, INFINITE);
737 /* maybe we should protect this with a mutex ? */
738 p_condvar->i_waiting_threads --;
740 /* Reacquire the mutex before returning. */
741 vlc_mutex_lock( p_mutex );
743 return( i_result == WAIT_FAILED );
748 /*****************************************************************************
749 * vlc_cond_destroy: destroy a condition
750 *****************************************************************************/
752 # define vlc_cond_destroy( P_COND ) \
753 _vlc_cond_destroy( __FILE__, __LINE__, P_COND )
755 # define vlc_cond_destroy( P_COND ) \
756 _vlc_cond_destroy( NULL, 0, P_COND )
759 static __inline__ int _vlc_cond_destroy( char * psz_file, int i_line,
760 vlc_cond_t *p_condvar )
762 #if defined( PTH_INIT_IN_PTH_H )
765 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
766 int i_result = pthread_cond_destroy( p_condvar );
769 intf_ErrMsg( "thread %d error: cond_destroy failed at %s:%d (%s)",
770 pthread_self(), psz_file, i_line, strerror(i_result) );
774 #elif defined( HAVE_CTHREADS_H )
777 #elif defined( HAVE_KERNEL_SCHEDULER_H )
781 #elif defined( WIN32 )
782 return( !CloseHandle( p_condvar->signal ) );
787 /*****************************************************************************
788 * vlc_thread_create: create a thread
789 *****************************************************************************/
791 # define vlc_thread_create( P_THREAD, PSZ_NAME, FUNC, P_DATA ) \
792 _vlc_thread_create( __FILE__, __LINE__, P_THREAD, PSZ_NAME, FUNC, P_DATA )
794 # define vlc_thread_create( P_THREAD, PSZ_NAME, FUNC, P_DATA ) \
795 _vlc_thread_create( NULL, 0, P_THREAD, PSZ_NAME, FUNC, P_DATA )
798 static __inline__ int _vlc_thread_create( char * psz_file, int i_line,
799 vlc_thread_t *p_thread,
801 vlc_thread_func_t func,
809 /* Initialize the wrapper structure */
811 wrapper.p_data = p_data;
812 getitimer( ITIMER_PROF, &wrapper.itimer );
813 vlc_mutex_init( &wrapper.lock );
814 vlc_cond_init( &wrapper.wait );
815 vlc_mutex_lock( &wrapper.lock );
817 /* Alter user-passed data so that we call the wrapper instead
818 * of the real function */
820 func = vlc_thread_wrapper;
823 #if defined( PTH_INIT_IN_PTH_H )
824 *p_thread = pth_spawn( PTH_ATTR_DEFAULT, func, p_data );
825 i_ret = ( p_thread == NULL );
827 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
828 i_ret = pthread_create( p_thread, NULL, func, p_data );
830 #elif defined( HAVE_CTHREADS_H )
831 *p_thread = cthread_fork( (cthread_fn_t)func, (any_t)p_data );
834 #elif defined( HAVE_KERNEL_SCHEDULER_H )
835 *p_thread = spawn_thread( (thread_func)func, psz_name,
836 B_NORMAL_PRIORITY, p_data );
837 i_ret = resume_thread( *p_thread );
839 #elif defined( WIN32 )
842 /* This method is not recommended when using the MSVCRT C library,
843 * so we'll have to use _beginthreadex instead */
844 *p_thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) func,
845 p_data, 0, &threadID);
848 /* When using the MSVCRT C library you have to use the _beginthreadex
849 * function instead of CreateThread, otherwise you'll end up with memory
850 * leaks and the signal function not working */
851 *p_thread = (HANDLE)_beginthreadex(NULL, 0, (PTHREAD_START) func,
852 p_data, 0, &threadID);
854 i_ret = ( *p_thread ? 0 : 1 );
861 vlc_cond_wait( &wrapper.wait, &wrapper.lock );
864 vlc_mutex_unlock( &wrapper.lock );
865 vlc_mutex_destroy( &wrapper.lock );
866 vlc_cond_destroy( &wrapper.wait );
871 intf_WarnMsg( 2, "thread info: %d (%s) has been created (%s:%d)",
872 *p_thread, psz_name, psz_file, i_line );
876 intf_ErrMsg( "thread error: %s couldn't be created at %s:%d (%s)",
877 psz_name, psz_file, i_line, strerror(i_ret) );
883 /*****************************************************************************
884 * vlc_thread_exit: terminate a thread
885 *****************************************************************************/
886 static __inline__ void vlc_thread_exit( void )
888 #if defined( PTH_INIT_IN_PTH_H )
891 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
894 #elif defined( HAVE_CTHREADS_H )
896 cthread_exit( &result );
898 #elif defined( HAVE_KERNEL_SCHEDULER_H )
901 #elif defined( WIN32 )
905 /* For now we don't close the thread handles (because of race conditions).
906 * Need to be looked at. */
912 /*****************************************************************************
913 * vlc_thread_join: wait until a thread exits
914 *****************************************************************************/
916 # define vlc_thread_join( THREAD ) \
917 _vlc_thread_join( __FILE__, __LINE__, THREAD )
919 # define vlc_thread_join( THREAD ) \
920 _vlc_thread_join( NULL, 0, THREAD )
923 static __inline__ void _vlc_thread_join( char * psz_file, int i_line,
924 vlc_thread_t thread )
928 #if defined( PTH_INIT_IN_PTH_H )
929 i_ret = pth_join( thread, NULL );
931 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
932 i_ret = pthread_join( thread, NULL );
934 #elif defined( HAVE_CTHREADS_H )
935 cthread_join( thread );
938 #elif defined( HAVE_KERNEL_SCHEDULER_H )
940 wait_for_thread( thread, &exit_value );
942 #elif defined( WIN32 )
943 WaitForSingleObject( thread, INFINITE );
949 intf_ErrMsg( "thread error: thread_join(%d) failed at %s:%d (%s)",
950 thread, psz_file, i_line, strerror(i_ret) );
954 intf_WarnMsg( 2, "thread info: %d has been joined (%s:%d)",
955 thread, psz_file, i_line );
960 static void *vlc_thread_wrapper( void *p_wrapper )
962 /* Put user data in thread-local variables */
963 void * p_data = ((wrapper_t*)p_wrapper)->p_data;
964 vlc_thread_func_t func = ((wrapper_t*)p_wrapper)->func;
966 /* Set the profile timer value */
967 setitimer( ITIMER_PROF, &((wrapper_t*)p_wrapper)->itimer, NULL );
969 /* Tell the calling thread that we don't need its data anymore */
970 vlc_mutex_lock( &((wrapper_t*)p_wrapper)->lock );
971 vlc_cond_signal( &((wrapper_t*)p_wrapper)->wait );
972 vlc_mutex_unlock( &((wrapper_t*)p_wrapper)->lock );
974 /* Call the real function */
975 return func( p_data );