X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fthreads.c;h=ed6dbc2ec9f8e98c0df62d6d4aaf488a70f9cc78;hb=6dfaddec8ce309db6a5cd4f93880e12edbb16c76;hp=282e118462b2d2bc17eea3c92f4894bc59fde800;hpb=cc01f686c5f807d6b53ea5298c4687f5a41dac28;p=vlc diff --git a/src/misc/threads.c b/src/misc/threads.c index 282e118462..ed6dbc2ec9 100644 --- a/src/misc/threads.c +++ b/src/misc/threads.c @@ -48,6 +48,8 @@ static volatile unsigned i_initializations = 0; #if defined( LIBVLC_USE_PTHREAD ) +# include + static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER; #endif @@ -99,14 +101,13 @@ void vlc_pthread_fatal (const char *action, int error, { fprintf (stderr, "LibVLC fatal error %s in thread %lu at %s:%u: %d\n", action, vlc_threadid (), file, line, error); - fflush (stderr); /* 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; - dprintf (2, " Error message: %m at:\n"); + fprintf (stderr, " Error message: %m at:\n"); #else char buf[1000]; const char *msg; @@ -124,8 +125,8 @@ void vlc_pthread_fatal (const char *action, int error, break; } fprintf (stderr, " Error message: %s\n", msg); - fflush (stderr); #endif + fflush (stderr); #ifdef HAVE_BACKTRACE void *stack[20]; @@ -163,7 +164,7 @@ int vlc_threads_init( void ) if( i_initializations == 0 ) { - p_root = vlc_custom_create( NULL, sizeof( *p_root ), + p_root = vlc_custom_create( (vlc_object_t *)NULL, sizeof( *p_root ), VLC_OBJECT_GENERIC, "root" ); if( p_root == NULL ) { @@ -459,12 +460,18 @@ static THREAD_RTYPE thread_entry (void *data) void *(*func) (void *) = ((struct vlc_thread_boot *)data)->entry; free (data); -#ifdef NDEBUG +#ifndef NDEBUG vlc_threadvar_set (&thread_object_key, obj); #endif msg_Dbg (obj, "thread started"); func (obj); msg_Dbg (obj, "thread ended"); + + libvlc_priv_t *libpriv = libvlc_priv (obj->p_libvlc); + vlc_mutex_lock (&libpriv->threads_lock); + if (--libpriv->threads_count == 0) + vlc_cond_signal (&libpriv->threads_wait); + vlc_mutex_unlock (&libpriv->threads_lock); return THREAD_RVAL; } @@ -480,6 +487,7 @@ int __vlc_thread_create( vlc_object_t *p_this, const char * psz_file, int i_line { int i_ret; vlc_object_internals_t *p_priv = vlc_internals( p_this ); + libvlc_priv_t *libpriv = libvlc_priv (p_this->p_libvlc); struct vlc_thread_boot *boot = malloc (sizeof (*boot)); if (boot == NULL) @@ -487,62 +495,58 @@ int __vlc_thread_create( vlc_object_t *p_this, const char * psz_file, int i_line boot->entry = func; boot->object = p_this; - vlc_mutex_lock( &p_this->object_lock ); + vlc_mutex_lock (&libpriv->threads_lock); + libpriv->threads_count++; + vlc_mutex_unlock (&libpriv->threads_lock); + + vlc_object_lock( p_this ); #if defined( LIBVLC_USE_PTHREAD ) + pthread_attr_t attr; + pthread_attr_init (&attr); + + /* Block the signals that signals interface plugin handles. + * If the LibVLC caller wants to handle some signals by itself, it should + * block these before whenever invoking LibVLC. And it must obviously not + * start the VLC signals interface plugin. + * + * LibVLC will normally ignore any interruption caused by an asynchronous + * signal during a system call. But there may well be some buggy cases + * where it fails to handle EINTR (bug reports welcome). Some underlying + * libraries might also not handle EINTR properly. + */ sigset_t set, oldset; + sigemptyset (&set); + sigdelset (&set, SIGHUP); + sigaddset (&set, SIGINT); + sigaddset (&set, SIGQUIT); + sigaddset (&set, SIGTERM); - /* We really don't want signals to (literaly) interrupt our blocking I/O - * system calls. SIGPIPE is especially bad, as it can be caused by remote - * peers through connected sockets. Generally, we cannot know which signals - * are handled by the main program. Also, external LibVLC bindings tend not - * to setup a proper signal mask before invoking LibVLC. - * Hence, we hereby block all signals, except those for which blocking is - * undefined, as listed below. Note that SIGKILL and SIGSTOP need not be - * listed (see the documentation for pthread_sigmask) here. */ - sigfillset (&set); - sigdelset (&set, SIGFPE); - sigdelset (&set, SIGILL); - sigdelset (&set, SIGSEGV); - sigdelset (&set, SIGBUS); + sigaddset (&set, SIGPIPE); /* We don't want this one, really! */ pthread_sigmask (SIG_BLOCK, &set, &oldset); - i_ret = pthread_create( &p_priv->thread_id, NULL, thread_entry, boot ); - pthread_sigmask (SIG_SETMASK, &oldset, NULL); - #ifndef __APPLE__ if( config_GetInt( p_this, "rt-priority" ) > 0 ) #endif { - int i_error, i_policy; - struct sched_param param; + struct sched_param p = { .sched_priority = i_priority, }; + int policy; - memset( ¶m, 0, sizeof(struct sched_param) ); + /* Hack to avoid error msg */ if( config_GetType( p_this, "rt-offset" ) ) - i_priority += config_GetInt( p_this, "rt-offset" ); - if( i_priority <= 0 ) - { - param.sched_priority = (-1) * i_priority; - i_policy = SCHED_OTHER; - } + p.sched_priority += config_GetInt( p_this, "rt-offset" ); + if( p.sched_priority <= 0 ) + p.sched_priority += sched_get_priority_max (policy = SCHED_OTHER); else - { - param.sched_priority = i_priority; - i_policy = SCHED_RR; - } - if( (i_error = pthread_setschedparam( p_priv->thread_id, - i_policy, ¶m )) ) - { - errno = i_error; - msg_Warn( p_this, "couldn't set thread priority (%s:%d): %m", - psz_file, i_line ); - i_priority = 0; - } + p.sched_priority += sched_get_priority_min (policy = SCHED_RR); + + pthread_attr_setschedpolicy (&attr, policy); + pthread_attr_setschedparam (&attr, &p); } -#ifndef __APPLE__ - else - i_priority = 0; -#endif + + i_ret = pthread_create( &p_priv->thread_id, &attr, thread_entry, boot ); + pthread_sigmask (SIG_SETMASK, &oldset, NULL); + pthread_attr_destroy (&attr); #elif defined( WIN32 ) || defined( UNDER_CE ) { @@ -601,7 +605,15 @@ int __vlc_thread_create( vlc_object_t *p_this, const char * psz_file, int i_line psz_name, psz_file, i_line ); } - vlc_mutex_unlock( &p_this->object_lock ); + vlc_object_unlock( p_this ); + + if (i_ret) + { + vlc_mutex_lock (&libpriv->threads_lock); + if (--libpriv->threads_count == 0) + vlc_cond_signal (&libpriv->threads_wait); + vlc_mutex_unlock (&libpriv->threads_lock); + } return i_ret; } @@ -663,14 +675,6 @@ int __vlc_thread_set_priority( vlc_object_t *p_this, const char * psz_file, return 0; } -/***************************************************************************** - * vlc_thread_ready: tell the parent thread we were successfully spawned - *****************************************************************************/ -void __vlc_thread_ready( vlc_object_t *p_this ) -{ - vlc_object_signal( p_this ); -} - /***************************************************************************** * vlc_thread_join: wait until a thread exits, inner version *****************************************************************************/ @@ -683,7 +687,10 @@ void __vlc_thread_join( vlc_object_t *p_this, const char * psz_file, int i_line /* Make sure we do return if we are calling vlc_thread_join() * from the joined thread */ if (pthread_equal (pthread_self (), p_priv->thread_id)) + { + msg_Warn (p_this, "joining the active thread (VLC might crash)"); i_ret = pthread_detach (p_priv->thread_id); + } else i_ret = pthread_join (p_priv->thread_id, NULL);