Commit a29e8329 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Replace vlc_detach() with simpler vlc_clone_detach()

vlc_clone_detach() is less flexible but we never used that lost
flexibilty. However, it will simplify a later Windows fix as well as
safely exposing detached threads to plugins.
parent a75bbdb2
...@@ -51,8 +51,8 @@ void system_End ( libvlc_int_t * ); ...@@ -51,8 +51,8 @@ void system_End ( libvlc_int_t * );
* Threads subsystem * Threads subsystem
*/ */
/* This cannot be used as is from plugins: */ /* This cannot be used as is from plugins yet: */
void vlc_detach (vlc_thread_t); int vlc_clone_detach (vlc_thread_t *, void *(*)(void *), void *, int);
/* Hopefully, no need to export this. There is a new thread API instead. */ /* Hopefully, no need to export this. There is a new thread API instead. */
void vlc_thread_cancel (vlc_object_t *); void vlc_thread_cancel (vlc_object_t *);
......
...@@ -600,23 +600,12 @@ void vlc_threads_setup (libvlc_int_t *p_libvlc) ...@@ -600,23 +600,12 @@ void vlc_threads_setup (libvlc_int_t *p_libvlc)
vlc_mutex_unlock (&lock); vlc_mutex_unlock (&lock);
} }
/**
* Creates and starts new thread. static int vlc_clone_attr (vlc_thread_t *th, pthread_attr_t *attr,
* void *(*entry) (void *), void *data, int priority)
* @param p_handle [OUT] pointer to write the handle of the created thread to
* @param entry entry point for the thread
* @param data data parameter given to the entry point
* @param priority thread priority value
* @return 0 on success, a standard error code on error.
*/
int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
int priority)
{ {
int ret; int ret;
pthread_attr_t attr;
pthread_attr_init (&attr);
/* Block the signals that signals interface plugin handles. /* Block the signals that signals interface plugin handles.
* If the LibVLC caller wants to handle some signals by itself, it should * If the LibVLC caller wants to handle some signals by itself, it should
* block these before whenever invoking LibVLC. And it must obviously not * block these before whenever invoking LibVLC. And it must obviously not
...@@ -653,8 +642,8 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data, ...@@ -653,8 +642,8 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
else else
sp.sched_priority += sched_get_priority_min (policy = SCHED_RR); sp.sched_priority += sched_get_priority_min (policy = SCHED_RR);
pthread_attr_setschedpolicy (&attr, policy); pthread_attr_setschedpolicy (attr, policy);
pthread_attr_setschedparam (&attr, &sp); pthread_attr_setschedparam (attr, &sp);
} }
#else #else
(void) priority; (void) priority;
...@@ -675,29 +664,36 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data, ...@@ -675,29 +664,36 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
#define VLC_STACKSIZE (128 * sizeof (void *) * 1024) #define VLC_STACKSIZE (128 * sizeof (void *) * 1024)
#ifdef VLC_STACKSIZE #ifdef VLC_STACKSIZE
ret = pthread_attr_setstacksize (&attr, VLC_STACKSIZE); ret = pthread_attr_setstacksize (attr, VLC_STACKSIZE);
assert (ret == 0); /* fails iif VLC_STACKSIZE is invalid */ assert (ret == 0); /* fails iif VLC_STACKSIZE is invalid */
#endif #endif
ret = pthread_create (p_handle, &attr, entry, data); ret = pthread_create (th, attr, entry, data);
pthread_sigmask (SIG_SETMASK, &oldset, NULL); pthread_sigmask (SIG_SETMASK, &oldset, NULL);
pthread_attr_destroy (&attr); pthread_attr_destroy (attr);
return ret; return ret;
} }
/** /**
* Marks a thread as cancelled. Next time the target thread reaches a * Creates and starts new thread.
* cancellation point (while not having disabled cancellation), it will *
* run its cancellation cleanup handler, the thread variable destructors, and * The thread must be <i>joined</i> with vlc_join() to reclaim resources
* terminate. vlc_join() must be used afterward regardless of a thread being * when it is not needed anymore.
* cancelled or not. *
* @param th [OUT] pointer to write the handle of the created thread to
* (mandatory, must be non-NULL)
* @param entry entry point for the thread
* @param data data parameter given to the entry point
* @param priority thread priority value
* @return 0 on success, a standard error code on error.
*/ */
void vlc_cancel (vlc_thread_t thread_id) int vlc_clone (vlc_thread_t *th, void *(*entry) (void *), void *data,
int priority)
{ {
pthread_cancel (thread_id); pthread_attr_t attr;
#ifdef HAVE_MAEMO
pthread_kill (thread_id, SIGRTMIN); pthread_attr_init (&attr);
#endif return vlc_clone_attr (th, &attr, entry, data, priority);
} }
/** /**
...@@ -718,25 +714,56 @@ void vlc_join (vlc_thread_t handle, void **result) ...@@ -718,25 +714,56 @@ void vlc_join (vlc_thread_t handle, void **result)
} }
/** /**
* Detaches a thread. When the specified thread completes, it will be * Creates and starts new detached thread.
* automatically destroyed (in particular, its stack will be reclaimed), * A detached thread cannot be joined. Its resources will be automatically
* instead of waiting for another thread to call vlc_join(). If the thread has * released whenever the thread exits (in particular, its call stack will be
* already completed, it will be destroyed immediately. * reclaimed). Nevertheless, a detached thread may
* be cancelled; this can expedite its termination.
* *
* When a thread performs some work asynchronously and may complete much * Detached thread are particularly useful when some work needs to be done
* earlier than it can be joined, detaching the thread can save memory. * asynchronously, that is likely to be completed much earlier than the thread
* However, care must be taken that any resources used by a detached thread * can practically be joined. In this case, thread detach can spare memory.
* remains valid until the thread completes. This will typically involve some
* kind of thread-safe signaling.
* *
* A thread may detach itself. * @warning Care must be taken that any resources used by the detached thread
* remains valid until the thread completes.
* *
* @param handle thread handle * @note A detached thread must eventually exit just like another other
* thread. In practice, LibVLC will wait for detached threads to exit before
* it unloads the plugins.
*
* @param th [OUT] pointer to hold the thread handle, or NULL
* @param entry entry point for the thread
* @param data data parameter given to the entry point
* @param priority thread priority value
* @return 0 on success, a standard error code on error.
*/ */
void vlc_detach (vlc_thread_t handle) int vlc_clone_detach (vlc_thread_t *th, void *(*entry) (void *), void *data,
int priority)
{ {
int val = pthread_detach (handle); vlc_thread_t dummy;
VLC_THREAD_ASSERT ("detaching thread"); pthread_attr_t attr;
if (th == NULL)
th = &dummy;
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
return vlc_clone_attr (th, &attr, entry, data, priority);
}
/**
* Marks a thread as cancelled. Next time the target thread reaches a
* cancellation point (while not having disabled cancellation), it will
* run its cancellation cleanup handler, the thread variable destructors, and
* terminate. vlc_join() must be used afterward regardless of a thread being
* cancelled or not.
*/
void vlc_cancel (vlc_thread_t thread_id)
{
pthread_cancel (thread_id);
#ifdef HAVE_MAEMO
pthread_kill (thread_id, SIGRTMIN);
#endif
} }
/** /**
......
...@@ -91,16 +91,12 @@ void playlist_fetcher_Push( playlist_fetcher_t *p_fetcher, ...@@ -91,16 +91,12 @@ void playlist_fetcher_Push( playlist_fetcher_t *p_fetcher,
p_fetcher->i_waiting, p_item ); p_fetcher->i_waiting, p_item );
if( !p_fetcher->b_live ) if( !p_fetcher->b_live )
{ {
vlc_thread_t th; if( vlc_clone_detach( NULL, Thread, p_fetcher,
VLC_THREAD_PRIORITY_LOW ) )
if( vlc_clone( &th, Thread, p_fetcher, VLC_THREAD_PRIORITY_LOW ) )
msg_Err( p_fetcher->p_playlist, msg_Err( p_fetcher->p_playlist,
"cannot spawn secondary preparse thread" ); "cannot spawn secondary preparse thread" );
else else
{
vlc_detach( th );
p_fetcher->b_live = true; p_fetcher->b_live = true;
}
} }
vlc_mutex_unlock( &p_fetcher->lock ); vlc_mutex_unlock( &p_fetcher->lock );
} }
......
...@@ -83,16 +83,12 @@ void playlist_preparser_Push( playlist_preparser_t *p_preparser, input_item_t *p ...@@ -83,16 +83,12 @@ void playlist_preparser_Push( playlist_preparser_t *p_preparser, input_item_t *p
p_preparser->i_waiting, p_item ); p_preparser->i_waiting, p_item );
if( !p_preparser->b_live ) if( !p_preparser->b_live )
{ {
vlc_thread_t th; if( vlc_clone_detach( NULL, Thread, p_preparser,
VLC_THREAD_PRIORITY_LOW ) )
if( vlc_clone( &th, Thread, p_preparser, VLC_THREAD_PRIORITY_LOW ) )
msg_Warn( p_preparser->p_playlist, msg_Warn( p_preparser->p_playlist,
"cannot spawn pre-parser thread" ); "cannot spawn pre-parser thread" );
else else
{
vlc_detach( th );
p_preparser->b_live = true; p_preparser->b_live = true;
}
} }
vlc_mutex_unlock( &p_preparser->lock ); vlc_mutex_unlock( &p_preparser->lock );
} }
......
...@@ -665,15 +665,25 @@ void vlc_join (vlc_thread_t handle, void **result) ...@@ -665,15 +665,25 @@ void vlc_join (vlc_thread_t handle, void **result)
#endif #endif
} }
void vlc_detach (vlc_thread_t handle) int vlc_clone_detach (vlc_thread_t *p_handle, void *(*entry) (void *),
void *data, int priority)
{ {
vlc_thread_t th;
if (p_handle == NULL)
p_handle = &th;
int ret = vlc_clone (p_handle, entry, data, priority);
if (ret)
return ret;
#ifndef UNDER_CE #ifndef UNDER_CE
CloseHandle (handle); CloseHandle (*p_handle);
#else #else
/* FIXME: handle->cancel_event leak */ /* FIXME: handle->cancel_event leak */
CloseHandle (handle->handle); CloseHandle (handle->handle);
free (handle); free (handle);
#endif #endif
return 0;
} }
/*** Thread cancellation ***/ /*** Thread cancellation ***/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment