+/*****************************************************************************
+ * vlc_cond_destroy: destroy a condition
+ *****************************************************************************/
+#ifdef DEBUG
+# define vlc_cond_destroy( P_COND ) \
+ _vlc_cond_destroy( __FILE__, __LINE__, P_COND )
+#else
+# define vlc_cond_destroy( P_COND ) \
+ _vlc_cond_destroy( NULL, 0, P_COND )
+#endif
+
+static __inline__ int _vlc_cond_destroy( char * psz_file, int i_line,
+ vlc_cond_t *p_condvar )
+{
+#if defined( PTH_INIT_IN_PTH_H )
+ return 0;
+
+#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
+ int i_result = pthread_cond_destroy( p_condvar );
+ if( i_result )
+ {
+ intf_ErrMsg( "thread %d error: cond_destroy failed at %s:%d (%s)",
+ pthread_self(), psz_file, i_line, strerror(i_result) );
+ }
+ return i_result;
+
+#elif defined( HAVE_CTHREADS_H )
+ return 0;
+
+#elif defined( HAVE_KERNEL_SCHEDULER_H )
+ p_condvar->init = 0;
+ return 0;
+
+#elif defined( WIN32 )
+ return( !CloseHandle( p_condvar->signal ) );
+
+#endif
+}
+
+/*****************************************************************************
+ * vlc_thread_create: create a thread
+ *****************************************************************************/
+#ifdef DEBUG
+# define vlc_thread_create( P_THREAD, PSZ_NAME, FUNC, P_DATA ) \
+ _vlc_thread_create( __FILE__, __LINE__, P_THREAD, PSZ_NAME, FUNC, P_DATA )
+#else
+# define vlc_thread_create( P_THREAD, PSZ_NAME, FUNC, P_DATA ) \
+ _vlc_thread_create( NULL, 0, P_THREAD, PSZ_NAME, FUNC, P_DATA )
+#endif
+
+static __inline__ int _vlc_thread_create( char * psz_file, int i_line,
+ vlc_thread_t *p_thread,
+ char *psz_name,
+ vlc_thread_func_t func,
+ void *p_data )
+{
+ int i_ret;
+
+#ifdef GPROF
+ wrapper_t wrapper;
+
+ /* Initialize the wrapper structure */
+ wrapper.func = func;
+ wrapper.p_data = p_data;
+ getitimer( ITIMER_PROF, &wrapper.itimer );
+ vlc_mutex_init( &wrapper.lock );
+ vlc_cond_init( &wrapper.wait );
+ vlc_mutex_lock( &wrapper.lock );
+
+ /* Alter user-passed data so that we call the wrapper instead
+ * of the real function */
+ p_data = &wrapper;
+ func = vlc_thread_wrapper;
+#endif
+
+#if defined( PTH_INIT_IN_PTH_H )
+ *p_thread = pth_spawn( PTH_ATTR_DEFAULT, func, p_data );
+ i_ret = ( p_thread == NULL );
+
+#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
+ i_ret = pthread_create( p_thread, NULL, func, p_data );
+
+#elif defined( HAVE_CTHREADS_H )
+ *p_thread = cthread_fork( (cthread_fn_t)func, (any_t)p_data );
+ i_ret = 0;
+
+#elif defined( HAVE_KERNEL_SCHEDULER_H )
+ *p_thread = spawn_thread( (thread_func)func, psz_name,
+ B_NORMAL_PRIORITY, p_data );
+ i_ret = resume_thread( *p_thread );
+
+#elif defined( WIN32 )
+#if 0
+ DWORD threadID;
+ /* This method is not recommended when using the MSVCRT C library,
+ * so we'll have to use _beginthreadex instead */
+ *p_thread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) func,
+ p_data, 0, &threadID);
+#endif
+ unsigned threadID;
+ /* When using the MSVCRT C library you have to use the _beginthreadex
+ * function instead of CreateThread, otherwise you'll end up with memory
+ * leaks and the signal function not working */
+ *p_thread = (HANDLE)_beginthreadex(NULL, 0, (PTHREAD_START) func,
+ p_data, 0, &threadID);
+
+ i_ret = ( *p_thread ? 0 : 1 );
+
+#endif
+
+#ifdef GPROF
+ if( i_ret == 0 )
+ {
+ vlc_cond_wait( &wrapper.wait, &wrapper.lock );
+ }
+
+ vlc_mutex_unlock( &wrapper.lock );
+ vlc_mutex_destroy( &wrapper.lock );
+ vlc_cond_destroy( &wrapper.wait );
+#endif
+
+ if( i_ret == 0 )
+ {
+ intf_WarnMsg( 2, "thread info: %d (%s) has been created (%s:%d)",
+ *p_thread, psz_name, psz_file, i_line );
+ }
+ else
+ {
+ intf_ErrMsg( "thread error: %s couldn't be created at %s:%d (%s)",
+ psz_name, psz_file, i_line, strerror(i_ret) );
+ }
+
+ return i_ret;
+}
+
+/*****************************************************************************
+ * vlc_thread_exit: terminate a thread
+ *****************************************************************************/
+static __inline__ void vlc_thread_exit( void )
+{
+#if defined( PTH_INIT_IN_PTH_H )
+ pth_exit( 0 );
+
+#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
+ pthread_exit( 0 );
+
+#elif defined( HAVE_CTHREADS_H )
+ int result;
+ cthread_exit( &result );
+
+#elif defined( HAVE_KERNEL_SCHEDULER_H )
+ exit_thread( 0 );
+
+#elif defined( WIN32 )
+#if 0
+ ExitThread( 0 );
+#endif
+ /* For now we don't close the thread handles (because of race conditions).
+ * Need to be looked at. */
+ _endthreadex(0);
+
+#endif
+}
+
+/*****************************************************************************
+ * vlc_thread_join: wait until a thread exits
+ *****************************************************************************/
+#ifdef DEBUG
+# define vlc_thread_join( THREAD ) \
+ _vlc_thread_join( __FILE__, __LINE__, THREAD )
+#else
+# define vlc_thread_join( THREAD ) \
+ _vlc_thread_join( NULL, 0, THREAD )
+#endif
+
+static __inline__ void _vlc_thread_join( char * psz_file, int i_line,
+ vlc_thread_t thread )
+{
+ int i_ret = 0;
+
+#if defined( PTH_INIT_IN_PTH_H )
+ i_ret = pth_join( thread, NULL );
+
+#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
+ i_ret = pthread_join( thread, NULL );
+
+#elif defined( HAVE_CTHREADS_H )
+ cthread_join( thread );
+ i_ret = 1;
+
+#elif defined( HAVE_KERNEL_SCHEDULER_H )
+ int32 exit_value;
+ wait_for_thread( thread, &exit_value );
+
+#elif defined( WIN32 )
+ WaitForSingleObject( thread, INFINITE );
+
+#endif
+
+ if( i_ret )
+ {
+ intf_ErrMsg( "thread error: thread_join(%d) failed at %s:%d (%s)",
+ thread, psz_file, i_line, strerror(i_ret) );
+ }
+ else
+ {
+ intf_WarnMsg( 2, "thread info: %d has been joined (%s:%d)",
+ thread, psz_file, i_line );
+ }
+}
+
+#ifdef GPROF
+static void *vlc_thread_wrapper( void *p_wrapper )
+{
+ /* Put user data in thread-local variables */
+ void * p_data = ((wrapper_t*)p_wrapper)->p_data;
+ vlc_thread_func_t func = ((wrapper_t*)p_wrapper)->func;
+
+ /* Set the profile timer value */
+ setitimer( ITIMER_PROF, &((wrapper_t*)p_wrapper)->itimer, NULL );
+
+ /* Tell the calling thread that we don't need its data anymore */
+ vlc_mutex_lock( &((wrapper_t*)p_wrapper)->lock );
+ vlc_cond_signal( &((wrapper_t*)p_wrapper)->wait );
+ vlc_mutex_unlock( &((wrapper_t*)p_wrapper)->lock );
+
+ /* Call the real function */
+ return func( p_data );
+}
+#endif
+