📄 threads.c
字号:
/***************************************************************************** * threads.c : threads implementation for the VideoLAN client ***************************************************************************** * Copyright (C) 1999-2007 the VideoLAN team * $Id: 3218f5eb6efb1cf86c00a1c08f8f4d2a100d17f0 $ * * Authors: Jean-Marc Dressler <polux@via.ecp.fr> * Samuel Hocevar <sam@zoy.org> * Gildas Bazin <gbazin@netcourrier.com> * Clément Sténac * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include "libvlc.h"#include <assert.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <signal.h>#define VLC_THREADS_UNINITIALIZED 0#define VLC_THREADS_PENDING 1#define VLC_THREADS_ERROR 2#define VLC_THREADS_READY 3/***************************************************************************** * Global mutex for lazy initialization of the threads system *****************************************************************************/static volatile unsigned i_initializations = 0;#if defined( LIBVLC_USE_PTHREAD )# include <sched.h>static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER;#endif/** * Global process-wide VLC object. * Contains inter-instance data, such as the module cache and global mutexes. */static libvlc_global_data_t *p_root;libvlc_global_data_t *vlc_global( void ){ assert( i_initializations > 0 ); return p_root;}#ifndef NDEBUG/** * Object running the current thread */static vlc_threadvar_t thread_object_key;vlc_object_t *vlc_threadobj (void){ return vlc_threadvar_get (&thread_object_key);}#endifvlc_threadvar_t msg_context_global_key;#if defined(LIBVLC_USE_PTHREAD)static inline unsigned long vlc_threadid (void){ union { pthread_t th; unsigned long int i; } v = { }; v.th = pthread_self (); return v.i;}#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE)# include <execinfo.h>#endif/***************************************************************************** * vlc_thread_fatal: Report an error from the threading layer ***************************************************************************** * This is mostly meant for debugging. *****************************************************************************/void vlc_pthread_fatal (const char *action, int error, const char *file, unsigned line){ fprintf (stderr, "LibVLC fatal error %s in thread %lu at %s:%u: %d\n", action, vlc_threadid (), file, line, error); /* Sometimes strerror_r() crashes too, so make sure we print an error * message before we invoke it */#ifdef __GLIBC__ /* Avoid the strerror_r() prototype brain damage in glibc */ errno = error; fprintf (stderr, " Error message: %m at:\n");#else char buf[1000]; const char *msg; switch (strerror_r (error, buf, sizeof (buf))) { case 0: msg = buf; break; case ERANGE: /* should never happen */ msg = "unknwon (too big to display)"; break; default: msg = "unknown (invalid error number)"; break; } fprintf (stderr, " Error message: %s\n", msg);#endif fflush (stderr);#ifdef HAVE_BACKTRACE void *stack[20]; int len = backtrace (stack, sizeof (stack) / sizeof (stack[0])); backtrace_symbols_fd (stack, len, 2);#endif abort ();}#elsevoid vlc_pthread_fatal (const char *action, int error, const char *file, unsigned line){ (void)action; (void)error; (void)file; (void)line; abort();}#endif/***************************************************************************** * vlc_threads_init: initialize threads system ***************************************************************************** * This function requires lazy initialization of a global lock in order to * keep the library really thread-safe. Some architectures don't support this * and thus do not guarantee the complete reentrancy. *****************************************************************************/int vlc_threads_init( void ){ int i_ret = VLC_SUCCESS; /* If we have lazy mutex initialization, use it. Otherwise, we just * hope nothing wrong happens. */#if defined( LIBVLC_USE_PTHREAD ) pthread_mutex_lock( &once_mutex );#endif if( i_initializations == 0 ) { p_root = vlc_custom_create( (vlc_object_t *)NULL, sizeof( *p_root ), VLC_OBJECT_GENERIC, "root" ); if( p_root == NULL ) { i_ret = VLC_ENOMEM; goto out; } /* We should be safe now. Do all the initialization stuff we want. */#ifndef NDEBUG vlc_threadvar_create( &thread_object_key, NULL );#endif vlc_threadvar_create( &msg_context_global_key, msg_StackDestroy ); } i_initializations++;out: /* If we have lazy mutex initialization support, unlock the mutex. * Otherwize, we are screwed. */#if defined( LIBVLC_USE_PTHREAD ) pthread_mutex_unlock( &once_mutex );#endif return i_ret;}/***************************************************************************** * vlc_threads_end: stop threads system ***************************************************************************** * FIXME: This function is far from being threadsafe. *****************************************************************************/void vlc_threads_end( void ){#if defined( LIBVLC_USE_PTHREAD ) pthread_mutex_lock( &once_mutex );#endif assert( i_initializations > 0 ); if( i_initializations == 1 ) { vlc_object_release( p_root ); vlc_threadvar_delete( &msg_context_global_key );#ifndef NDEBUG vlc_threadvar_delete( &thread_object_key );#endif } i_initializations--;#if defined( LIBVLC_USE_PTHREAD ) pthread_mutex_unlock( &once_mutex );#endif}#if defined (__GLIBC__) && (__GLIBC_MINOR__ < 6)/* This is not prototyped under glibc, though it exists. */int pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind );#endif/***************************************************************************** * vlc_mutex_init: initialize a mutex *****************************************************************************/int vlc_mutex_init( vlc_mutex_t *p_mutex ){#if defined( LIBVLC_USE_PTHREAD ) pthread_mutexattr_t attr; int i_result; pthread_mutexattr_init( &attr );# ifndef NDEBUG /* Create error-checking mutex to detect problems more easily. */# if defined (__GLIBC__) && (__GLIBC_MINOR__ < 6) pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ERRORCHECK_NP );# else pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK );# endif# endif i_result = pthread_mutex_init( p_mutex, &attr ); pthread_mutexattr_destroy( &attr ); return i_result;#elif defined( UNDER_CE ) InitializeCriticalSection( &p_mutex->csection ); return 0;#elif defined( WIN32 ) *p_mutex = CreateMutex( NULL, FALSE, NULL ); return (*p_mutex != NULL) ? 0 : ENOMEM;#elif defined( HAVE_KERNEL_SCHEDULER_H ) /* check the arguments and whether it's already been initialized */ if( p_mutex == NULL ) { return B_BAD_VALUE; } if( p_mutex->init == 9999 ) { return EALREADY; } p_mutex->lock = create_sem( 1, "BeMutex" ); if( p_mutex->lock < B_NO_ERROR ) { return( -1 ); } p_mutex->init = 9999; return B_OK;#endif}/***************************************************************************** * vlc_mutex_init: initialize a recursive mutex (Do not use) *****************************************************************************/int vlc_mutex_init_recursive( vlc_mutex_t *p_mutex ){#if defined( LIBVLC_USE_PTHREAD ) pthread_mutexattr_t attr; int i_result; pthread_mutexattr_init( &attr );# if defined (__GLIBC__) && (__GLIBC_MINOR__ < 6) pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_RECURSIVE_NP );# else pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );# endif i_result = pthread_mutex_init( p_mutex, &attr ); pthread_mutexattr_destroy( &attr ); return( i_result );#elif defined( WIN32 ) /* Create mutex returns a recursive mutex */ *p_mutex = CreateMutex( 0, FALSE, 0 ); return (*p_mutex != NULL) ? 0 : ENOMEM;#else# error Unimplemented!#endif}/***************************************************************************** * vlc_mutex_destroy: destroy a mutex, inner version *****************************************************************************/void __vlc_mutex_destroy( const char * psz_file, int i_line, vlc_mutex_t *p_mutex ){#if defined( LIBVLC_USE_PTHREAD ) int val = pthread_mutex_destroy( p_mutex ); VLC_THREAD_ASSERT ("destroying mutex");#elif defined( UNDER_CE ) VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); DeleteCriticalSection( &p_mutex->csection );#elif defined( WIN32 ) VLC_UNUSED( psz_file); VLC_UNUSED( i_line ); CloseHandle( *p_mutex );#elif defined( HAVE_KERNEL_SCHEDULER_H ) if( p_mutex->init == 9999 ) delete_sem( p_mutex->lock ); p_mutex->init = 0;#endif}/***************************************************************************** * vlc_cond_init: initialize a condition *****************************************************************************/int __vlc_cond_init( vlc_cond_t *p_condvar ){#if defined( LIBVLC_USE_PTHREAD ) pthread_condattr_t attr; int ret; ret = pthread_condattr_init (&attr); if (ret) return ret;# if !defined (_POSIX_CLOCK_SELECTION) /* Fairly outdated POSIX support (that was defined in 2001) */# define _POSIX_CLOCK_SELECTION (-1)# endif# if (_POSIX_CLOCK_SELECTION >= 0) /* NOTE: This must be the same clock as the one in mtime.c */ pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);# endif ret = pthread_cond_init (p_condvar, &attr); pthread_condattr_destroy (&attr); return ret;#elif defined( UNDER_CE ) || defined( WIN32 ) /* Create an auto-reset event. */ *p_condvar = CreateEvent( NULL, /* no security */ FALSE, /* auto-reset event */ FALSE, /* start non-signaled */ NULL ); /* unnamed */ return *p_condvar ? 0 : ENOMEM;#elif defined( HAVE_KERNEL_SCHEDULER_H ) if( !p_condvar ) { return B_BAD_VALUE; } if( p_condvar->init == 9999 ) { return EALREADY; } p_condvar->thread = -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -