[vlc-devel] [PATCH 1/2] variables: var_CreateOps creates variable with create/dup/free callbacks
Antti Ajanki
antti.ajanki at iki.fi
Tue Sep 9 18:58:15 CEST 2014
Use case: A reference counted variable can be safely stored as
VLC_VAR_VARIABLE if it is created with callbacks that correctly
manipulate the reference count.
---
include/vlc_variables.h | 11 ++++
src/misc/variables.c | 150 +++++++++++++++++++++++++++++++++--------------
src/misc/variables.h | 2 +-
3 files changed, 119 insertions(+), 44 deletions(-)
diff --git a/include/vlc_variables.h b/include/vlc_variables.h
index 6f48aa1..3a81d9a 100644
--- a/include/vlc_variables.h
+++ b/include/vlc_variables.h
@@ -138,12 +138,23 @@ enum {
};
/**@}*/
+typedef struct variable_management_ops_t
+{
+ vlc_value_t (*pf_init) ();
+ int (*pf_cmp) ( vlc_value_t, vlc_value_t );
+ void (*pf_dup) ( vlc_value_t * );
+ void (*pf_free) ( vlc_value_t * );
+} variable_management_ops_t;
+
/*****************************************************************************
* Prototypes
*****************************************************************************/
VLC_API int var_Create( vlc_object_t *, const char *, int );
#define var_Create(a,b,c) var_Create( VLC_OBJECT(a), b, c )
+VLC_API int var_CreateOps( vlc_object_t *, const char *, int, const variable_management_ops_t * );
+#define var_CreateOps(a,b,c,d) var_CreateOps( VLC_OBJECT(a), b, c, d )
+
VLC_API int var_Destroy( vlc_object_t *, const char * );
#define var_Destroy(a,b) var_Destroy( VLC_OBJECT(a), b )
diff --git a/src/misc/variables.c b/src/misc/variables.c
index 19b5fb7..07a1b9c 100644
--- a/src/misc/variables.c
+++ b/src/misc/variables.c
@@ -145,6 +145,12 @@ static int TriggerListCallback( vlc_object_t *, variable_t *,
const char *, int,
vlc_value_t * );
+static int InheritWithOps( vlc_object_t *, const char *, int,
+ vlc_value_t *, variable_ops_t * );
+
+static int GetCheckedWithOps( vlc_object_t *, const char *, int,
+ vlc_value_t *, variable_ops_t * );
+
static int varcmp( const void *a, const void *b )
{
const variable_t *va = a, *vb = b;
@@ -166,12 +172,12 @@ static variable_t *Lookup( vlc_object_t *obj, const char *psz_name )
static void Destroy( variable_t *p_var )
{
- p_var->ops->pf_free( &p_var->val );
+ p_var->ops.pf_free( &p_var->val );
if( p_var->choices.i_count )
{
for( int i = 0 ; i < p_var->choices.i_count ; i++ )
{
- p_var->ops->pf_free( &p_var->choices.p_values[i] );
+ p_var->ops.pf_free( &p_var->choices.p_values[i] );
free( p_var->choices_text.p_values[i].psz_string );
}
free( p_var->choices.p_values );
@@ -207,6 +213,24 @@ static void Destroy( variable_t *p_var )
/**
* Initialize a vlc variable
*
+ * \param p_this The object in which to create the variable
+ * \param psz_name The name of the variable
+ * \param i_type The variables type. Must be one of \ref var_type combined with
+ * zero or more \ref var_flags
+ */
+int var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
+{
+ return var_CreateOps( p_this, psz_name, i_type, NULL );
+}
+
+#undef var_CreateOps
+/**
+ * Initialize a vlc variable with callbacks
+ *
+ * If p_ops is defined, the callbacks in p_ops will be used to create,
+ * copy and release the value of this variable. The callbacks will be
+ * called with the variable mutex locked.
+ *
* We hash the given string and insert it into the sorted list. The insertion
* may require slow memory copies, but think about what we gain in the log(n)
* lookup phase when setting/getting the variable value!
@@ -215,8 +239,9 @@ static void Destroy( variable_t *p_var )
* \param psz_name The name of the variable
* \param i_type The variables type. Must be one of \ref var_type combined with
* zero or more \ref var_flags
+ * \param p_ops An optional structure of resource management callbacks
*/
-int var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
+int var_CreateOps( vlc_object_t *p_this, const char *psz_name, int i_type, const variable_management_ops_t *p_ops )
{
assert( p_this );
@@ -246,43 +271,58 @@ int var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
switch( i_type & VLC_VAR_CLASS )
{
case VLC_VAR_BOOL:
- p_var->ops = &bool_ops;
+ p_var->ops = bool_ops;
p_var->val.b_bool = false;
break;
case VLC_VAR_INTEGER:
- p_var->ops = &int_ops;
+ p_var->ops = int_ops;
p_var->val.i_int = 0;
break;
case VLC_VAR_STRING:
- p_var->ops = &string_ops;
+ p_var->ops = string_ops;
p_var->val.psz_string = NULL;
break;
case VLC_VAR_FLOAT:
- p_var->ops = &float_ops;
+ p_var->ops = float_ops;
p_var->val.f_float = 0.0;
break;
case VLC_VAR_TIME:
- p_var->ops = &time_ops;
+ p_var->ops = time_ops;
p_var->val.i_time = 0;
break;
case VLC_VAR_COORDS:
- p_var->ops = &coords_ops;
+ p_var->ops = coords_ops;
p_var->val.coords.x = p_var->val.coords.y = 0;
break;
case VLC_VAR_ADDRESS:
- p_var->ops = &addr_ops;
+ p_var->ops = addr_ops;
p_var->val.p_address = NULL;
break;
case VLC_VAR_VOID:
- p_var->ops = &void_ops;
+ p_var->ops = void_ops;
break;
default:
assert (0);
}
+ if ( p_ops )
+ {
+ assert( p_ops->pf_init );
+ assert( p_ops->pf_cmp );
+ assert( p_ops->pf_dup );
+ assert( p_ops->pf_free );
+
+ p_var->ops.pf_cmp = p_ops->pf_cmp;
+ p_var->ops.pf_dup = p_ops->pf_dup;
+ p_var->ops.pf_free = p_ops->pf_free;
+ }
+
+ bool initialized_by_inherit = false;
if( (i_type & VLC_VAR_DOINHERIT)
- && var_Inherit( p_this, psz_name, i_type, &p_var->val ) == 0 )
+ && InheritWithOps( p_this, psz_name, i_type, &p_var->val, &p_var->ops ) == 0 )
{
+ initialized_by_inherit = true;
+
if( i_type & VLC_VAR_HASCHOICE )
{
/* We must add the inherited value to our choice list */
@@ -292,7 +332,7 @@ int var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
0, p_var->val );
INSERT_ELEM( p_var->choices_text.p_values,
p_var->choices_text.i_count, 0, p_var->val );
- p_var->ops->pf_dup( &p_var->choices.p_values[0] );
+ p_var->ops.pf_dup( &p_var->choices.p_values[0] );
p_var->choices_text.p_values[0].psz_string = NULL;
}
}
@@ -307,7 +347,11 @@ int var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
if( unlikely(pp_var == NULL) )
ret = VLC_ENOMEM;
else if( (p_oldvar = *pp_var) == p_var ) /* Variable create */
+ {
p_var = NULL; /* Variable created */
+ if ( p_ops && !initialized_by_inherit )
+ (*pp_var)->val = p_ops->pf_init();
+ }
else /* Variable already exists */
{
assert (((i_type ^ p_oldvar->i_type) & VLC_VAR_CLASS) == 0);
@@ -411,11 +455,11 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
case VLC_VAR_SETMIN:
if( p_var->i_type & VLC_VAR_HASMIN )
{
- p_var->ops->pf_free( &p_var->min );
+ p_var->ops.pf_free( &p_var->min );
}
p_var->i_type |= VLC_VAR_HASMIN;
p_var->min = *p_val;
- p_var->ops->pf_dup( &p_var->min );
+ p_var->ops.pf_dup( &p_var->min );
CheckValue( p_var, &p_var->val );
break;
case VLC_VAR_GETMIN:
@@ -427,11 +471,11 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
case VLC_VAR_SETMAX:
if( p_var->i_type & VLC_VAR_HASMAX )
{
- p_var->ops->pf_free( &p_var->max );
+ p_var->ops.pf_free( &p_var->max );
}
p_var->i_type |= VLC_VAR_HASMAX;
p_var->max = *p_val;
- p_var->ops->pf_dup( &p_var->max );
+ p_var->ops.pf_dup( &p_var->max );
CheckValue( p_var, &p_var->val );
break;
case VLC_VAR_GETMAX:
@@ -443,11 +487,11 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
case VLC_VAR_SETSTEP:
if( p_var->i_type & VLC_VAR_HASSTEP )
{
- p_var->ops->pf_free( &p_var->step );
+ p_var->ops.pf_free( &p_var->step );
}
p_var->i_type |= VLC_VAR_HASSTEP;
p_var->step = *p_val;
- p_var->ops->pf_dup( &p_var->step );
+ p_var->ops.pf_dup( &p_var->step );
CheckValue( p_var, &p_var->val );
break;
case VLC_VAR_GETSTEP:
@@ -464,7 +508,7 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
i, *p_val );
INSERT_ELEM( p_var->choices_text.p_values,
p_var->choices_text.i_count, i, *p_val );
- p_var->ops->pf_dup( &p_var->choices.p_values[i] );
+ p_var->ops.pf_dup( &p_var->choices.p_values[i] );
p_var->choices_text.p_values[i].psz_string =
( p_val2 && p_val2->psz_string ) ?
strdup( p_val2->psz_string ) : NULL;
@@ -479,7 +523,7 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
int i;
for( i = 0 ; i < p_var->choices.i_count ; i++ )
- if( p_var->ops->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 )
+ if( p_var->ops.pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 )
break;
if( i == p_var->choices.i_count )
@@ -494,7 +538,7 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
else if( p_var->i_default == i )
p_var->i_default = -1;
- p_var->ops->pf_free( &p_var->choices.p_values[i] );
+ p_var->ops.pf_free( &p_var->choices.p_values[i] );
free( p_var->choices_text.p_values[i].psz_string );
REMOVE_ELEM( p_var->choices.p_values, p_var->choices.i_count, i );
REMOVE_ELEM( p_var->choices_text.p_values,
@@ -510,7 +554,7 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
break;
case VLC_VAR_CLEARCHOICES:
for( int i = 0 ; i < p_var->choices.i_count ; i++ )
- p_var->ops->pf_free( &p_var->choices.p_values[i] );
+ p_var->ops.pf_free( &p_var->choices.p_values[i] );
for( int i = 0 ; i < p_var->choices_text.i_count ; i++ )
free( p_var->choices_text.p_values[i].psz_string );
@@ -529,7 +573,7 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
int i;
/* FIXME: the list is sorted, dude. Use something cleverer. */
for( i = 0 ; i < p_var->choices.i_count ; i++ )
- if( p_var->ops->pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 )
+ if( p_var->ops.pf_cmp( p_var->choices.p_values[i], *p_val ) == 0 )
break;
if( i == p_var->choices.i_count )
@@ -543,7 +587,7 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
case VLC_VAR_SETVALUE:
/* Duplicate data if needed */
newval = *p_val;
- p_var->ops->pf_dup( &newval );
+ p_var->ops.pf_dup( &newval );
/* Backup needed stuff */
oldval = p_var->val;
/* Check boundaries and list */
@@ -551,7 +595,7 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
/* Set the variable */
p_var->val = newval;
/* Free data if needed */
- p_var->ops->pf_free( &oldval );
+ p_var->ops.pf_free( &oldval );
break;
case VLC_VAR_GETCHOICES:
case VLC_VAR_GETLIST:
@@ -577,7 +621,7 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
{
p_val->p_list->p_values[i] = p_var->choices.p_values[i];
p_val->p_list->pi_types[i] = p_var->i_type;
- p_var->ops->pf_dup( &p_val->p_list->p_values[i] );
+ p_var->ops.pf_dup( &p_val->p_list->p_values[i] );
if( p_val2 )
{
p_val2->p_list->p_values[i].psz_string =
@@ -640,7 +684,7 @@ int var_GetAndSet( vlc_object_t *p_this, const char *psz_name, int i_action,
WaitUnused( p_this, p_var );
/* Duplicated data if needed */
- //p_var->ops->pf_dup( &val );
+ //p_var->ops.pf_dup( &val );
/* Backup needed stuff */
oldval = p_var->val;
@@ -737,7 +781,7 @@ int var_SetChecked( vlc_object_t *p_this, const char *psz_name,
WaitUnused( p_this, p_var );
/* Duplicate data if needed */
- p_var->ops->pf_dup( &val );
+ p_var->ops.pf_dup( &val );
/* Backup needed stuff */
oldval = p_var->val;
@@ -752,7 +796,7 @@ int var_SetChecked( vlc_object_t *p_this, const char *psz_name,
i_ret = TriggerCallback( p_this, p_var, psz_name, oldval );
/* Free data if needed */
- p_var->ops->pf_free( &oldval );
+ p_var->ops.pf_free( &oldval );
vlc_mutex_unlock( &p_priv->var_lock );
@@ -776,6 +820,15 @@ int var_Set( vlc_object_t *p_this, const char *psz_name, vlc_value_t val )
int var_GetChecked( vlc_object_t *p_this, const char *psz_name,
int expected_type, vlc_value_t *p_val )
{
+ return GetCheckedWithOps( p_this, psz_name, expected_type, p_val, NULL );
+}
+
+static int GetCheckedWithOps( vlc_object_t *p_this, const char *psz_name,
+ int expected_type, vlc_value_t *p_val,
+ variable_ops_t *p_ops )
+{
+ VLC_UNUSED(expected_type);
+
assert( p_this );
vlc_object_internals_t *p_priv = vlc_internals( p_this );
@@ -795,7 +848,11 @@ int var_GetChecked( vlc_object_t *p_this, const char *psz_name,
*p_val = p_var->val;
/* Duplicate value if needed */
- p_var->ops->pf_dup( p_val );
+ p_var->ops.pf_dup( p_val );
+
+ /* Optionally return ops */
+ if ( p_ops )
+ *p_ops = p_var->ops;
}
else
err = VLC_ENOVAR;
@@ -1207,7 +1264,7 @@ static void CheckValue ( variable_t *p_var, vlc_value_t *p_val )
/* This list is not sorted so go throug it (this is a small list) */
for( i = p_var->choices.i_count ; i-- ; )
{
- if( p_var->ops->pf_cmp( *p_val, p_var->choices.p_values[i] ) == 0 )
+ if( p_var->ops.pf_cmp( *p_val, p_var->choices.p_values[i] ) == 0 )
{
break;
}
@@ -1217,10 +1274,10 @@ static void CheckValue ( variable_t *p_var, vlc_value_t *p_val )
if( i < 0 )
{
/* Free the old variable, get the new one, dup it */
- p_var->ops->pf_free( p_val );
+ p_var->ops.pf_free( p_val );
*p_val = p_var->choices.p_values[p_var->i_default >= 0
? p_var->i_default : 0 ];
- p_var->ops->pf_dup( p_val );
+ p_var->ops.pf_dup( p_val );
}
}
@@ -1269,19 +1326,14 @@ static void CheckValue ( variable_t *p_var, vlc_value_t *p_val )
}
}
-/**
- * Finds the value of a variable. If the specified object does not hold a
- * variable with the specified name, try the parent object, and iterate until
- * the top of the tree. If no match is found, the value is read from the
- * configuration.
- */
-int var_Inherit( vlc_object_t *p_this, const char *psz_name, int i_type,
- vlc_value_t *p_val )
+static int InheritWithOps( vlc_object_t *p_this, const char *psz_name,
+ int i_type, vlc_value_t *p_val,
+ variable_ops_t *p_ops )
{
i_type &= VLC_VAR_CLASS;
for( vlc_object_t *obj = p_this; obj != NULL; obj = obj->p_parent )
{
- if( var_GetChecked( obj, psz_name, i_type, p_val ) == VLC_SUCCESS )
+ if( GetCheckedWithOps( obj, psz_name, i_type, p_val, p_ops ) == VLC_SUCCESS )
return VLC_SUCCESS;
}
@@ -1309,6 +1361,18 @@ int var_Inherit( vlc_object_t *p_this, const char *psz_name, int i_type,
return VLC_SUCCESS;
}
+/**
+ * Finds the value of a variable. If the specified object does not hold a
+ * variable with the specified name, try the parent object, and iterate until
+ * the top of the tree. If no match is found, the value is read from the
+ * configuration.
+ */
+int var_Inherit( vlc_object_t *p_this, const char *psz_name, int i_type,
+ vlc_value_t *p_val )
+{
+ return InheritWithOps( p_this, psz_name, i_type, p_val, NULL );
+}
+
/**
* It inherits a string as an unsigned rational number (it also accepts basic
diff --git a/src/misc/variables.h b/src/misc/variables.h
index 35b8203..8571143 100644
--- a/src/misc/variables.h
+++ b/src/misc/variables.h
@@ -86,7 +86,7 @@ struct variable_t
/** The variable display name, mainly for use by the interfaces */
char * psz_text;
- const variable_ops_t *ops;
+ variable_ops_t ops;
int i_type; /**< The type of the variable */
unsigned i_usage; /**< Reference count */
--
1.7.10.4
More information about the vlc-devel
mailing list