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 $
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( ST_INIT_IN_ST_H ) /* State threads */
38 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) /* pthreads (like Linux & BSD) */
41 /* Needed for pthread_cond_timedwait */
44 /* This is not prototyped under Linux, though it exists. */
45 int pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind );
47 #elif defined( HAVE_CTHREADS_H ) /* GNUMach */
48 # include <cthreads.h>
50 #elif defined( HAVE_KERNEL_SCHEDULER_H ) /* BeOS */
51 # include <kernel/OS.h>
52 # include <kernel/scheduler.h>
53 # include <byteorder.h>
55 #elif defined( WIN32 )
56 #define WIN32_LEAN_AND_MEAN
61 # error no threads available on your system !
65 /*****************************************************************************
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 *****************************************************************************/
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 */
78 #define THREAD_CREATE 10 /* thread is initializing */
79 #define THREAD_START 11 /* thread has forked */
80 #define THREAD_READY 19 /* thread is ready */
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 */
88 #define THREAD_ERROR 30 /* an error occured */
89 #define THREAD_FATAL 31 /* an fatal error occured - program must end */
91 /*****************************************************************************
93 *****************************************************************************/
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;
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;
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;
110 #elif defined( HAVE_CTHREADS_H )
111 typedef cthread_t vlc_thread_t;
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 {
120 struct cthread_queue queue;
123 typedef struct s_condition {
125 struct cthread_queue queue;
127 struct cond_imp *implications;
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 */
135 typedef thread_id vlc_thread_t;
149 #elif defined( WIN32 )
150 typedef HANDLE vlc_thread_t;
151 typedef CRITICAL_SECTION vlc_mutex_t;
155 int i_waiting_threads;
159 typedef unsigned (__stdcall *PTHREAD_START) (void *);
163 typedef void *(*vlc_thread_func_t)(void *p_data);
165 /*****************************************************************************
167 *****************************************************************************/
170 /* Wrapper function for profiling */
171 static void * vlc_thread_wrapper ( void *p_wrapper );
175 # define ITIMER_REAL 1
176 # define ITIMER_PROF 2
180 struct timeval it_value;
181 struct timeval it_interval;
184 int setitimer(int kind, const struct itimerval* itnew, struct itimerval* itold);
188 typedef struct wrapper_s
190 /* Data lock access */
194 /* Data used to spawn the real thread */
195 vlc_thread_func_t func;
198 /* Profiling timer passed to the thread */
199 struct itimerval itimer;
205 /*****************************************************************************
206 * vlc_threads_init: initialize threads system
207 *****************************************************************************/
208 static __inline__ int vlc_threads_init( void )
210 #if defined( PTH_INIT_IN_PTH_H )
213 #elif defined( ST_INIT_IN_ST_H )
216 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
219 #elif defined( HAVE_CTHREADS_H )
222 #elif defined( HAVE_KERNEL_SCHEDULER_H )
225 #elif defined( WIN32 )
231 /*****************************************************************************
232 * vlc_threads_end: stop threads system
233 *****************************************************************************/
234 static __inline__ int vlc_threads_end( void )
236 #if defined( PTH_INIT_IN_PTH_H )
239 #elif defined( ST_INIT_IN_ST_H )
242 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
245 #elif defined( HAVE_CTHREADS_H )
248 #elif defined( HAVE_KERNEL_SCHEDULER_H )
251 #elif defined( WIN32 )
257 /*****************************************************************************
258 * vlc_mutex_init: initialize a mutex
259 *****************************************************************************/
260 static __inline__ int vlc_mutex_init( vlc_mutex_t *p_mutex )
262 #if defined( PTH_INIT_IN_PTH_H )
263 return pth_mutex_init( p_mutex );
265 #elif defined( ST_INIT_IN_ST_H )
266 *p_mutex = st_mutex_new();
267 return ( *p_mutex == NULL ) ? errno : 0;
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;
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 );
282 return pthread_mutex_init( p_mutex, NULL );
284 #elif defined( HAVE_CTHREADS_H )
285 mutex_init( p_mutex );
288 #elif defined( HAVE_KERNEL_SCHEDULER_H )
290 /* check the arguments and whether it's already been initialized */
291 if( p_mutex == NULL )
296 if( p_mutex->init == 9999 )
301 p_mutex->lock = create_sem( 1, "BeMutex" );
302 if( p_mutex->lock < B_NO_ERROR )
307 p_mutex->init = 9999;
310 #elif defined( WIN32 )
311 InitializeCriticalSection( p_mutex );
317 /*****************************************************************************
318 * vlc_mutex_lock: lock a mutex
319 *****************************************************************************/
321 # define vlc_mutex_lock( P_MUTEX ) \
322 _vlc_mutex_lock( __FILE__, __LINE__, P_MUTEX )
324 # define vlc_mutex_lock( P_MUTEX ) \
325 _vlc_mutex_lock( NULL, 0, P_MUTEX )
328 static __inline__ int _vlc_mutex_lock( char * psz_file, int i_line,
329 vlc_mutex_t *p_mutex )
331 #if defined( PTH_INIT_IN_PTH_H )
332 return pth_mutex_acquire( p_mutex, TRUE, NULL );
334 #elif defined( ST_INIT_IN_ST_H )
335 return st_mutex_lock( *p_mutex );
337 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
338 int i_return = pthread_mutex_lock( p_mutex );
341 intf_ErrMsg( "thread %d error: mutex_lock failed at %s:%d (%s)",
342 pthread_self(), psz_file, i_line, strerror(i_return) );
346 #elif defined( HAVE_CTHREADS_H )
347 mutex_lock( p_mutex );
350 #elif defined( HAVE_KERNEL_SCHEDULER_H )
358 if( p_mutex->init < 2000 )
363 err = acquire_sem( p_mutex->lock );
366 #elif defined( WIN32 )
367 EnterCriticalSection( p_mutex );
373 /*****************************************************************************
374 * vlc_mutex_unlock: unlock a mutex
375 *****************************************************************************/
377 # define vlc_mutex_unlock( P_MUTEX ) \
378 _vlc_mutex_unlock( __FILE__, __LINE__, P_MUTEX )
380 # define vlc_mutex_unlock( P_MUTEX ) \
381 _vlc_mutex_unlock( NULL, 0, P_MUTEX )
384 static __inline__ int _vlc_mutex_unlock( char * psz_file, int i_line,
385 vlc_mutex_t *p_mutex )
387 #if defined( PTH_INIT_IN_PTH_H )
388 return pth_mutex_release( p_mutex );
390 #elif defined( ST_INIT_IN_ST_H )
391 return st_mutex_unlock( *p_mutex );
393 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
394 int i_return = pthread_mutex_unlock( p_mutex );
397 intf_ErrMsg( "thread %d error: mutex_unlock failed at %s:%d (%s)",
398 pthread_self(), psz_file, i_line, strerror(i_return) );
402 #elif defined( HAVE_CTHREADS_H )
403 mutex_unlock( p_mutex );
406 #elif defined( HAVE_KERNEL_SCHEDULER_H )
412 if( p_mutex->init < 2000 )
417 release_sem( p_mutex->lock );
420 #elif defined( WIN32 )
421 LeaveCriticalSection( p_mutex );
427 /*****************************************************************************
428 * vlc_mutex_destroy: destroy a mutex
429 *****************************************************************************/
431 # define vlc_mutex_destroy( P_MUTEX ) \
432 _vlc_mutex_destroy( __FILE__, __LINE__, P_MUTEX )
434 # define vlc_mutex_destroy( P_MUTEX ) \
435 _vlc_mutex_destroy( NULL, 0, P_MUTEX )
438 static __inline__ int _vlc_mutex_destroy( char * psz_file, int i_line,
439 vlc_mutex_t *p_mutex )
441 #if defined( PTH_INIT_IN_PTH_H )
444 #elif defined( ST_INIT_IN_ST_H )
445 return st_mutex_destroy( *p_mutex );
447 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
448 int i_return = pthread_mutex_destroy( p_mutex );
451 intf_ErrMsg( "thread %d error: mutex_destroy failed at %s:%d (%s)",
452 pthread_self(), psz_file, i_line, strerror(i_return) );
456 #elif defined( HAVE_CTHREADS_H )
459 #elif defined( HAVE_KERNEL_SCHEDULER_H )
460 if( p_mutex->init == 9999 )
462 delete_sem( p_mutex->lock );
468 #elif defined( WIN32 )
469 DeleteCriticalSection( p_mutex );
475 /*****************************************************************************
476 * vlc_cond_init: initialize a condition
477 *****************************************************************************/
478 static __inline__ int vlc_cond_init( vlc_cond_t *p_condvar )
480 #if defined( PTH_INIT_IN_PTH_H )
481 return pth_cond_init( p_condvar );
483 #elif defined( ST_INIT_IN_ST_H )
484 *p_condvar = st_cond_new();
485 return ( *p_condvar == NULL ) ? errno : 0;
487 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
488 return pthread_cond_init( p_condvar, NULL );
490 #elif defined( HAVE_CTHREADS_H )
491 /* condition_init() */
492 spin_lock_init( &p_condvar->lock );
493 cthread_queue_init( &p_condvar->queue );
495 p_condvar->implications = 0;
499 #elif defined( HAVE_KERNEL_SCHEDULER_H )
505 if( p_condvar->init == 9999 )
510 p_condvar->thread = -1;
511 p_condvar->init = 9999;
514 #elif defined( WIN32 )
515 /* initialise counter */
516 p_condvar->i_waiting_threads = 0;
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 */
524 return( !p_condvar->signal );
529 /*****************************************************************************
530 * vlc_cond_signal: start a thread on condition completion
531 *****************************************************************************/
532 static __inline__ int vlc_cond_signal( vlc_cond_t *p_condvar )
534 #if defined( PTH_INIT_IN_PTH_H )
535 return pth_cond_notify( p_condvar, FALSE );
537 #elif defined( ST_INIT_IN_ST_H )
538 return st_cond_signal( *p_condvar );
540 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
541 return pthread_cond_signal( p_condvar );
543 #elif defined( HAVE_CTHREADS_H )
544 /* condition_signal() */
545 if ( p_condvar->queue.head || p_condvar->implications )
547 cond_signal( (condition_t)p_condvar );
551 #elif defined( HAVE_KERNEL_SCHEDULER_H )
557 if( p_condvar->init < 2000 )
562 while( p_condvar->thread != -1 )
565 if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
570 if( info.state != B_THREAD_SUSPENDED )
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. */
580 /* Ok, we have to wake up that thread */
581 resume_thread( p_condvar->thread );
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 )
595 PulseEvent( p_condvar->signal );
596 Sleep( 0 ); /* deschedule the current thread */
603 /*****************************************************************************
604 * vlc_cond_broadcast: start all threads waiting on condition completion
605 *****************************************************************************/
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
611 static __inline__ int vlc_cond_broadcast( vlc_cond_t *p_condvar )
613 #if defined( PTH_INIT_IN_PTH_H )
614 return pth_cond_notify( p_condvar, FALSE );
616 #elif defined( ST_INIT_IN_ST_H )
617 return st_cond_broadcast( p_condvar );
619 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
620 return pthread_cond_broadcast( p_condvar );
622 #elif defined( HAVE_CTHREADS_H )
623 /* condition_signal() */
624 if ( p_condvar->queue.head || p_condvar->implications )
626 cond_signal( (condition_t)p_condvar );
630 #elif defined( HAVE_KERNEL_SCHEDULER_H )
636 if( p_condvar->init < 2000 )
641 while( p_condvar->thread != -1 )
644 if( get_thread_info(p_condvar->thread, &info) == B_BAD_VALUE )
649 if( info.state != B_THREAD_SUSPENDED )
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. */
659 /* Ok, we have to wake up that thread */
660 resume_thread( p_condvar->thread );
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 )
672 PulseEvent( p_condvar->signal );
673 Sleep( 0 ); /* deschedule the current thread */
680 /*****************************************************************************
681 * vlc_cond_wait: wait until condition completion
682 *****************************************************************************/
684 # define vlc_cond_wait( P_COND, P_MUTEX ) \
685 _vlc_cond_wait( __FILE__, __LINE__, P_COND, P_MUTEX )
687 # define vlc_cond_wait( P_COND, P_MUTEX ) \
688 _vlc_cond_wait( NULL, 0, P_COND, P_MUTEX )
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 )
695 #if defined( PTH_INIT_IN_PTH_H )
696 return pth_cond_await( p_condvar, p_mutex, NULL );
698 #elif defined( ST_INIT_IN_ST_H )
701 st_mutex_unlock( *p_mutex );
702 i_ret = st_cond_wait( *p_condvar );
703 st_mutex_lock( *p_mutex );
707 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
710 return pthread_cond_wait( p_condvar, p_mutex );
712 /* In debug mode, timeout */
714 struct timespec timeout;
719 gettimeofday( &now, NULL );
720 timeout.tv_sec = now.tv_sec + THREAD_COND_TIMEOUT;
721 timeout.tv_nsec = now.tv_usec * 1000;
723 i_result = pthread_cond_timedwait( p_condvar, p_mutex, &timeout );
725 if( i_result == ETIMEDOUT )
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) );
734 intf_ErrMsg( "thread %d error: cond_wait failed at %s:%d (%s)",
735 pthread_self(), psz_file, i_line, strerror(i_result) );
741 #elif defined( HAVE_CTHREADS_H )
742 condition_wait( (condition_t)p_condvar, (mutex_t)p_mutex );
745 #elif defined( HAVE_KERNEL_SCHEDULER_H )
756 if( p_condvar->init < 2000 )
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;
769 vlc_mutex_lock( p_mutex );
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.
779 * The solution we use should however fulfill all our needs (even though
780 * it is not a correct pthreads implementation)
784 p_condvar->i_waiting_threads ++;
786 /* Release the mutex */
787 vlc_mutex_unlock( p_mutex );
789 i_result = WaitForSingleObject( p_condvar->signal, INFINITE);
791 /* maybe we should protect this with a mutex ? */
792 p_condvar->i_waiting_threads --;
794 /* Reacquire the mutex before returning. */
795 vlc_mutex_lock( p_mutex );
797 return( i_result == WAIT_FAILED );
802 /*****************************************************************************
803 * vlc_cond_destroy: destroy a condition
804 *****************************************************************************/
806 # define vlc_cond_destroy( P_COND ) \
807 _vlc_cond_destroy( __FILE__, __LINE__, P_COND )
809 # define vlc_cond_destroy( P_COND ) \
810 _vlc_cond_destroy( NULL, 0, P_COND )
813 static __inline__ int _vlc_cond_destroy( char * psz_file, int i_line,
814 vlc_cond_t *p_condvar )
816 #if defined( PTH_INIT_IN_PTH_H )
819 #elif defined( ST_INIT_IN_ST_H )
820 return st_cond_destroy( *p_condvar );
822 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
823 int i_result = pthread_cond_destroy( p_condvar );
826 intf_ErrMsg( "thread %d error: cond_destroy failed at %s:%d (%s)",
827 pthread_self(), psz_file, i_line, strerror(i_result) );
831 #elif defined( HAVE_CTHREADS_H )
834 #elif defined( HAVE_KERNEL_SCHEDULER_H )
838 #elif defined( WIN32 )
839 return( !CloseHandle( p_condvar->signal ) );
844 /*****************************************************************************
845 * vlc_thread_create: create a thread
846 *****************************************************************************/
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 )
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 )
855 static __inline__ int _vlc_thread_create( char * psz_file, int i_line,
856 vlc_thread_t *p_thread,
858 vlc_thread_func_t func,
866 /* Initialize the wrapper structure */
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 );
874 /* Alter user-passed data so that we call the wrapper instead
875 * of the real function */
877 func = vlc_thread_wrapper;
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 );
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 );
888 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
889 i_ret = pthread_create( p_thread, NULL, func, p_data );
891 #elif defined( HAVE_CTHREADS_H )
892 *p_thread = cthread_fork( (cthread_fn_t)func, (any_t)p_data );
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 );
900 #elif defined( WIN32 )
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);
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);
915 i_ret = ( *p_thread ? 0 : 1 );
922 vlc_cond_wait( &wrapper.wait, &wrapper.lock );
925 vlc_mutex_unlock( &wrapper.lock );
926 vlc_mutex_destroy( &wrapper.lock );
927 vlc_cond_destroy( &wrapper.wait );
932 intf_WarnMsg( 2, "thread info: %d (%s) has been created (%s:%d)",
933 *p_thread, psz_name, psz_file, i_line );
937 intf_ErrMsg( "thread error: %s couldn't be created at %s:%d (%s)",
938 psz_name, psz_file, i_line, strerror(i_ret) );
944 /*****************************************************************************
945 * vlc_thread_exit: terminate a thread
946 *****************************************************************************/
947 static __inline__ void vlc_thread_exit( void )
949 #if defined( PTH_INIT_IN_PTH_H )
952 #elif defined( ST_INIT_IN_ST_H )
954 st_thread_exit( &result );
956 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
959 #elif defined( HAVE_CTHREADS_H )
961 cthread_exit( &result );
963 #elif defined( HAVE_KERNEL_SCHEDULER_H )
966 #elif defined( WIN32 )
970 /* For now we don't close the thread handles (because of race conditions).
971 * Need to be looked at. */
977 /*****************************************************************************
978 * vlc_thread_join: wait until a thread exits
979 *****************************************************************************/
981 # define vlc_thread_join( THREAD ) \
982 _vlc_thread_join( __FILE__, __LINE__, THREAD )
984 # define vlc_thread_join( THREAD ) \
985 _vlc_thread_join( NULL, 0, THREAD )
988 static __inline__ void _vlc_thread_join( char * psz_file, int i_line,
989 vlc_thread_t thread )
993 #if defined( PTH_INIT_IN_PTH_H )
994 i_ret = pth_join( thread, NULL );
996 #elif defined( ST_INIT_IN_ST_H )
997 i_ret = st_thread_join( thread, NULL );
999 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
1000 i_ret = pthread_join( thread, NULL );
1002 #elif defined( HAVE_CTHREADS_H )
1003 cthread_join( thread );
1006 #elif defined( HAVE_KERNEL_SCHEDULER_H )
1008 wait_for_thread( thread, &exit_value );
1010 #elif defined( WIN32 )
1011 WaitForSingleObject( thread, INFINITE );
1017 intf_ErrMsg( "thread error: thread_join(%d) failed at %s:%d (%s)",
1018 thread, psz_file, i_line, strerror(i_ret) );
1022 intf_WarnMsg( 2, "thread info: %d has been joined (%s:%d)",
1023 thread, psz_file, i_line );
1028 static void *vlc_thread_wrapper( void *p_wrapper )
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;
1034 /* Set the profile timer value */
1035 setitimer( ITIMER_PROF, &((wrapper_t*)p_wrapper)->itimer, NULL );
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 );
1042 /* Call the real function */
1043 return func( p_data );