Commit b2c266cd authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Use a global R/W lock for configuration

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).
parent b3dce1b9
...@@ -54,6 +54,8 @@ static inline int IsConfigFloatType (int type) ...@@ -54,6 +54,8 @@ static inline int IsConfigFloatType (int type)
uint_fast32_t ConfigStringToKey( const char * ); uint_fast32_t ConfigStringToKey( const char * );
char *ConfigKeyToString( uint_fast32_t ); char *ConfigKeyToString( uint_fast32_t );
extern vlc_rwlock_t config_lock;
/* The configuration file */ /* The configuration file */
#define CONFIG_FILE "vlcrc" #define CONFIG_FILE "vlcrc"
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include "configuration.h" #include "configuration.h"
#include "modules/modules.h" #include "modules/modules.h"
vlc_rwlock_t config_lock;
static inline char *strdupnull (const char *src) static inline char *strdupnull (const char *src)
{ {
return src ? strdup (src) : NULL; return src ? strdup (src) : NULL;
...@@ -220,9 +222,9 @@ char * __config_GetPsz( vlc_object_t *p_this, const char *psz_name ) ...@@ -220,9 +222,9 @@ char * __config_GetPsz( vlc_object_t *p_this, const char *psz_name )
} }
/* 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);
return psz_value; return psz_value;
} }
...@@ -256,7 +258,7 @@ void __config_PutPsz( vlc_object_t *p_this, ...@@ -256,7 +258,7 @@ void __config_PutPsz( vlc_object_t *p_this,
return; return;
} }
vlc_mutex_lock( p_config->p_lock ); vlc_rwlock_wrlock (&config_lock);
/* backup old value */ /* backup old value */
oldval.psz_string = (char *)p_config->value.psz; oldval.psz_string = (char *)p_config->value.psz;
...@@ -270,7 +272,7 @@ void __config_PutPsz( vlc_object_t *p_this, ...@@ -270,7 +272,7 @@ void __config_PutPsz( vlc_object_t *p_this,
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 )
{ {
...@@ -506,6 +508,7 @@ void __config_ResetAll( vlc_object_t *p_this ) ...@@ -506,6 +508,7 @@ void __config_ResetAll( vlc_object_t *p_this )
module_t *p_module; module_t *p_module;
module_t **list = module_list_get (NULL); module_t **list = module_list_get (NULL);
vlc_rwlock_wrlock (&config_lock);
for (size_t j = 0; (p_module = list[j]) != NULL; j++) for (size_t j = 0; (p_module = list[j]) != NULL; j++)
{ {
if( p_module->b_submodule ) continue; if( p_module->b_submodule ) continue;
...@@ -514,7 +517,6 @@ void __config_ResetAll( vlc_object_t *p_this ) ...@@ -514,7 +517,6 @@ void __config_ResetAll( vlc_object_t *p_this )
{ {
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)) if (IsConfigIntegerType (p_config->i_type))
p_config->value.i = p_config->orig.i; p_config->value.i = p_config->orig.i;
else else
...@@ -527,9 +529,9 @@ void __config_ResetAll( vlc_object_t *p_this ) ...@@ -527,9 +529,9 @@ void __config_ResetAll( vlc_object_t *p_this )
p_config->value.psz = p_config->value.psz =
strdupnull (p_config->orig.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);
} }
...@@ -189,6 +189,7 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name ) ...@@ -189,6 +189,7 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL); locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
locale_t baseloc = uselocale (loc); locale_t baseloc = uselocale (loc);
vlc_rwlock_wrlock (&config_lock);
while (fgets (line, 1024, file) != NULL) while (fgets (line, 1024, file) != NULL)
{ {
/* Ignore comments and empty lines */ /* Ignore comments and empty lines */
...@@ -263,7 +264,6 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name ) ...@@ -263,7 +264,6 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
/* We found it */ /* We found it */
errno = 0; errno = 0;
vlc_mutex_lock( p_item->p_lock );
switch( p_item->i_type ) switch( p_item->i_type )
{ {
case CONFIG_ITEM_BOOL: case CONFIG_ITEM_BOOL:
...@@ -301,10 +301,10 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name ) ...@@ -301,10 +301,10 @@ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name )
p_item->saved.psz = strdupnull (p_item->value.psz); p_item->saved.psz = strdupnull (p_item->value.psz);
break; break;
} }
vlc_mutex_unlock( p_item->p_lock );
break; break;
} }
} }
vlc_rwlock_unlock (&config_lock);
if (ferror (file)) if (ferror (file))
{ {
...@@ -532,6 +532,9 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, ...@@ -532,6 +532,9 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
goto error; goto error;
} }
/* Configuration lock must be taken before vlcrc serializer below. */
vlc_rwlock_rdlock (&config_lock);
/* The temporary configuration file is per-PID. Therefore SaveConfigFile() /* The temporary configuration file is per-PID. Therefore SaveConfigFile()
* should be serialized against itself within a given process. */ * should be serialized against itself within a given process. */
static vlc_mutex_t lock = VLC_STATIC_MUTEX; static vlc_mutex_t lock = VLC_STATIC_MUTEX;
...@@ -540,6 +543,7 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, ...@@ -540,6 +543,7 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
int fd = utf8_open (temporary, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR); int fd = utf8_open (temporary, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
if (fd == -1) if (fd == -1)
{ {
vlc_rwlock_unlock (&config_lock);
vlc_mutex_unlock (&lock); vlc_mutex_unlock (&lock);
module_list_free (list); module_list_free (list);
goto error; goto error;
...@@ -547,6 +551,7 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, ...@@ -547,6 +551,7 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
file = fdopen (fd, "wt"); file = fdopen (fd, "wt");
if (file == NULL) if (file == NULL)
{ {
vlc_rwlock_unlock (&config_lock);
close (fd); close (fd);
vlc_mutex_unlock (&lock); vlc_mutex_unlock (&lock);
module_list_free (list); module_list_free (list);
...@@ -560,6 +565,10 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, ...@@ -560,6 +565,10 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL); locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL);
locale_t baseloc = uselocale (loc); 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 */ /* Look for the selected module, if NULL then save everything */
for( i_index = 0; (p_parser = list[i_index]) != NULL; i_index++ ) for( i_index = 0; (p_parser = list[i_index]) != NULL; i_index++ )
{ {
...@@ -591,8 +600,6 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, ...@@ -591,8 +600,6 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
|| p_item->b_unsaveable) /* ignore volatile option */ || p_item->b_unsaveable) /* ignore volatile option */
continue; continue;
vlc_mutex_lock (p_item->p_lock);
/* Do not save the new value in the configuration file /* Do not save the new value in the configuration file
* if doing an autosave, and the item is not an "autosaved" one. */ * if doing an autosave, and the item is not an "autosaved" one. */
bool b_retain = b_autosave && !p_item->b_autosave; bool b_retain = b_autosave && !p_item->b_autosave;
...@@ -663,9 +670,9 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name, ...@@ -663,9 +670,9 @@ static int SaveConfigFile( vlc_object_t *p_this, const char *psz_module_name,
if (!b_retain) if (!b_retain)
p_item->b_dirty = false; p_item->b_dirty = false;
vlc_mutex_unlock (p_item->p_lock);
} }
} }
vlc_rwlock_unlock (&config_lock);
module_list_free (list); module_list_free (list);
if (loc != (locale_t)0) if (loc != (locale_t)0)
...@@ -721,14 +728,15 @@ error: ...@@ -721,14 +728,15 @@ error:
int config_AutoSaveConfigFile( vlc_object_t *p_this ) int config_AutoSaveConfigFile( vlc_object_t *p_this )
{ {
size_t i_index; int ret = VLC_SUCCESS;
bool save = false; bool save = false;
assert( p_this ); assert( p_this );
/* Check if there's anything to save */ /* Check if there's anything to save */
module_t **list = module_list_get (NULL); 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_t *p_parser = list[i_index];
module_config_t *p_item, *p_end; module_config_t *p_item, *p_end;
...@@ -739,14 +747,17 @@ int config_AutoSaveConfigFile( vlc_object_t *p_this ) ...@@ -739,14 +747,17 @@ int config_AutoSaveConfigFile( vlc_object_t *p_this )
p_item < p_end && !save; p_item < p_end && !save;
p_item++ ) 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 )
......
...@@ -137,6 +137,7 @@ void __module_InitBank( vlc_object_t *p_this ) ...@@ -137,6 +137,7 @@ void __module_InitBank( vlc_object_t *p_this )
* options of main will be available in the module bank structure just * options of main will be available in the module bank structure just
* as for every other module. */ * as for every other module. */
AllocateBuiltinModule( p_this, vlc_entry__main ); AllocateBuiltinModule( p_this, vlc_entry__main );
vlc_rwlock_init (&config_lock);
} }
else else
p_module_bank->i_usage++; p_module_bank->i_usage++;
...@@ -180,6 +181,7 @@ void module_EndBank( vlc_object_t *p_this, bool b_plugins ) ...@@ -180,6 +181,7 @@ void module_EndBank( vlc_object_t *p_this, bool b_plugins )
vlc_mutex_unlock( &module_lock ); vlc_mutex_unlock( &module_lock );
return; return;
} }
vlc_rwlock_destroy (&config_lock);
p_module_bank = NULL; p_module_bank = NULL;
vlc_mutex_unlock( &module_lock ); vlc_mutex_unlock( &module_lock );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment