Previously, we had one configuration mutex per module.
With a global read/write lock, resetting, loading, saving and
auto-saving the configuration becomes atomic (and use only one lock &
unlock pair). Also, multiple threads can now read the configuration
item of the same module at the same time.
Note that, as the earlier configuration mutex, only configuration item
values are protected. The list of items and their meta-data cannot
change while VLC runs (they're hard-coded in the plugin descriptors).
uint_fast32_t ConfigStringToKey( const char * );
char *ConfigKeyToString( uint_fast32_t );
uint_fast32_t ConfigStringToKey( const char * );
char *ConfigKeyToString( uint_fast32_t );
+extern vlc_rwlock_t config_lock;
+
/* The configuration file */
#define CONFIG_FILE "vlcrc"
/* The configuration file */
#define CONFIG_FILE "vlcrc"
#include "configuration.h"
#include "modules/modules.h"
#include "configuration.h"
#include "modules/modules.h"
+vlc_rwlock_t config_lock;
+
static inline char *strdupnull (const char *src)
{
return src ? strdup (src) : NULL;
static inline char *strdupnull (const char *src)
{
return src ? strdup (src) : NULL;
}
/* return a copy of the string */
}
/* return a copy of the string */
- vlc_mutex_lock( p_config->p_lock );
+ vlc_rwlock_rdlock (&config_lock);
char *psz_value = strdupnull (p_config->value.psz);
char *psz_value = strdupnull (p_config->value.psz);
- vlc_mutex_unlock( p_config->p_lock );
+ vlc_rwlock_unlock (&config_lock);
- vlc_mutex_lock( p_config->p_lock );
+ vlc_rwlock_wrlock (&config_lock);
/* backup old value */
oldval.psz_string = (char *)p_config->value.psz;
/* backup old value */
oldval.psz_string = (char *)p_config->value.psz;
val.psz_string = (char *)p_config->value.psz;
val.psz_string = (char *)p_config->value.psz;
- vlc_mutex_unlock( p_config->p_lock );
+ vlc_rwlock_unlock (&config_lock);
if( p_config->pf_callback )
{
if( p_config->pf_callback )
{
module_t *p_module;
module_t **list = module_list_get (NULL);
module_t *p_module;
module_t **list = module_list_get (NULL);
+ vlc_rwlock_wrlock (&config_lock);
for (size_t j = 0; (p_module = list[j]) != NULL; j++)
{
if( p_module->b_submodule ) continue;
for (size_t j = 0; (p_module = list[j]) != NULL; j++)
{
if( p_module->b_submodule ) continue;
{
module_config_t *p_config = p_module->p_config + i;
{
module_config_t *p_config = p_module->p_config + i;
- vlc_mutex_lock (p_config->p_lock);
if (IsConfigIntegerType (p_config->i_type))
p_config->value.i = p_config->orig.i;
else
if (IsConfigIntegerType (p_config->i_type))
p_config->value.i = p_config->orig.i;
else
p_config->value.psz =
strdupnull (p_config->orig.psz);
}
p_config->value.psz =
strdupnull (p_config->orig.psz);
}
- vlc_mutex_unlock (p_config->p_lock);
+ vlc_rwlock_unlock (&config_lock);
module_list_free (list);
}
module_list_free (list);
}
locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
locale_t baseloc = uselocale (loc);
locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
locale_t baseloc = uselocale (loc);
+ vlc_rwlock_wrlock (&config_lock);
while (fgets (line, 1024, file) != NULL)
{
/* Ignore comments and empty lines */
while (fgets (line, 1024, file) != NULL)
{
/* Ignore comments and empty lines */
/* We found it */
errno = 0;
/* We found it */
errno = 0;
- vlc_mutex_lock( p_item->p_lock );
switch( p_item->i_type )
{
case CONFIG_ITEM_BOOL:
switch( p_item->i_type )
{
case CONFIG_ITEM_BOOL:
p_item->saved.psz = strdupnull (p_item->value.psz);
break;
}
p_item->saved.psz = strdupnull (p_item->value.psz);
break;
}
- vlc_mutex_unlock( p_item->p_lock );
+ vlc_rwlock_unlock (&config_lock);
+ /* Configuration lock must be taken before vlcrc serializer below. */
+ vlc_rwlock_rdlock (&config_lock);
+
/* The temporary configuration file is per-PID. Therefore SaveConfigFile()
* should be serialized against itself within a given process. */
static vlc_mutex_t lock = VLC_STATIC_MUTEX;
/* The temporary configuration file is per-PID. Therefore SaveConfigFile()
* should be serialized against itself within a given process. */
static vlc_mutex_t lock = VLC_STATIC_MUTEX;
int fd = utf8_open (temporary, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
if (fd == -1)
{
int fd = utf8_open (temporary, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
if (fd == -1)
{
+ vlc_rwlock_unlock (&config_lock);
vlc_mutex_unlock (&lock);
module_list_free (list);
goto error;
vlc_mutex_unlock (&lock);
module_list_free (list);
goto error;
file = fdopen (fd, "wt");
if (file == NULL)
{
file = fdopen (fd, "wt");
if (file == NULL)
{
+ vlc_rwlock_unlock (&config_lock);
close (fd);
vlc_mutex_unlock (&lock);
module_list_free (list);
close (fd);
vlc_mutex_unlock (&lock);
module_list_free (list);
locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
locale_t baseloc = uselocale (loc);
locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
locale_t baseloc = uselocale (loc);
+ /* We would take the config lock here. But this would cause a lock
+ * inversion with the serializer above and config_AutoSaveConfigFile().
+ vlc_rwlock_rdlock (&config_lock);*/
+
/* Look for the selected module, if NULL then save everything */
for( i_index = 0; (p_parser = list[i_index]) != NULL; i_index++ )
{
/* Look for the selected module, if NULL then save everything */
for( i_index = 0; (p_parser = list[i_index]) != NULL; i_index++ )
{
|| p_item->b_unsaveable) /* ignore volatile option */
continue;
|| p_item->b_unsaveable) /* ignore volatile option */
continue;
- vlc_mutex_lock (p_item->p_lock);
-
/* Do not save the new value in the configuration file
* if doing an autosave, and the item is not an "autosaved" one. */
bool b_retain = b_autosave && !p_item->b_autosave;
/* Do not save the new value in the configuration file
* if doing an autosave, and the item is not an "autosaved" one. */
bool b_retain = b_autosave && !p_item->b_autosave;
if (!b_retain)
p_item->b_dirty = false;
if (!b_retain)
p_item->b_dirty = false;
- vlc_mutex_unlock (p_item->p_lock);
+ vlc_rwlock_unlock (&config_lock);
module_list_free (list);
if (loc != (locale_t)0)
module_list_free (list);
if (loc != (locale_t)0)
int config_AutoSaveConfigFile( vlc_object_t *p_this )
{
int config_AutoSaveConfigFile( vlc_object_t *p_this )
{
bool save = false;
assert( p_this );
/* Check if there's anything to save */
module_t **list = module_list_get (NULL);
bool save = false;
assert( p_this );
/* Check if there's anything to save */
module_t **list = module_list_get (NULL);
- for( i_index = 0; list[i_index] && !save; i_index++ )
+ vlc_rwlock_rdlock (&config_lock);
+ for (size_t i_index = 0; list[i_index] && !save; i_index++)
{
module_t *p_parser = list[i_index];
module_config_t *p_item, *p_end;
{
module_t *p_parser = list[i_index];
module_config_t *p_item, *p_end;
p_item < p_end && !save;
p_item++ )
{
p_item < p_end && !save;
p_item++ )
{
- vlc_mutex_lock (p_item->p_lock);
save = p_item->b_autosave && p_item->b_dirty;
save = p_item->b_autosave && p_item->b_dirty;
- vlc_mutex_unlock (p_item->p_lock);
- module_list_free (list);
- return save ? VLC_SUCCESS : SaveConfigFile( p_this, NULL, true );
+ if (save)
+ /* Note: this will get the read lock recursively. Ok. */
+ ret = SaveConfigFile (p_this, NULL, true);
+ vlc_rwlock_unlock (&config_lock);
+
+ module_list_free (list);
+ return ret;
}
int __config_SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name )
}
int __config_SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name )
* options of main will be available in the module bank structure just
* as for every other module. */
AllocateBuiltinModule( p_this, vlc_entry__main );
* options of main will be available in the module bank structure just
* as for every other module. */
AllocateBuiltinModule( p_this, vlc_entry__main );
+ vlc_rwlock_init (&config_lock);
}
else
p_module_bank->i_usage++;
}
else
p_module_bank->i_usage++;
vlc_mutex_unlock( &module_lock );
return;
}
vlc_mutex_unlock( &module_lock );
return;
}
+ vlc_rwlock_destroy (&config_lock);
p_module_bank = NULL;
vlc_mutex_unlock( &module_lock );
p_module_bank = NULL;
vlc_mutex_unlock( &module_lock );