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.
char *psz_name; /* given name */
/* Object variables */
char *psz_name; /* given name */
/* Object variables */
vlc_mutex_t var_lock;
vlc_cond_t var_wait;
int i_vars;
vlc_mutex_t var_lock;
vlc_cond_t var_wait;
int i_vars;
p_new->i_flags = p_this->i_flags
& (OBJECT_FLAGS_NODBG|OBJECT_FLAGS_QUIET|OBJECT_FLAGS_NOINTERACT);
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;
* no memmove calls have to be done. */
while( p_priv->i_vars )
{
* 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 );
vlc_cond_destroy( &p_priv->var_wait );
vlc_mutex_destroy( &p_priv->var_lock );
printf( " `-o No variables\n" );
for( i = 0; i < vlc_internals( p_object )->i_vars; i++ )
{
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 )
const char *psz_type = "unknown";
switch( p_var->i_type & VLC_VAR_TYPE )
*****************************************************************************/
static int GetUnused ( vlc_object_t *, const char * );
static uint32_t HashString ( const char * );
*****************************************************************************/
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 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 *,
*/
int __var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
{
*/
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};
static vlc_list_t dummy_null_list = {0, NULL, NULL};
- 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 );
p_var->i_hash = HashString( psz_name );
p_var->psz_name = strdup( psz_name );
* 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. */
* 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_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)",
{
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;
}
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... */
vlc_mutex_unlock( &p_priv->var_lock );
/* We did not need to create a new variable, free everything... */
free( p_var->choices.p_values );
free( p_var->choices_text.p_values );
}
free( p_var->choices.p_values );
free( p_var->choices_text.p_values );
}
- 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->p_vars[i_new] = var;
+ p_priv->pp_vars[i_new] = p_var;
vlc_mutex_unlock( &p_priv->var_lock );
return VLC_SUCCESS;
vlc_mutex_unlock( &p_priv->var_lock );
return VLC_SUCCESS;
- p_var = &p_priv->p_vars[i_var];
+ p_var = p_priv->pp_vars[i_var];
if( p_var->i_usage > 1 )
{
if( p_var->i_usage > 1 )
{
free( p_var->psz_name );
free( p_var->psz_text );
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 )
{
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;
vlc_mutex_unlock( &p_priv->var_lock );
vlc_mutex_unlock( &p_priv->var_lock );
vlc_mutex_lock( &p_priv->var_lock );
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 );
- p_var = &p_priv->p_vars[i_var];
+ p_var = p_priv->pp_vars[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 );
/* Duplicated data if needed */
//p_var->ops->pf_dup( &val );
/* Deal with callbacks.*/
if( p_var->i_entries )
/* 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 );
vlc_mutex_unlock( &p_priv->var_lock );
vlc_mutex_lock( &p_priv->var_lock );
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 );
- 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 );
vlc_mutex_unlock( &p_priv->var_lock );
- 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 );
assert( expected_type == 0 ||
(p_var->i_type & VLC_VAR_CLASS) == expected_type );
/* Deal with callbacks */
if( p_var->i_entries )
/* 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 );
/* Free data if needed */
p_var->ops->pf_free( &oldval );
vlc_mutex_lock( &p_priv->var_lock );
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 );
- 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 );
assert( expected_type == 0 ||
(p_var->i_type & VLC_VAR_CLASS) == expected_type );
- 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,
INSERT_ELEM( p_var->p_entries,
p_var->i_entries,
- 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-- ; )
{
for( i_entry = p_var->i_entries ; i_entry-- ; )
{
- 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 )
/* 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;
vlc_mutex_unlock( &p_priv->var_lock );
return i_ret;
- 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( i_var < 0 )
{
return VLC_ENOVAR;
}
- if( ! p_priv->p_vars[i_var].b_incallback )
+ if( ! p_priv->pp_vars[i_var]->b_incallback )
* to see how we handle them.
* XXX: does this really need to be written recursively?
*****************************************************************************/
* 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;
}
{
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 )
- if( i_hash <= p_vars[0].i_hash )
+ if( i_hash <= pp_vars[0]->i_hash )
- if( i_hash >= p_vars[i_count - 1].i_hash )
+ if( i_hash >= pp_vars[i_count - 1]->i_hash )
i_middle = i_count / 2;
/* We know that 0 < i_middle */
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 */
}
/* 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 );
}
i_count - i_middle - 1,
i_hash );
}
static int u32cmp( const void *key, const void *data )
{
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 ;
uint32_t hash = *(const uint32_t *)key ;
- if( hash > p_var->i_hash )
+ if( hash > (*pp_var)->i_hash )
- if( hash < p_var->i_hash )
+ if( hash < (*pp_var)->i_hash )
* We use a recursive inner function indexed on the hash. Care is taken of
* possible hash collisions.
*****************************************************************************/
* 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 )
uint32_t i_hash;
i_hash = HashString( psz_name );
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 );
return -1;
assert( i_count > 0 );
/* Find the first entry with the right hash */
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. */
/* 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 */
}
/* Hash found, but entry not found */
* Tell we're in a callback, release the lock, call stored functions,
* retake the lock.
**********************************************************************/
* 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 )
{
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 );
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-- ; )
{
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_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;