* Local duplication functions, and local deallocation functions
*****************************************************************************/
static void DupDummy( vlc_value_t *p_val ) { (void)p_val; /* unused */ }
-static void DupString( vlc_value_t *p_val ) { if( p_val->psz_string ) p_val->psz_string = strdup( p_val->psz_string ); }
+static void DupString( vlc_value_t *p_val ) { p_val->psz_string = strdup( p_val->psz_string ?: ""); }
static void DupList( vlc_value_t *p_val )
{
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 *, int, const char * );
-static int LookupInner ( variable_t *, int, uint32_t );
+static int Lookup ( variable_t *, size_t, const char * );
static void CheckValue ( variable_t *, vlc_value_t * );
}
}
break;
- case VLC_VAR_TRIGGER_CALLBACKS:
- {
- /* Deal with callbacks. Tell we're in a callback, release the lock,
- * call stored functions, retake the lock. */
- if( p_var->i_entries )
- {
- int i_var;
- int i_entries = p_var->i_entries;
- callback_entry_t *p_entries = p_var->p_entries;
-
- 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, p_var->val, p_var->val,
- p_entries[i_entries].p_data );
- }
-
- vlc_mutex_lock( &p_priv->var_lock );
-
- 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 );
- vlc_mutex_unlock( &p_priv->var_lock );
- return VLC_ENOVAR;
- }
-
- p_var = &p_priv->p_vars[i_var];
- p_var->b_incallback = false;
- }
- }
- break;
case VLC_VAR_SETISCOMMAND:
p_var->i_type |= VLC_VAR_ISCOMMAND;
p_var = &p_priv->p_vars[i_var];
p_var->b_incallback = false;
+ vlc_cond_broadcast( &p_priv->var_wait );
}
/* Free data if needed */
p_var = &p_priv->p_vars[i_var];
p_var->b_incallback = false;
+ vlc_cond_broadcast( &p_priv->var_wait );
}
vlc_mutex_unlock( &p_priv->var_lock );
/* Following functions are local */
/*****************************************************************************
- * GetUnused: find an unused variable from its name
+ * GetUnused: find an unused (not in callback) variable from its name
*****************************************************************************
* We do i_tries tries before giving up, just in case the variable is being
* modified and called from a callback.
*****************************************************************************/
static int GetUnused( vlc_object_t *p_this, const char *psz_name )
{
- int i_var, i_tries = 0;
vlc_object_internals_t *p_priv = vlc_internals( p_this );
while( true )
{
+ int i_var;
+
i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
if( i_var < 0 )
{
return i_var;
}
- if( i_tries++ > 100 )
- {
- msg_Err( p_this, "caught in a callback deadlock? ('%s')", psz_name );
- return VLC_ETIMEOUT;
- }
-
- vlc_mutex_unlock( &p_priv->var_lock );
- msleep( THREAD_SLEEP );
- vlc_mutex_lock( &p_priv->var_lock );
+ mutex_cleanup_push( &p_priv->var_lock );
+ vlc_cond_wait( &p_priv->var_wait, &p_priv->var_lock );
+ vlc_cleanup_pop( );
}
}
return i_middle + 1;
}
+static int u32cmp( const void *key, const void *data )
+{
+ const variable_t *p_var = data;
+ uint32_t hash = *(const uint32_t *)key ;
+
+ if( hash > p_var->i_hash )
+ return 1;
+ if( hash < p_var->i_hash )
+ return -1;
+ return 0;
+}
+
/*****************************************************************************
* Lookup: find an existing variable given its name
*****************************************************************************
* We use a recursive inner function indexed on the hash. Care is taken of
* possible hash collisions.
- * XXX: does this really need to be written recursively?
*****************************************************************************/
-static int Lookup( variable_t *p_vars, int i_count, const char *psz_name )
+static int Lookup( variable_t *p_vars, size_t i_count, const char *psz_name )
{
+ variable_t *p_var;
uint32_t i_hash;
- int i, i_pos;
-
- if( i_count == 0 )
- {
- return -1;
- }
i_hash = HashString( psz_name );
-
- i_pos = LookupInner( p_vars, i_count, i_hash );
+ p_var = bsearch( &i_hash, p_vars, i_count, sizeof( *p_var ), u32cmp );
/* Hash not found */
- if( i_hash != p_vars[i_pos].i_hash )
- {
+ if( p_var == NULL )
return -1;
- }
- /* Hash found, entry found */
- if( !strcmp( psz_name, p_vars[i_pos].psz_name ) )
- {
- return i_pos;
- }
+ assert( i_count > 0 );
- /* Hash collision! This should be very rare, but we cannot guarantee
- * it will never happen. Just do an exhaustive search amongst all
- * entries with the same hash. */
- for( i = i_pos - 1 ; i > 0 && i_hash == p_vars[i].i_hash ; i-- )
- {
- if( !strcmp( psz_name, p_vars[i].psz_name ) )
- {
- return i;
- }
- }
+ /* Find the first entry with the right hash */
+ while( (p_var > p_vars) && (i_hash == p_var[-1].i_hash) )
+ p_var--;
+
+ assert( p_var->i_hash == i_hash );
- for( i = i_pos + 1 ; i < i_count && i_hash == p_vars[i].i_hash ; i++ )
+ /* 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++ )
{
- if( !strcmp( psz_name, p_vars[i].psz_name ) )
- {
- return i;
- }
+ if( !strcmp( psz_name, p_var->psz_name ) )
+ return p_var - p_vars;
}
/* Hash found, but entry not found */
return -1;
}
-static int LookupInner( variable_t *p_vars, int i_count, uint32_t i_hash )
-{
- int i_middle;
-
- if( i_hash <= p_vars[0].i_hash )
- {
- return 0;
- }
-
- if( i_hash >= p_vars[i_count-1].i_hash )
- {
- return i_count - 1;
- }
-
- i_middle = i_count / 2;
-
- /* We know that 0 < i_middle */
- if( i_hash < p_vars[i_middle].i_hash )
- {
- return LookupInner( p_vars, i_middle, i_hash );
- }
-
- /* We know that i_middle + 1 < i_count */
- if( i_hash > p_vars[i_middle].i_hash )
- {
- return i_middle + LookupInner( p_vars + i_middle,
- i_count - i_middle,
- i_hash );
- }
-
- return i_middle;
-}
-
/*****************************************************************************
* CheckValue: check that a value is valid wrt. a variable
*****************************************************************************
int i_var;
variable_t *p_var;
- if( p_this->p_parent || ( p_this->p_libvlc && p_this != p_this->p_libvlc ) )
+ if( p_this->p_parent || ( p_this->p_libvlc && p_this != (vlc_object_t*) p_this->p_libvlc ) )
{
vlc_object_internals_t *p_priv;
/* Duplicate value if needed */
p_var->ops->pf_dup( p_val );
+ /*msg_Dbg( p_this, "Inherited value for var %s from object %s",
+ psz_name ? : "(null)",
+ p_this->psz_object_name ? : "(Unknown)" );*/
return VLC_SUCCESS;
}
else if ( p_this->p_parent ) /* We are still not there */
break;
}
default:
+ msg_Warn( p_this, "Could not inherit value for var %s "
+ "from config. Invalid Type", psz_name );
return VLC_ENOOBJ;
break;
}
+ /*msg_Dbg( p_this, "Inherited value for var %s from config", psz_name );*/
return VLC_SUCCESS;
}