]> git.sesse.net Git - vlc/blobdiff - src/libvlc.c
GC: thread-safety, and offset independence
[vlc] / src / libvlc.c
index 55d95fa6f557fdfb17a2695dd4b01bfecac0ba2a..87920fb96a02f1cafa7ab843848bccd8c57548c9 100644 (file)
 #include "audio_output/aout_internal.h"
 
 #include <vlc_vout.h>
-
 #include <vlc_sout.h>
-#include "stream_output/stream_output.h"
-
 #include <vlc_charset.h>
 
 #include "libvlc.h"
@@ -107,39 +104,63 @@ static unsigned          i_instances = 0;
 static bool b_daemon = false;
 #endif
 
-/*****************************************************************************
- * vlc_gc_*.
- *****************************************************************************/
-void __vlc_gc_incref( gc_object_t * p_gc )
-{
-    assert( p_gc->i_gc_refcount > 0 );
+#undef vlc_gc_init
+#undef vlc_hold
+#undef vlc_release
 
-    /* FIXME: atomic version needed! */
-    p_gc->i_gc_refcount ++;
+/**
+ * Atomically set the reference count to 1.
+ * @param p_gc reference counted object
+ * @param pf_destruct destruction calback
+ * @return p_gc.
+ */
+void *vlc_gc_init (gc_object_t *p_gc, void (*pf_destruct) (gc_object_t *))
+{
+    p_gc->pf_destructor = pf_destruct;
+
+    /* Nobody else can possibly lock the spin - it's there as a barrier */
+    vlc_spin_init (&p_gc->spin);
+    vlc_spin_lock (&p_gc->spin);
+    p_gc->refs = 1;
+    vlc_spin_unlock (&p_gc->spin);
+    return p_gc;
 }
 
-void __vlc_gc_decref( gc_object_t *p_gc )
+/**
+ * Atomically increment the reference count.
+ * @param p_gc reference counted object
+ * @return p_gc.
+ */
+void *vlc_hold (gc_object_t * p_gc)
 {
     assert( p_gc );
-    assert( p_gc->i_gc_refcount > 0 );
-
-    /* FIXME: atomic version needed! */
-    p_gc->i_gc_refcount -- ;
 
-    if( p_gc->i_gc_refcount == 0 )
-    {
-        p_gc->pf_destructor( p_gc );
-        /* Do not use the p_gc pointer from now on ! */
-    }
+    vlc_spin_lock (&p_gc->spin);
+    assert (p_gc->refs > 0);
+    p_gc->refs++;
+    vlc_spin_unlock (&p_gc->spin);
+    return p_gc;
 }
 
-void
-__vlc_gc_init( gc_object_t * p_gc, void (*pf_destructor)( gc_object_t * ),
-               void * arg)
+/**
+ * Atomically decrement the reference count and, if it reaches zero, destroy.
+ * @param p_gc reference counted object.
+ */
+void vlc_release (gc_object_t *p_gc)
 {
-    p_gc->i_gc_refcount = 1;
-    p_gc->pf_destructor = pf_destructor;
-    p_gc->p_destructor_arg = arg;
+    bool dead;
+
+    assert( p_gc );
+    vlc_spin_lock (&p_gc->spin);
+    assert (p_gc->refs > 0);
+    dead = !--p_gc->refs;
+    vlc_spin_unlock (&p_gc->spin);
+
+    if (dead)
+    {
+        vlc_spin_destroy (&p_gc->spin);
+        p_gc->pf_destructor (p_gc);
+    }
 }
 
 /*****************************************************************************
@@ -152,7 +173,7 @@ static void SetLanguage   ( char const * );
 static inline int LoadMessages (void);
 static int  GetFilenames  ( libvlc_int_t *, int, const char *[] );
 static void Help          ( libvlc_int_t *, char const *psz_help_name );
-static void Usage         ( libvlc_int_t *, char const *psz_module_name );
+static void Usage         ( libvlc_int_t *, char const *psz_search );
 static void ListModules   ( libvlc_int_t *, bool );
 static void Version       ( void );
 
@@ -269,18 +290,6 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
     /* System specific initialization code */
     system_Init( p_libvlc, &i_argc, ppsz_argv );
 
-    /* Get the executable name (similar to the basename command) */
-    if( i_argc > 0 && ppsz_argv[0][0] )
-    {
-        free( p_libvlc->psz_object_name );
-
-        const char *psz_exe = strrchr( ppsz_argv[0], '/' );
-        if( psz_exe && *(psz_exe + 1) )
-            p_libvlc->psz_object_name = strdup( psz_exe + 1 );
-        else
-            p_libvlc->psz_object_name = strdup( ppsz_argv[0] );
-    }
-
     /*
      * Support for gettext
      */
@@ -546,7 +555,9 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
 #ifdef HAVE_DBUS
     dbus_threads_init_default();
 
-    if( config_GetInt( p_libvlc, "one-instance" ) > 0 )
+    if( config_GetInt( p_libvlc, "one-instance" ) > 0
+        || ( config_GetInt( p_libvlc, "one-instance-when-started-from-file" )
+             && config_GetInt( p_libvlc, "started-from-file" ) ) )
     {
         /* Initialise D-Bus interface, check for other instances */
         DBusConnection  *p_conn = NULL;
@@ -666,6 +677,28 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
     /*
      * Message queue options
      */
+    char * psz_verbose_objects = config_GetPsz( p_libvlc, "verbose-objects" );
+    if( psz_verbose_objects )
+    {
+        char * psz_object, * iter = psz_verbose_objects;
+        while( (psz_object = strsep( &iter, "," )) )
+        {
+            switch( psz_object[0] )
+            {
+                printf("%s\n", psz_object+1);
+                case '+': msg_EnableObjectPrinting(p_libvlc, psz_object+1); break;
+                case '-': msg_DisableObjectPrinting(p_libvlc, psz_object+1); break;
+                default:
+                    msg_Err( p_libvlc, "verbose-objects usage: \n"
+                            "--verbose-objects=+printthatobject,"
+                            "-dontprintthatone\n"
+                            "(keyword 'all' to applies to all objects)\n");
+                    free( psz_verbose_objects );
+                    return VLC_EGENERIC;
+            }
+        }
+        free( psz_verbose_objects );
+    }
 
     var_Create( p_libvlc, "verbose", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
     if( config_GetInt( p_libvlc, "quiet" ) > 0 )
@@ -844,7 +877,9 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
 #ifdef HAVE_DBUS
     /* loads dbus control interface if in one-instance mode
      * we do it only when playlist exists, because dbus module needs it */
-    if( config_GetInt( p_libvlc, "one-instance" ) > 0 )
+    if( config_GetInt( p_libvlc, "one-instance" ) > 0
+        || ( config_GetInt( p_libvlc, "one-instance-when-started-from-file" )
+             && config_GetInt( p_libvlc, "started-from-file" ) ) )
         libvlc_InternalAddIntf( p_libvlc, "dbus,none" );
 
     /* Prevents the power management daemon from suspending the system
@@ -1012,24 +1047,10 @@ int libvlc_InternalCleanup( libvlc_int_t *p_libvlc )
     stats_TimersDumpAll( p_libvlc );
     stats_TimersCleanAll( p_libvlc );
 
-#ifdef ENABLE_SOUT
-    announce_handler_t * p_announce;
-
-    /* Free announce handler(s?) */
-    while( (p_announce = vlc_object_find( p_libvlc, VLC_OBJECT_ANNOUNCE,
-                                                 FIND_CHILD ) ) )
-    {
-        msg_Dbg( p_libvlc, "removing announce handler" );
-        vlc_object_detach( p_announce );
-        vlc_object_release( p_announce );
-        announce_HandlerDestroy( p_announce );
-    }
-#endif
-
     bool b_clean = true;
     FOREACH_ARRAY( input_item_t *p_del, priv->input_items )
-        msg_Err( p_libvlc, "input item %p has not been deleted properly: refcount %d, name %s",
-            p_del, p_del->i_gc_refcount, p_del->psz_name ? p_del->psz_name : "(null)" );
+        msg_Err( p_libvlc, "input item %p has not been deleted properly: name %s",
+            p_del, p_del->psz_name ? p_del->psz_name : "(null)" );
         b_clean = false;
     FOREACH_END();
     assert( b_clean );
@@ -1296,20 +1317,20 @@ static void Help( libvlc_int_t *p_this, char const *psz_help_name )
 
     if( psz_help_name && !strcmp( psz_help_name, "help" ) )
     {
-        utf8_fprintf( stdout, vlc_usage, p_this->psz_object_name );
-        Usage( p_this, "help" );
-        Usage( p_this, "main" );
+        utf8_fprintf( stdout, vlc_usage, "vlc" );
+        Usage( p_this, "=help" );
+        Usage( p_this, "=main" );
         print_help_on_full_help();
     }
     else if( psz_help_name && !strcmp( psz_help_name, "longhelp" ) )
     {
-        utf8_fprintf( stdout, vlc_usage, p_this->psz_object_name );
+        utf8_fprintf( stdout, vlc_usage, "vlc" );
         Usage( p_this, NULL );
         print_help_on_full_help();
     }
     else if( psz_help_name && !strcmp( psz_help_name, "full-help" ) )
     {
-        utf8_fprintf( stdout, vlc_usage, p_this->psz_object_name );
+        utf8_fprintf( stdout, vlc_usage, "vlc" );
         Usage( p_this, NULL );
     }
     else if( psz_help_name )
@@ -1355,7 +1376,7 @@ static void print_help_section( module_config_t *p_item, bool b_color, bool b_de
     }
 }
 
-static void Usage( libvlc_int_t *p_this, char const *psz_module_name )
+static void Usage( libvlc_int_t *p_this, char const *psz_search )
 {
 #define FORMAT_STRING "  %s --%s%s%s%s%s%s%s "
     /* short option ------'    | | | | | | |
@@ -1395,6 +1416,11 @@ static void Usage( libvlc_int_t *p_this, char const *psz_module_name )
     bool b_description_hack;
     bool b_color       = config_GetInt( p_this, "color" ) > 0;
     bool b_has_advanced = false;
+    bool b_found       = false;
+    int  i_only_advanced = 0; /* Number of modules ignored because they
+                               * only have advanced options */
+    bool b_strict = psz_search && *psz_search == '=';
+    if( b_strict ) psz_search++;
 
     memset( psz_spaces_text, ' ', PADDING_SPACES+LINE_START );
     psz_spaces_text[PADDING_SPACES+LINE_START] = '\0';
@@ -1421,7 +1447,7 @@ static void Usage( libvlc_int_t *p_this, char const *psz_module_name )
 
     /* Ugly hack to make sure that the help options always come first
      * (part 1) */
-    if( !psz_module_name )
+    if( !psz_search )
         Usage( p_this, "help" );
 
     /* Enumerate the config for each module */
@@ -1433,13 +1459,15 @@ static void Usage( libvlc_int_t *p_this, char const *psz_module_name )
         module_config_t *p_section = NULL;
         module_config_t *p_end = p_parser->p_config + p_parser->confsize;
 
-        if( psz_module_name && strcmp( psz_module_name,
-                                       p_parser->psz_object_name ) )
+        if( psz_search &&
+            ( b_strict ? strcmp( psz_search, p_parser->psz_object_name )
+                       : !strstr( p_parser->psz_object_name, psz_search ) ) )
         {
             char *const *pp_shortcut = p_parser->pp_shortcuts;
             while( *pp_shortcut )
             {
-                if( !strcmp( psz_module_name, *pp_shortcut ) )
+                if( b_strict ? !strcmp( psz_search, *pp_shortcut )
+                             : !!strstr( *pp_shortcut, psz_search ) )
                     break;
                 pp_shortcut ++;
             }
@@ -1456,7 +1484,7 @@ static void Usage( libvlc_int_t *p_this, char const *psz_module_name )
         b_help_module = !strcmp( "help", p_parser->psz_object_name );
         /* Ugly hack to make sure that the help options always come first
          * (part 2) */
-        if( !psz_module_name && b_help_module )
+        if( !psz_search && b_help_module )
             continue;
 
         /* Ignore modules with only advanced config options if requested */
@@ -1467,16 +1495,25 @@ static void Usage( libvlc_int_t *p_this, char const *psz_module_name )
                  p_item++ )
             {
                 if( (p_item->i_type & CONFIG_ITEM) &&
-                    !p_item->b_advanced ) break;
+                    !p_item->b_advanced && !p_item->b_removed ) break;
+            }
+
+            if( p_item == p_end )
+            {
+                i_only_advanced++;
+                continue;
             }
         }
 
+        b_found = true;
+
         /* Print name of module */
         if( strcmp( "main", p_parser->psz_object_name ) )
         {
             if( b_color )
-                utf8_fprintf( stdout, "\n " GREEN "%s" GRAY "\n",
-                              p_parser->psz_longname );
+                utf8_fprintf( stdout, "\n " GREEN "%s" GRAY " (%s)\n",
+                              p_parser->psz_longname,
+                               p_parser->psz_object_name );
             else
                 utf8_fprintf( stdout, "\n %s\n", p_parser->psz_longname );
         }
@@ -1660,7 +1697,7 @@ static void Usage( libvlc_int_t *p_this, char const *psz_module_name )
 
             if( p_item->i_type == CONFIG_ITEM_BOOL && !b_help_module )
             {
-                utf8_fprintf( stdout, psz_format_bool, psz_short, 
+                utf8_fprintf( stdout, psz_format_bool, psz_short,
                               p_item->psz_name, psz_prefix, p_item->psz_name,
                               psz_bra, psz_type, psz_ket, psz_spaces );
             }
@@ -1774,16 +1811,41 @@ static void Usage( libvlc_int_t *p_this, char const *psz_module_name )
         }
     }
 
-    if( b_has_advanced ) 
+    if( b_has_advanced )
     {
         if( b_color )
             utf8_fprintf( stdout, "\n" WHITE "%s" GRAY " %s\n", _( "Note:" ),
            _( "add --advanced to your command line to see advanced options."));
         else
-            utf8_fprintf( stdout, "\n %s %s\n", _( "Note:" ),
+            utf8_fprintf( stdout, "\n%s %s\n", _( "Note:" ),
            _( "add --advanced to your command line to see advanced options."));
     }
 
+    if( i_only_advanced > 0 )
+    {
+        if( b_color )
+        {
+            utf8_fprintf( stdout, "\n" WHITE "%s" GRAY " ", _( "Note:" ) );
+            utf8_fprintf( stdout, _( "%d module(s) were not displayed because they only have advanced options.\n" ), i_only_advanced );
+        }
+        else
+        {
+            utf8_fprintf( stdout, "\n%s ", _( "Note:" ) );
+            utf8_fprintf( stdout, _( "%d module(s) were not displayed because they only have advanced options.\n" ), i_only_advanced );
+        }
+    }
+    else if( !b_found )
+    {
+        if( b_color )
+            utf8_fprintf( stdout, "\n" WHITE "%s" GRAY "\n",
+                       _( "No matching module found. Use --list or" \
+                          "--list-verbose to list available modules." ) );
+        else
+            utf8_fprintf( stdout, "\n%s\n",
+                       _( "No matching module found. Use --list or" \
+                          "--list-verbose to list available modules." ) );
+    }
+
     /* Release the module list */
     vlc_list_release( p_list );
 }