]> git.sesse.net Git - vlc/commitdiff
* ./src/misc/threads.c: improved lazy initialization of the global lock.
authorSam Hocevar <sam@videolan.org>
Tue, 16 Jul 2002 21:29:10 +0000 (21:29 +0000)
committerSam Hocevar <sam@videolan.org>
Tue, 16 Jul 2002 21:29:10 +0000 (21:29 +0000)
include/vlc_symbols.h
include/vlc_threads.h
src/libvlc.c
src/misc/modules_plugin.h
src/misc/threads.c

index 9a8e3fa671f01254cf52abb129828bb57bd8e55c..3614f55f0417702a1c5a9054acfe1c97a80b4b5d 100644 (file)
@@ -31,6 +31,7 @@ struct module_symbols_s
     int (* __vlc_mutex_destroy_inner) ( char *, int, vlc_mutex_t * ) ;
     int (* __vlc_mutex_init_inner) ( vlc_object_t *, vlc_mutex_t * ) ;
     int (* __vlc_thread_create_inner) ( vlc_object_t *, char *, int, char *, void * ( * ) ( void * ), vlc_bool_t ) ;
+    int (* __vlc_threads_end_inner) ( vlc_object_t * ) ;
     int (* __vlc_threads_init_inner) ( vlc_object_t * ) ;
     int (* input_AccessInit_inner) ( input_thread_t * ) ;
     int (* input_ChangeArea_inner) ( input_thread_t *, input_area_t * ) ;
@@ -44,7 +45,6 @@ struct module_symbols_s
     int (* input_UnselectES_inner) ( input_thread_t *, es_descriptor_t * ) ;
     int (* playlist_Add_inner) ( playlist_t *, const char *, int, int ) ;
     int (* playlist_Delete_inner) ( playlist_t *, int ) ;
-    int (* vlc_threads_end_inner) ( void ) ;
     int (* vout_ChromaCmp_inner) ( u32, u32 ) ;
     module_config_t * (* config_FindConfig_inner) ( vlc_object_t *, const char *psz_name ) ;
     module_t * (* __module_Need_inner) ( vlc_object_t *, int, const char *, void * ) ;
@@ -188,6 +188,7 @@ struct module_symbols_s
 #   define __vlc_thread_create p_symbols->__vlc_thread_create_inner
 #   define __vlc_thread_join p_symbols->__vlc_thread_join_inner
 #   define __vlc_thread_ready p_symbols->__vlc_thread_ready_inner
+#   define __vlc_threads_end p_symbols->__vlc_threads_end_inner
 #   define __vlc_threads_init p_symbols->__vlc_threads_init_inner
 #   define __vout_CreateThread p_symbols->__vout_CreateThread_inner
 #   define aout_DestroyFifo p_symbols->aout_DestroyFifo_inner
@@ -253,7 +254,6 @@ struct module_symbols_s
 #   define playlist_Add p_symbols->playlist_Add_inner
 #   define playlist_Command p_symbols->playlist_Command_inner
 #   define playlist_Delete p_symbols->playlist_Delete_inner
-#   define vlc_threads_end p_symbols->vlc_threads_end_inner
 #   define vout_AllocatePicture p_symbols->vout_AllocatePicture_inner
 #   define vout_ChromaCmp p_symbols->vout_ChromaCmp_inner
 #   define vout_CreatePicture p_symbols->vout_CreatePicture_inner
index bf017f4720a9f95c82d383c2f27433c8bef1eb2f..2bbb333fda4131199446dc330d2eb8dd9ad970f9 100644 (file)
@@ -3,7 +3,7 @@
  * This header provides a portable threads implementation.
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
- * $Id: vlc_threads.h,v 1.4 2002/07/05 11:18:56 sam Exp $
+ * $Id: vlc_threads.h,v 1.5 2002/07/16 21:29:10 sam Exp $
  *
  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
  *          Samuel Hocevar <sam@via.ecp.fr>
@@ -178,7 +178,7 @@ typedef struct
  * Function definitions
  *****************************************************************************/
 VLC_EXPORT( int,  __vlc_threads_init,  ( vlc_object_t * ) );
-VLC_EXPORT( int,    vlc_threads_end,   ( void ) );
+VLC_EXPORT( int,  __vlc_threads_end,   ( vlc_object_t * ) );
 VLC_EXPORT( int,  __vlc_mutex_init,    ( vlc_object_t *, vlc_mutex_t * ) );
 VLC_EXPORT( int,  __vlc_mutex_destroy, ( char *, int, vlc_mutex_t * ) );
 VLC_EXPORT( int,  __vlc_cond_init,     ( vlc_object_t *, vlc_cond_t * ) );
@@ -193,6 +193,12 @@ VLC_EXPORT( void, __vlc_thread_join,   ( vlc_object_t *, char *, int ) );
 #define vlc_threads_init( P_THIS )                                          \
     __vlc_threads_init( CAST_TO_VLC_OBJECT(P_THIS) )
 
+/*****************************************************************************
+ * vlc_threads_end: deinitialize threads system
+ *****************************************************************************/
+#define vlc_threads_end( P_THIS )                                          \
+    __vlc_threads_end( CAST_TO_VLC_OBJECT(P_THIS) )
+
 /*****************************************************************************
  * vlc_mutex_init: initialize a mutex
  *****************************************************************************/
index b7d831b9d8f8571cd98b56caaf15fc493aedbb0e..804a9e47f1b3a981cb8dae73d4d7238b6cd5efc2 100644 (file)
@@ -4,7 +4,7 @@
  * and spawns threads.
  *****************************************************************************
  * Copyright (C) 1998-2001 VideoLAN
- * $Id: libvlc.c,v 1.14 2002/07/15 19:15:05 sam Exp $
+ * $Id: libvlc.c,v 1.15 2002/07/16 21:29:10 sam Exp $
  *
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
@@ -771,8 +771,8 @@ vlc_error_t vlc_destroy( vlc_t *p_vlc )
     }
     vlc_mutex_unlock( p_vlc->p_global_lock );
 
-    /* Stop thread system FIXME: last one out please shut the door! */
-    //vlc_threads_end( );
+    /* Stop thread system: last one out please shut the door! */
+    vlc_threads_end( p_vlc );
 
     /* Destroy mutexes */
     vlc_mutex_destroy( &p_vlc->structure_lock );
index 62528a31797f6d84a5bc9a7d6070c8a7a671299f..c1d6d91dc34b7eab074f336c0351a8d01b56952a 100644 (file)
@@ -302,7 +302,7 @@ static inline const char * module_error( char *psz_buffer )
     (p_symbols)->playlist_Add_inner = playlist_Add; \
     (p_symbols)->playlist_Delete_inner = playlist_Delete; \
     (p_symbols)->__vlc_threads_init_inner = __vlc_threads_init; \
-    (p_symbols)->vlc_threads_end_inner = vlc_threads_end; \
+    (p_symbols)->__vlc_threads_end_inner = __vlc_threads_end; \
     (p_symbols)->__vlc_mutex_init_inner = __vlc_mutex_init; \
     (p_symbols)->__vlc_mutex_destroy_inner = __vlc_mutex_destroy; \
     (p_symbols)->__vlc_cond_init_inner = __vlc_cond_init; \
index d6583653189d9be5526ae29c4aa39ce9494475d4..9a41247623d92d175fec62da31ba4ad8592050c2 100644 (file)
@@ -2,7 +2,7 @@
  * threads.c : threads implementation for the VideoLAN client
  *****************************************************************************
  * Copyright (C) 1999, 2000, 2001, 2002 VideoLAN
- * $Id: threads.c,v 1.8 2002/07/05 11:18:56 sam Exp $
+ * $Id: threads.c,v 1.9 2002/07/16 21:29:10 sam Exp $
  *
  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
@@ -68,21 +68,50 @@ typedef struct wrapper_s
 
 #endif /* GPROF */
 
+/*****************************************************************************
+ * Global mutexes for lazy initialization of the threads system
+ *****************************************************************************/
+static volatile int i_initializations = 0;
+
+#if defined( PTH_INIT_IN_PTH_H )
+    /* Unimplemented */
+#elif defined( ST_INIT_IN_ST_H )
+    /* Unimplemented */
+#elif defined( WIN32 )
+    /* Unimplemented */
+#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
+    static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER;
+#elif defined( HAVE_CTHREADS_H )
+    /* Unimplemented */
+#elif defined( HAVE_KERNEL_SCHEDULER_H )
+    /* Unimplemented */
+#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( vlc_object_t *p_this )
 {
-    /* FIXME: this is definitely _not_ threadsafe, but at least it works
-     * under all implementations. We should for instance use pthread_once
-     * for lazy initialization of the global lock. */
-    static int i_status = VLC_THREADS_UNINITIALIZED;
-    int i_ret;
+    static volatile int i_status = VLC_THREADS_UNINITIALIZED;
+    int i_ret = 0;
 
-    if( i_status == VLC_THREADS_READY )
-    {
-        return 0;
-    }
+#if defined( PTH_INIT_IN_PTH_H )
+    /* Unimplemented */
+#elif defined( ST_INIT_IN_ST_H )
+    /* Unimplemented */
+#elif defined( WIN32 )
+    /* Unimplemented */
+#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
+    pthread_mutex_lock( &once_mutex );
+#elif defined( HAVE_CTHREADS_H )
+    /* Unimplemented */
+#elif defined( HAVE_KERNEL_SCHEDULER_H )
+    /* Unimplemented */
+#endif
 
     if( i_status == VLC_THREADS_UNINITIALIZED )
     {
@@ -90,35 +119,49 @@ int __vlc_threads_init( vlc_object_t *p_this )
 
 #if defined( PTH_INIT_IN_PTH_H )
         i_ret = pth_init();
-
 #elif defined( ST_INIT_IN_ST_H )
         i_ret = st_init();
-
 #elif defined( WIN32 )
-        i_ret = 0;
-
+        /* Unimplemented */
 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
-        i_ret = 0;
-
+        /* Unimplemented */
 #elif defined( HAVE_CTHREADS_H )
-        i_ret = 0;
-
+        /* Unimplemented */
 #elif defined( HAVE_KERNEL_SCHEDULER_H )
-        i_ret = 0;
-
+        /* Unimplemented */
 #endif
+
         if( i_ret )
         {
             i_status = VLC_THREADS_ERROR;
-            return i_ret;
         }
+        else
+        {
+            vlc_mutex_init( p_this, p_this->p_vlc->p_global_lock );
+            i_status = VLC_THREADS_READY;
+        }
+    }
+    else
+    {
+        i_ret = ( i_status == VLC_THREADS_READY );
+    }
 
-        vlc_mutex_init( p_this, p_this->p_vlc->p_global_lock );
-
-        i_status = VLC_THREADS_READY;
+    i_initializations++;
 
-        return i_ret;
-    }
+#if defined( PTH_INIT_IN_PTH_H )
+    /* Unimplemented */
+#elif defined( ST_INIT_IN_ST_H )
+    /* Unimplemented */
+#elif defined( WIN32 )
+    /* Unimplemented */
+#elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
+    pthread_mutex_unlock( &once_mutex );
+    return i_ret;
+#elif defined( HAVE_CTHREADS_H )
+    /* Unimplemented */
+#elif defined( HAVE_KERNEL_SCHEDULER_H )
+    /* Unimplemented */
+#endif
 
     /* Wait until the other thread has initialized the thread library */
     while( i_status == VLC_THREADS_PENDING )
@@ -126,30 +169,45 @@ int __vlc_threads_init( vlc_object_t *p_this )
         msleep( THREAD_SLEEP );
     }
 
-    return( i_status == VLC_THREADS_READY );
+    return i_status == VLC_THREADS_READY;
 }
 
 /*****************************************************************************
  * vlc_threads_end: stop threads system
+ *****************************************************************************
+ * FIXME: This function is far from being threadsafe. We should undo exactly
+ * what we did above in vlc_threads_init.
  *****************************************************************************/
-int vlc_threads_end( void )
+int __vlc_threads_end( vlc_object_t *p_this )
 {
 #if defined( PTH_INIT_IN_PTH_H )
-    return pth_kill();
+    i_initializations--;
+    if( i_initializations == 0 )
+    {
+        return pth_kill();
+    }
+    return 0;
 
 #elif defined( ST_INIT_IN_ST_H )
+    i_initializations--;
     return 0;
 
 #elif defined( WIN32 )
+    i_initializations--;
     return 0;
 
 #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
+    pthread_mutex_lock( &once_mutex );
+    i_initializations--;
+    pthread_mutex_unlock( &once_mutex );
     return 0;
 
 #elif defined( HAVE_CTHREADS_H )
+    i_initializations--;
     return 0;
 
 #elif defined( HAVE_KERNEL_SCHEDULER_H )
+    i_initializations--;
     return 0;
 
 #endif