]> git.sesse.net Git - vlc/commitdiff
Allocate each object variable separately
authorRémi Denis-Courmont <remi@remlab.net>
Wed, 30 Dec 2009 15:01:29 +0000 (17:01 +0200)
committerRémi Denis-Courmont <remi@remlab.net>
Wed, 30 Dec 2009 15:15:43 +0000 (17:15 +0200)
This reduces the amount of memory copied when creating/deleting a
variable on an object. We now use a table of pointers instead of table
of variable_t.

This also simplifies callback handling a bit as the variable_t cannot
move anymore while we wait. Earlier another thread could add or remove
another variable on the same object, thus changing the variable table.

With this change, we could also store non-serialized data (i.e.
non-movable with memcpy/memmove) directly inside variable_t.

src/libvlc.h
src/misc/objects.c
src/misc/variables.c

index 629a28fe7dd3dcdf41047037fc1438c8e458e034..640c4b8226fd7536822e74eba629c392dc952663 100644 (file)
@@ -162,7 +162,7 @@ typedef struct vlc_object_internals_t
     char           *psz_name; /* given name */
 
     /* Object variables */
-    variable_t *    p_vars;
+    variable_t    **pp_vars;
     vlc_mutex_t     var_lock;
     vlc_cond_t      var_wait;
     int             i_vars;
index fa3805e4ea60fd8828c572522e49db5eee419fe6..ac40fcd189a72b174e3a65f9b3351a62057ad85e 100644 (file)
@@ -131,13 +131,7 @@ void *__vlc_custom_create( vlc_object_t *p_this, size_t i_size,
         p_new->i_flags = p_this->i_flags
             & (OBJECT_FLAGS_NODBG|OBJECT_FLAGS_QUIET|OBJECT_FLAGS_NOINTERACT);
 
-    p_priv->p_vars = calloc( 16, sizeof( variable_t ) );
-
-    if( !p_priv->p_vars )
-    {
-        free( p_priv );
-        return NULL;
-    }
+    p_priv->pp_vars = NULL;
 
     if( p_this == NULL )
     {
@@ -291,10 +285,9 @@ static void vlc_object_destroy( vlc_object_t *p_this )
      * no memmove calls have to be done. */
     while( p_priv->i_vars )
     {
-        var_Destroy( p_this, p_priv->p_vars[p_priv->i_vars - 1].psz_name );
+        var_Destroy( p_this, p_priv->pp_vars[p_priv->i_vars - 1]->psz_name );
     }
 
-    free( p_priv->p_vars );
     vlc_cond_destroy( &p_priv->var_wait );
     vlc_mutex_destroy( &p_priv->var_lock );
 
@@ -822,7 +815,7 @@ static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
             printf( " `-o No variables\n" );
         for( i = 0; i < vlc_internals( p_object )->i_vars; i++ )
         {
-            variable_t *p_var = vlc_internals( p_object )->p_vars + i;
+            const variable_t *p_var = vlc_internals( p_object )->pp_vars[i];
             const char *psz_type = "unknown";
 
             switch( p_var->i_type & VLC_VAR_TYPE )
index b930544a5e4fa1fca50bb24b8997bc04f54362e7..cf63b065c5242fd5e61163f24832e4529849675d 100644 (file)
@@ -154,15 +154,15 @@ time_ops   = { CmpTime,    DupDummy,  FreeDummy,  };
  *****************************************************************************/
 static int      GetUnused   ( vlc_object_t *, const char * );
 static uint32_t HashString  ( const char * );
-static int      Insert      ( variable_t *, int, const char * );
-static int      InsertInner ( variable_t *, int, uint32_t );
-static int      Lookup      ( variable_t *, size_t, const char * );
+static int      Insert      ( variable_t **, int, const char * );
+static int      InsertInner ( variable_t **, int, uint32_t );
+static int      Lookup      ( variable_t **, size_t, const char * );
 
 static void     CheckValue  ( variable_t *, vlc_value_t * );
 
 static int      InheritValue( vlc_object_t *, const char *, vlc_value_t *,
                               int );
-static int      TriggerCallback( vlc_object_t *, variable_t **, const char *,
+static int      TriggerCallback( vlc_object_t *, variable_t *, const char *,
                                  vlc_value_t );
 
 /**
@@ -179,12 +179,12 @@ static int      TriggerCallback( vlc_object_t *, variable_t **, const char *,
  */
 int __var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
 {
-    variable_t var, *p_var = &var;
     static vlc_list_t dummy_null_list = {0, NULL, NULL};
-
     assert( p_this );
 
-    memset( p_var, 0, sizeof(*p_var) );
+    variable_t *p_var = calloc( 1, sizeof( *p_var ) );
+    if( p_var == NULL )
+        return VLC_ENOMEM;
 
     p_var->i_hash = HashString( psz_name );
     p_var->psz_name = strdup( psz_name );
@@ -274,22 +274,22 @@ int __var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
      * duplicate the lookups. It's not that serious, but if anyone finds some
      * time to rework Insert() so that only one lookup has to be done, feel
      * free to do so. */
-    i_new = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
+    i_new = Lookup( p_priv->pp_vars, p_priv->i_vars, psz_name );
 
     if( i_new >= 0 )
     {
         /* If the types differ, variable creation failed. */
-        if( (i_type & VLC_VAR_CLASS) != (p_priv->p_vars[i_new].i_type & VLC_VAR_CLASS) )
+        if( (i_type & VLC_VAR_CLASS) != (p_priv->pp_vars[i_new]->i_type & VLC_VAR_CLASS) )
         {
             msg_Err( p_this, "Variable '%s' (0x%04x) already exist but with a different type (0x%04x)",
-                     psz_name, p_priv->p_vars[i_new].i_type, i_type );
+                     psz_name, p_priv->pp_vars[i_new]->i_type, i_type );
             vlc_mutex_unlock( &p_priv->var_lock );
             return VLC_EBADVAR;
         }
 
-        p_priv->p_vars[i_new].i_usage++;
-        p_priv->p_vars[i_new].i_type |= ( i_type & VLC_VAR_ISCOMMAND );
-        p_priv->p_vars[i_new].i_type |= ( i_type & VLC_VAR_HASCHOICE );
+        p_priv->pp_vars[i_new]->i_usage++;
+        p_priv->pp_vars[i_new]->i_type |= ( i_type & VLC_VAR_ISCOMMAND );
+        p_priv->pp_vars[i_new]->i_type |= ( i_type & VLC_VAR_HASCHOICE );
         vlc_mutex_unlock( &p_priv->var_lock );
 
         /* We did not need to create a new variable, free everything... */
@@ -305,24 +305,23 @@ int __var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
             free( p_var->choices.p_values );
             free( p_var->choices_text.p_values );
         }
+        free( p_var );
         return VLC_SUCCESS;
     }
 
-    i_new = Insert( p_priv->p_vars, p_priv->i_vars, psz_name );
+    i_new = Insert( p_priv->pp_vars, p_priv->i_vars, psz_name );
 
-    if( (p_priv->i_vars & 15) == 15 )
-    {
-        p_priv->p_vars = xrealloc( p_priv->p_vars,
-                                  (p_priv->i_vars+17) * sizeof(variable_t) );
-    }
+    if( (p_priv->i_vars & 15) == 0 )
+        p_priv->pp_vars = xrealloc( p_priv->pp_vars,
+                                 (p_priv->i_vars+16) * sizeof(variable_t *) );
 
-    memmove( p_priv->p_vars + i_new + 1,
-             p_priv->p_vars + i_new,
-             (p_priv->i_vars - i_new) * sizeof(variable_t) );
+    memmove( p_priv->pp_vars + i_new + 1,
+             p_priv->pp_vars + i_new,
+             (p_priv->i_vars - i_new) * sizeof(variable_t *) );
 
     p_priv->i_vars++;
 
-    p_priv->p_vars[i_new] = var;
+    p_priv->pp_vars[i_new] = p_var;
     vlc_mutex_unlock( &p_priv->var_lock );
 
     return VLC_SUCCESS;
@@ -355,7 +354,7 @@ int __var_Destroy( vlc_object_t *p_this, const char *psz_name )
         return i_var;
     }
 
-    p_var = &p_priv->p_vars[i_var];
+    p_var = p_priv->pp_vars[i_var];
 
     if( p_var->i_usage > 1 )
     {
@@ -385,22 +384,28 @@ int __var_Destroy( vlc_object_t *p_this, const char *psz_name )
     free( p_var->psz_name );
     free( p_var->psz_text );
 
-    memmove( p_priv->p_vars + i_var,
-             p_priv->p_vars + i_var + 1,
-             (p_priv->i_vars - i_var - 1) * sizeof(variable_t) );
+    p_priv->i_vars--;
+    memmove( p_priv->pp_vars + i_var,
+             p_priv->pp_vars + i_var + 1,
+             (p_priv->i_vars - i_var) * sizeof(variable_t *) );
 
+    if( p_priv->i_vars == 0 )
+    {
+        free( p_priv->pp_vars );
+        p_priv->pp_vars = NULL;
+    }
+    else
     if( (p_priv->i_vars & 15) == 0 )
     {
-        variable_t *p_vars = realloc( p_priv->p_vars,
-                                    (p_priv->i_vars) * sizeof( variable_t ) );
-        if( p_vars )
-            p_priv->p_vars = p_vars;
+        variable_t **pp_vars = realloc( p_priv->pp_vars,
+                                    (p_priv->i_vars) * sizeof(variable_t *) );
+        if( pp_vars != NULL )
+            p_priv->pp_vars = pp_vars;
     }
 
-    p_priv->i_vars--;
-
     vlc_mutex_unlock( &p_priv->var_lock );
 
+    free( p_var );
     return VLC_SUCCESS;
 }
 
@@ -426,7 +431,7 @@ int __var_Change( vlc_object_t *p_this, const char *psz_name,
 
     vlc_mutex_lock( &p_priv->var_lock );
 
-    i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
+    i_var = Lookup( p_priv->pp_vars, p_priv->i_vars, psz_name );
 
     if( i_var < 0 )
     {
@@ -434,7 +439,7 @@ int __var_Change( vlc_object_t *p_this, const char *psz_name,
         return VLC_ENOVAR;
     }
 
-    p_var = &p_priv->p_vars[i_var];
+    p_var = p_priv->pp_vars[i_var];
 
     switch( i_action )
     {
@@ -672,7 +677,7 @@ int __var_GetAndSet( vlc_object_t *p_this, const char *psz_name, int i_action,
         return i_var;
     }
 
-    p_var = &p_priv->p_vars[i_var];
+    p_var = p_priv->pp_vars[i_var];
 
     /* Duplicated data if needed */
     //p_var->ops->pf_dup( &val );
@@ -701,7 +706,7 @@ int __var_GetAndSet( vlc_object_t *p_this, const char *psz_name, int i_action,
 
     /* Deal with callbacks.*/
     if( p_var->i_entries )
-        i_ret = TriggerCallback( p_this, &p_var, psz_name, oldval );
+        i_ret = TriggerCallback( p_this, p_var, psz_name, oldval );
 
     vlc_mutex_unlock( &p_priv->var_lock );
 
@@ -726,7 +731,7 @@ int __var_Type( vlc_object_t *p_this, const char *psz_name )
 
     vlc_mutex_lock( &p_priv->var_lock );
 
-    i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
+    i_var = Lookup( p_priv->pp_vars, p_priv->i_vars, psz_name );
 
     if( i_var < 0 )
     {
@@ -734,7 +739,7 @@ int __var_Type( vlc_object_t *p_this, const char *psz_name )
         return 0;
     }
 
-    i_type = p_priv->p_vars[i_var].i_type;
+    i_type = p_priv->pp_vars[i_var]->i_type;
 
     vlc_mutex_unlock( &p_priv->var_lock );
 
@@ -762,7 +767,7 @@ int var_SetChecked( vlc_object_t *p_this, const char *psz_name,
         return i_var;
     }
 
-    p_var = &p_priv->p_vars[i_var];
+    p_var = p_priv->pp_vars[i_var];
     assert( expected_type == 0 ||
             (p_var->i_type & VLC_VAR_CLASS) == expected_type );
 
@@ -780,7 +785,7 @@ int var_SetChecked( vlc_object_t *p_this, const char *psz_name,
 
     /* Deal with callbacks */
     if( p_var->i_entries )
-        i_ret = TriggerCallback( p_this, &p_var, psz_name, oldval );
+        i_ret = TriggerCallback( p_this, p_var, psz_name, oldval );
 
     /* Free data if needed */
     p_var->ops->pf_free( &oldval );
@@ -813,10 +818,10 @@ int var_GetChecked( vlc_object_t *p_this, const char *psz_name,
 
     vlc_mutex_lock( &p_priv->var_lock );
 
-    i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
+    i_var = Lookup( p_priv->pp_vars, p_priv->i_vars, psz_name );
     if( i_var >= 0 )
     {
-        variable_t *p_var = &p_priv->p_vars[i_var];
+        variable_t *p_var = p_priv->pp_vars[i_var];
 
         assert( expected_type == 0 ||
                 (p_var->i_type & VLC_VAR_CLASS) == expected_type );
@@ -896,7 +901,7 @@ int __var_AddCallback( vlc_object_t *p_this, const char *psz_name,
         return i_var;
     }
 
-    p_var = &p_priv->p_vars[i_var];
+    p_var = p_priv->pp_vars[i_var];
 
     INSERT_ELEM( p_var->p_entries,
                  p_var->i_entries,
@@ -936,7 +941,7 @@ int __var_DelCallback( vlc_object_t *p_this, const char *psz_name,
         return i_var;
     }
 
-    p_var = &p_priv->p_vars[i_var];
+    p_var = p_priv->pp_vars[i_var];
 
     for( i_entry = p_var->i_entries ; i_entry-- ; )
     {
@@ -995,12 +1000,12 @@ int __var_TriggerCallback( vlc_object_t *p_this, const char *psz_name )
         return i_var;
     }
 
-    p_var = &p_priv->p_vars[i_var];
+    p_var = p_priv->pp_vars[i_var];
 
     /* Deal with callbacks. Tell we're in a callback, release the lock,
      * call stored functions, retake the lock. */
     if( p_var->i_entries )
-        i_ret = TriggerCallback( p_this, &p_var, psz_name, p_var->val );
+        i_ret = TriggerCallback( p_this, p_var, psz_name, p_var->val );
 
     vlc_mutex_unlock( &p_priv->var_lock );
     return i_ret;
@@ -1171,13 +1176,13 @@ static int GetUnused( vlc_object_t *p_this, const char *psz_name )
     {
         int i_var;
 
-        i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
+        i_var = Lookup( p_priv->pp_vars, p_priv->i_vars, psz_name );
         if( i_var < 0 )
         {
             return VLC_ENOVAR;
         }
 
-        if( ! p_priv->p_vars[i_var].b_incallback )
+        if( ! p_priv->pp_vars[i_var]->b_incallback )
         {
             return i_var;
         }
@@ -1217,26 +1222,26 @@ static uint32_t HashString( const char *psz_string )
  * to see how we handle them.
  * XXX: does this really need to be written recursively?
  *****************************************************************************/
-static int Insert( variable_t *p_vars, int i_count, const char *psz_name )
+static int Insert( variable_t **pp_vars, int i_count, const char *psz_name )
 {
     if( i_count == 0 )
     {
         return 0;
     }
 
-    return InsertInner( p_vars, i_count, HashString( psz_name ) );
+    return InsertInner( pp_vars, i_count, HashString( psz_name ) );
 }
 
-static int InsertInner( variable_t *p_vars, int i_count, uint32_t i_hash )
+static int InsertInner( variable_t **pp_vars, int i_count, uint32_t i_hash )
 {
     int i_middle;
 
-    if( i_hash <= p_vars[0].i_hash )
+    if( i_hash <= pp_vars[0]->i_hash )
     {
         return 0;
     }
 
-    if( i_hash >= p_vars[i_count - 1].i_hash )
+    if( i_hash >= pp_vars[i_count - 1]->i_hash )
     {
         return i_count;
     }
@@ -1244,15 +1249,15 @@ static int InsertInner( variable_t *p_vars, int i_count, uint32_t i_hash )
     i_middle = i_count / 2;
 
     /* We know that 0 < i_middle */
-    if( i_hash < p_vars[i_middle].i_hash )
+    if( i_hash < pp_vars[i_middle]->i_hash )
     {
-        return InsertInner( p_vars, i_middle, i_hash );
+        return InsertInner( pp_vars, i_middle, i_hash );
     }
 
     /* We know that i_middle + 1 < i_count */
-    if( i_hash > p_vars[i_middle + 1].i_hash )
+    if( i_hash > pp_vars[i_middle + 1]->i_hash )
     {
-        return i_middle + 1 + InsertInner( p_vars + i_middle + 1,
+        return i_middle + 1 + InsertInner( pp_vars + i_middle + 1,
                                            i_count - i_middle - 1,
                                            i_hash );
     }
@@ -1262,12 +1267,12 @@ static int InsertInner( variable_t *p_vars, int i_count, uint32_t i_hash )
 
 static int u32cmp( const void *key, const void *data )
 {
-    const variable_t *p_var = data;
+    const variable_t *const *pp_var = data;
     uint32_t hash = *(const uint32_t *)key ;
 
-    if( hash > p_var->i_hash )
+    if( hash > (*pp_var)->i_hash )
         return 1;
-    if( hash < p_var->i_hash )
+    if( hash < (*pp_var)->i_hash )
         return -1;
     return 0;
 }
@@ -1278,35 +1283,35 @@ static int u32cmp( const void *key, const void *data )
  * We use a recursive inner function indexed on the hash. Care is taken of
  * possible hash collisions.
  *****************************************************************************/
-static int Lookup( variable_t *p_vars, size_t i_count, const char *psz_name )
+static int Lookup( variable_t **pp_vars, size_t i_count, const char *psz_name )
 {
-    variable_t *p_var;
+    variable_t **pp_var;
     uint32_t i_hash;
 
     i_hash = HashString( psz_name );
-    p_var = bsearch( &i_hash, p_vars, i_count, sizeof( *p_var ), u32cmp );
+    pp_var = bsearch( &i_hash, pp_vars, i_count, sizeof( *pp_var ), u32cmp );
 
     /* Hash not found */
-    if( p_var == NULL )
+    if( pp_var == NULL )
         return -1;
 
     assert( i_count > 0 );
 
     /* Find the first entry with the right hash */
-    while( (p_var > p_vars) && (i_hash == p_var[-1].i_hash) )
-        p_var--;
+    while( (pp_var > pp_vars) && (i_hash == pp_var[-1]->i_hash) )
+        pp_var--;
 
-    assert( p_var->i_hash == i_hash );
+    assert( (*pp_var)->i_hash == i_hash );
 
     /* Hash collision should be very unlikely, but we cannot guarantee
      * it will never happen. So we do an exhaustive search amongst all
      * entries with the same hash. Typically, there is only one anyway. */
-    for( variable_t *p_end = p_vars + i_count;
-         (p_var < p_end) && (i_hash == p_var->i_hash);
-         p_var++ )
+    for( variable_t **p_end = pp_vars + i_count;
+         (pp_var < p_end) && (i_hash == (*pp_var)->i_hash);
+         pp_var++ )
     {
-        if( !strcmp( psz_name, p_var->psz_name ) )
-            return p_var - p_vars;
+        if( !strcmp( psz_name, (*pp_var)->psz_name ) )
+            return pp_var - pp_vars;
     }
 
     /* Hash found, but entry not found */
@@ -1469,41 +1474,31 @@ static int InheritValue( vlc_object_t *p_this, const char *psz_name,
  * Tell we're in a callback, release the lock, call stored functions,
  * retake the lock.
  **********************************************************************/
-static int TriggerCallback( vlc_object_t *p_this, variable_t **pp_var,
+static int TriggerCallback( vlc_object_t *p_this, variable_t *p_var,
                             const char *psz_name, vlc_value_t oldval )
 {
-    int i_var;
-    int i_entries = (*pp_var)->i_entries;
-    callback_entry_t *p_entries = (*pp_var)->p_entries;
+    int i_entries = p_var->i_entries;
+    callback_entry_t *p_entries = p_var->p_entries;
 
     assert( p_this );
 
     vlc_object_internals_t *p_priv = vlc_internals( p_this );
 
-    (*pp_var)->b_incallback = true;
+    p_var->b_incallback = true;
     vlc_mutex_unlock( &p_priv->var_lock );
 
     /* The real calls */
     for( ; i_entries-- ; )
     {
-        p_entries[i_entries].pf_callback( p_this, psz_name, oldval, (*pp_var)->val,
+        p_entries[i_entries].pf_callback( p_this, psz_name, oldval, p_var->val,
                                           p_entries[i_entries].p_data );
     }
 
     vlc_mutex_lock( &p_priv->var_lock );
+    p_var->b_incallback = false;
+    vlc_cond_broadcast( &p_priv->var_wait );
 
-    i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
-    if( i_var < 0 )
-    {
-        msg_Err( p_this, "variable %s has disappeared", psz_name );
-        return VLC_ENOVAR;
-     }
-
-     *pp_var = &p_priv->p_vars[i_var];
-     (*pp_var)->b_incallback = false;
-     vlc_cond_broadcast( &p_priv->var_wait );
-
-     return VLC_SUCCESS;
+    return VLC_SUCCESS;
 }