Replace vlc_detach() with simpler vlc_clone_detach()
authorRémi Denis-Courmont <remi@remlab.net>
Mon, 29 Nov 2010 18:15:46 +0000 (20:15 +0200)
committerRémi Denis-Courmont <remi@remlab.net>
Mon, 29 Nov 2010 18:17:04 +0000 (20:17 +0200)
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.

src/libvlc.h
src/misc/pthread.c
src/playlist/fetcher.c
src/playlist/preparser.c
src/win32/thread.c

index dc31535..82a05d0 100644 (file)
@@ -51,8 +51,8 @@ void system_End       ( libvlc_int_t * );
  * Threads subsystem
  */
 
-/* This cannot be used as is from plugins: */
-void vlc_detach (vlc_thread_t);
+/* This cannot be used as is from plugins yet: */
+int vlc_clone_detach (vlc_thread_t *, void *(*)(void *), void *, int);
 
 /* Hopefully, no need to export this. There is a new thread API instead. */
 void vlc_thread_cancel (vlc_object_t *);
index 2da18b5..6512c2e 100644 (file)
@@ -600,23 +600,12 @@ void vlc_threads_setup (libvlc_int_t *p_libvlc)
     vlc_mutex_unlock (&lock);
 }
 
-/**
- * Creates and starts new thread.
- *
- * @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)
+
+static int vlc_clone_attr (vlc_thread_t *th, pthread_attr_t *attr,
+                           void *(*entry) (void *), void *data, int priority)
 {
     int ret;
 
-    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
@@ -653,8 +642,8 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
         else
             sp.sched_priority += sched_get_priority_min (policy = SCHED_RR);
 
-        pthread_attr_setschedpolicy (&attr, policy);
-        pthread_attr_setschedparam (&attr, &sp);
+        pthread_attr_setschedpolicy (attr, policy);
+        pthread_attr_setschedparam (attr, &sp);
     }
 #else
     (void) priority;
@@ -675,29 +664,36 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
 #define VLC_STACKSIZE (128 * sizeof (void *) * 1024)
 
 #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 */
 #endif
 
-    ret = pthread_create (p_handle, &attr, entry, data);
+    ret = pthread_create (th, attr, entry, data);
     pthread_sigmask (SIG_SETMASK, &oldset, NULL);
-    pthread_attr_destroy (&attr);
+    pthread_attr_destroy (attr);
     return ret;
 }
 
 /**
- * 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.
+ * Creates and starts new thread.
+ *
+ * The thread must be <i>joined</i> with vlc_join() to reclaim resources
+ * when it is not needed anymore.
+ *
+ * @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);
-#ifdef HAVE_MAEMO
-    pthread_kill (thread_id, SIGRTMIN);
-#endif
+    pthread_attr_t attr;
+
+    pthread_attr_init (&attr);
+    return vlc_clone_attr (th, &attr, entry, data, priority);
 }
 
 /**
@@ -718,25 +714,56 @@ void vlc_join (vlc_thread_t handle, void **result)
 }
 
 /**
- * Detaches a thread. When the specified thread completes, it will be
- * automatically destroyed (in particular, its stack will be reclaimed),
- * instead of waiting for another thread to call vlc_join(). If the thread has
- * already completed, it will be destroyed immediately.
+ * Creates and starts new detached thread.
+ * A detached thread cannot be joined. Its resources will be automatically
+ * released whenever the thread exits (in particular, its call stack will be
+ * reclaimed). Nevertheless, a detached thread may
+ * be cancelled; this can expedite its termination.
  *
- * When a thread performs some work asynchronously and may complete much
- * earlier than it can be joined, detaching the thread can save memory.
- * However, care must be taken that any resources used by a detached thread
- * remains valid until the thread completes. This will typically involve some
- * kind of thread-safe signaling.
+ * Detached thread are particularly useful when some work needs to be done
+ * asynchronously, that is likely to be completed much earlier than the thread
+ * can practically be joined. In this case, thread detach can spare memory.
  *
- * 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_ASSERT ("detaching thread");
+    vlc_thread_t dummy;
+    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
 }
 
 /**
index 1551020..2113d42 100644 (file)
@@ -91,16 +91,12 @@ void playlist_fetcher_Push( playlist_fetcher_t *p_fetcher,
                  p_fetcher->i_waiting, p_item );
     if( !p_fetcher->b_live )
     {
-        vlc_thread_t th;
-
-        if( vlc_clone( &th, Thread, p_fetcher, VLC_THREAD_PRIORITY_LOW ) )
+        if( vlc_clone_detach( NULL, Thread, p_fetcher,
+                              VLC_THREAD_PRIORITY_LOW ) )
             msg_Err( p_fetcher->p_playlist,
                      "cannot spawn secondary preparse thread" );
         else
-        {
-            vlc_detach( th );
             p_fetcher->b_live = true;
-        }
     }
     vlc_mutex_unlock( &p_fetcher->lock );
 }
index 64182e3..dfd955a 100644 (file)
@@ -83,16 +83,12 @@ void playlist_preparser_Push( playlist_preparser_t *p_preparser, input_item_t *p
                  p_preparser->i_waiting, p_item );
     if( !p_preparser->b_live )
     {
-        vlc_thread_t th;
-
-        if( vlc_clone( &th, Thread, p_preparser, VLC_THREAD_PRIORITY_LOW ) )
+        if( vlc_clone_detach( NULL, Thread, p_preparser,
+                              VLC_THREAD_PRIORITY_LOW ) )
             msg_Warn( p_preparser->p_playlist,
                       "cannot spawn pre-parser thread" );
         else
-        {
-            vlc_detach( th );
             p_preparser->b_live = true;
-        }
     }
     vlc_mutex_unlock( &p_preparser->lock );
 }
index 63e181d..6f745e0 100644 (file)
@@ -665,15 +665,25 @@ void vlc_join (vlc_thread_t handle, void **result)
 #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
-    CloseHandle (handle);
+    CloseHandle (*p_handle);
 #else
     /* FIXME: handle->cancel_event leak */
     CloseHandle (handle->handle);
     free (handle);
 #endif
+    return 0;
 }
 
 /*** Thread cancellation ***/