libobs/util: Use a mutex with config files
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include "config-file.h"
|
||||
#include "threading.h"
|
||||
#include "platform.h"
|
||||
#include "base.h"
|
||||
#include "bmem.h"
|
||||
@@ -57,8 +58,19 @@ struct config_data {
|
||||
char *file;
|
||||
struct darray sections; /* struct config_section */
|
||||
struct darray defaults; /* struct config_section */
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
static inline bool init_mutex(config_t *config)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
if (pthread_mutexattr_init(&attr) != 0)
|
||||
return false;
|
||||
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
|
||||
return false;
|
||||
return pthread_mutex_init(&config->mutex, &attr) == 0;
|
||||
}
|
||||
|
||||
config_t *config_create(const char *file)
|
||||
{
|
||||
struct config_data *config;
|
||||
@@ -70,6 +82,12 @@ config_t *config_create(const char *file)
|
||||
fclose(f);
|
||||
|
||||
config = bzalloc(sizeof(struct config_data));
|
||||
|
||||
if (!init_mutex(config)) {
|
||||
bfree(config);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
config->file = bstrdup(file);
|
||||
return config;
|
||||
}
|
||||
@@ -278,6 +296,11 @@ int config_open(config_t **config, const char *file,
|
||||
if (!*config)
|
||||
return CONFIG_ERROR;
|
||||
|
||||
if (!init_mutex(*config)) {
|
||||
bfree(*config);
|
||||
return CONFIG_ERROR;
|
||||
}
|
||||
|
||||
(*config)->file = bstrdup(file);
|
||||
|
||||
errorcode = config_parse_file(&(*config)->sections, file, always_open);
|
||||
@@ -301,6 +324,11 @@ int config_open_string(config_t **config, const char *str)
|
||||
if (!*config)
|
||||
return CONFIG_ERROR;
|
||||
|
||||
if (!init_mutex(*config)) {
|
||||
bfree(*config);
|
||||
return CONFIG_ERROR;
|
||||
}
|
||||
|
||||
(*config)->file = NULL;
|
||||
|
||||
lexer_init(&lex);
|
||||
@@ -333,9 +361,13 @@ int config_save(config_t *config)
|
||||
dstr_init(&str);
|
||||
dstr_init(&tmp);
|
||||
|
||||
pthread_mutex_lock(&config->mutex);
|
||||
|
||||
f = os_fopen(config->file, "wb");
|
||||
if (!f)
|
||||
if (!f) {
|
||||
pthread_mutex_unlock(&config->mutex);
|
||||
return CONFIG_FILENOTFOUND;
|
||||
}
|
||||
|
||||
for (i = 0; i < config->sections.num; i++) {
|
||||
struct config_section *section = darray_item(
|
||||
@@ -371,6 +403,8 @@ int config_save(config_t *config)
|
||||
fwrite(str.array, 1, str.len, f);
|
||||
fclose(f);
|
||||
|
||||
pthread_mutex_unlock(&config->mutex);
|
||||
|
||||
dstr_free(&tmp);
|
||||
dstr_free(&str);
|
||||
|
||||
@@ -391,6 +425,8 @@ int config_save_safe(config_t *config, const char *temp_ext,
|
||||
return CONFIG_ERROR;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&config->mutex);
|
||||
|
||||
dstr_copy(&temp_file, config->file);
|
||||
if (*temp_ext != '.')
|
||||
dstr_cat(&temp_file, ".");
|
||||
@@ -419,6 +455,7 @@ int config_save_safe(config_t *config, const char *temp_ext,
|
||||
os_rename(temp_file.array, file);
|
||||
|
||||
cleanup:
|
||||
pthread_mutex_unlock(&config->mutex);
|
||||
dstr_free(&temp_file);
|
||||
dstr_free(&backup_file);
|
||||
return ret;
|
||||
@@ -442,6 +479,7 @@ void config_close(config_t *config)
|
||||
darray_free(&config->defaults);
|
||||
darray_free(&config->sections);
|
||||
bfree(config->file);
|
||||
pthread_mutex_destroy(&config->mutex);
|
||||
bfree(config);
|
||||
}
|
||||
|
||||
@@ -453,14 +491,20 @@ size_t config_num_sections(config_t *config)
|
||||
const char *config_get_section(config_t *config, size_t idx)
|
||||
{
|
||||
struct config_section *section;
|
||||
const char *name = NULL;
|
||||
|
||||
pthread_mutex_lock(&config->mutex);
|
||||
|
||||
if (idx >= config->sections.num)
|
||||
return NULL;
|
||||
goto unlock;
|
||||
|
||||
section = darray_item(sizeof(struct config_section), &config->sections,
|
||||
idx);
|
||||
name = section->name;
|
||||
|
||||
return section->name;
|
||||
unlock:
|
||||
pthread_mutex_unlock(&config->mutex);
|
||||
return name;
|
||||
}
|
||||
|
||||
static const struct config_item *config_find_item(const struct darray *sections,
|
||||
@@ -487,14 +531,16 @@ static const struct config_item *config_find_item(const struct darray *sections,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void config_set_item(struct darray *sections, const char *section,
|
||||
const char *name, char *value)
|
||||
static void config_set_item(config_t *config, struct darray *sections,
|
||||
const char *section, const char *name, char *value)
|
||||
{
|
||||
struct config_section *sec = NULL;
|
||||
struct config_section *array = sections->array;
|
||||
struct config_item *item;
|
||||
size_t i, j;
|
||||
|
||||
pthread_mutex_lock(&config->mutex);
|
||||
|
||||
for (i = 0; i < sections->num; i++) {
|
||||
struct config_section *cur_sec = array+i;
|
||||
struct config_item *items = cur_sec->items.array;
|
||||
@@ -506,7 +552,7 @@ static void config_set_item(struct darray *sections, const char *section,
|
||||
if (astrcmpi(item->name, name) == 0) {
|
||||
bfree(item->value);
|
||||
item->value = value;
|
||||
return;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,6 +570,9 @@ static void config_set_item(struct darray *sections, const char *section,
|
||||
item = darray_push_back_new(sizeof(struct config_item), &sec->items);
|
||||
item->name = bstrdup(name);
|
||||
item->value = value;
|
||||
|
||||
unlock:
|
||||
pthread_mutex_unlock(&config->mutex);
|
||||
}
|
||||
|
||||
void config_set_string(config_t *config, const char *section,
|
||||
@@ -531,7 +580,8 @@ void config_set_string(config_t *config, const char *section,
|
||||
{
|
||||
if (!value)
|
||||
value = "";
|
||||
config_set_item(&config->sections, section, name, bstrdup(value));
|
||||
config_set_item(config, &config->sections, section, name,
|
||||
bstrdup(value));
|
||||
}
|
||||
|
||||
void config_set_int(config_t *config, const char *section,
|
||||
@@ -540,7 +590,7 @@ void config_set_int(config_t *config, const char *section,
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%"PRId64, value);
|
||||
config_set_item(&config->sections, section, name, str.array);
|
||||
config_set_item(config, &config->sections, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_uint(config_t *config, const char *section,
|
||||
@@ -549,14 +599,14 @@ void config_set_uint(config_t *config, const char *section,
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%"PRIu64, value);
|
||||
config_set_item(&config->sections, section, name, str.array);
|
||||
config_set_item(config, &config->sections, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_bool(config_t *config, const char *section,
|
||||
const char *name, bool value)
|
||||
{
|
||||
char *str = bstrdup(value ? "true" : "false");
|
||||
config_set_item(&config->sections, section, name, str);
|
||||
config_set_item(config, &config->sections, section, name, str);
|
||||
}
|
||||
|
||||
void config_set_double(config_t *config, const char *section,
|
||||
@@ -564,7 +614,7 @@ void config_set_double(config_t *config, const char *section,
|
||||
{
|
||||
char *str = bzalloc(64);
|
||||
os_dtostr(value, str, 64);
|
||||
config_set_item(&config->sections, section, name, str);
|
||||
config_set_item(config, &config->sections, section, name, str);
|
||||
}
|
||||
|
||||
void config_set_default_string(config_t *config, const char *section,
|
||||
@@ -572,7 +622,8 @@ void config_set_default_string(config_t *config, const char *section,
|
||||
{
|
||||
if (!value)
|
||||
value = "";
|
||||
config_set_item(&config->defaults, section, name, bstrdup(value));
|
||||
config_set_item(config, &config->defaults, section, name,
|
||||
bstrdup(value));
|
||||
}
|
||||
|
||||
void config_set_default_int(config_t *config, const char *section,
|
||||
@@ -581,7 +632,7 @@ void config_set_default_int(config_t *config, const char *section,
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%"PRId64, value);
|
||||
config_set_item(&config->defaults, section, name, str.array);
|
||||
config_set_item(config, &config->defaults, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_default_uint(config_t *config, const char *section,
|
||||
@@ -590,14 +641,14 @@ void config_set_default_uint(config_t *config, const char *section,
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%"PRIu64, value);
|
||||
config_set_item(&config->defaults, section, name, str.array);
|
||||
config_set_item(config, &config->defaults, section, name, str.array);
|
||||
}
|
||||
|
||||
void config_set_default_bool(config_t *config, const char *section,
|
||||
const char *name, bool value)
|
||||
{
|
||||
char *str = bstrdup(value ? "true" : "false");
|
||||
config_set_item(&config->defaults, section, name, str);
|
||||
config_set_item(config, &config->defaults, section, name, str);
|
||||
}
|
||||
|
||||
void config_set_default_double(config_t *config, const char *section,
|
||||
@@ -606,20 +657,25 @@ void config_set_default_double(config_t *config, const char *section,
|
||||
struct dstr str;
|
||||
dstr_init(&str);
|
||||
dstr_printf(&str, "%g", value);
|
||||
config_set_item(&config->defaults, section, name, str.array);
|
||||
config_set_item(config, &config->defaults, section, name, str.array);
|
||||
}
|
||||
|
||||
const char *config_get_string(const config_t *config, const char *section,
|
||||
const char *config_get_string(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const struct config_item *item = config_find_item(&config->sections,
|
||||
section, name);
|
||||
const struct config_item *item;
|
||||
const char *value = NULL;
|
||||
|
||||
pthread_mutex_lock(&config->mutex);
|
||||
|
||||
item = config_find_item(&config->sections, section, name);
|
||||
if (!item)
|
||||
item = config_find_item(&config->defaults, section, name);
|
||||
if (!item)
|
||||
return NULL;
|
||||
if (item)
|
||||
value = item->value;
|
||||
|
||||
return item->value;
|
||||
pthread_mutex_unlock(&config->mutex);
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline int64_t str_to_int64(const char *str)
|
||||
@@ -644,7 +700,7 @@ static inline uint64_t str_to_uint64(const char *str)
|
||||
return strtoull(str, NULL, 10);
|
||||
}
|
||||
|
||||
int64_t config_get_int(const config_t *config, const char *section,
|
||||
int64_t config_get_int(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
@@ -654,7 +710,7 @@ int64_t config_get_int(const config_t *config, const char *section,
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t config_get_uint(const config_t *config, const char *section,
|
||||
uint64_t config_get_uint(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
@@ -664,7 +720,7 @@ uint64_t config_get_uint(const config_t *config, const char *section,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool config_get_bool(const config_t *config, const char *section,
|
||||
bool config_get_bool(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
@@ -675,7 +731,7 @@ bool config_get_bool(const config_t *config, const char *section,
|
||||
return false;
|
||||
}
|
||||
|
||||
double config_get_double(const config_t *config, const char *section,
|
||||
double config_get_double(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_string(config, section, name);
|
||||
@@ -689,6 +745,9 @@ bool config_remove_value(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
struct darray *sections = &config->sections;
|
||||
bool success = false;
|
||||
|
||||
pthread_mutex_lock(&config->mutex);
|
||||
|
||||
for (size_t i = 0; i < sections->num; i++) {
|
||||
struct config_section *sec = darray_item(
|
||||
@@ -706,27 +765,34 @@ bool config_remove_value(config_t *config, const char *section,
|
||||
config_item_free(item);
|
||||
darray_erase(sizeof(struct config_item),
|
||||
&sec->items, j);
|
||||
return true;
|
||||
success = true;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
unlock:
|
||||
pthread_mutex_unlock(&config->mutex);
|
||||
return success;
|
||||
}
|
||||
|
||||
const char *config_get_default_string(const config_t *config,
|
||||
const char *config_get_default_string(config_t *config,
|
||||
const char *section, const char *name)
|
||||
{
|
||||
const struct config_item *item;
|
||||
const char *value = NULL;
|
||||
|
||||
pthread_mutex_lock(&config->mutex);
|
||||
|
||||
item = config_find_item(&config->defaults, section, name);
|
||||
if (!item)
|
||||
return NULL;
|
||||
if (item)
|
||||
value = item->value;
|
||||
|
||||
return item->value;
|
||||
pthread_mutex_unlock(&config->mutex);
|
||||
return value;
|
||||
}
|
||||
|
||||
int64_t config_get_default_int(const config_t *config, const char *section,
|
||||
int64_t config_get_default_int(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_default_string(config, section, name);
|
||||
@@ -736,7 +802,7 @@ int64_t config_get_default_int(const config_t *config, const char *section,
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t config_get_default_uint(const config_t *config, const char *section,
|
||||
uint64_t config_get_default_uint(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_default_string(config, section, name);
|
||||
@@ -746,7 +812,7 @@ uint64_t config_get_default_uint(const config_t *config, const char *section,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool config_get_default_bool(const config_t *config, const char *section,
|
||||
bool config_get_default_bool(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_default_string(config, section, name);
|
||||
@@ -757,7 +823,7 @@ bool config_get_default_bool(const config_t *config, const char *section,
|
||||
return false;
|
||||
}
|
||||
|
||||
double config_get_default_double(const config_t *config, const char *section,
|
||||
double config_get_default_double(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
const char *value = config_get_default_string(config, section, name);
|
||||
@@ -767,15 +833,23 @@ double config_get_default_double(const config_t *config, const char *section,
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
bool config_has_user_value(const config_t *config, const char *section,
|
||||
bool config_has_user_value(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
return config_find_item(&config->sections, section, name) != NULL;
|
||||
bool success;
|
||||
pthread_mutex_lock(&config->mutex);
|
||||
success = config_find_item(&config->sections, section, name) != NULL;
|
||||
pthread_mutex_unlock(&config->mutex);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool config_has_default_value(const config_t *config, const char *section,
|
||||
bool config_has_default_value(config_t *config, const char *section,
|
||||
const char *name)
|
||||
{
|
||||
return config_find_item(&config->defaults, section, name) != NULL;
|
||||
bool success;
|
||||
pthread_mutex_lock(&config->mutex);
|
||||
success = config_find_item(&config->defaults, section, name) != NULL;
|
||||
pthread_mutex_unlock(&config->mutex);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@@ -64,15 +64,15 @@ EXPORT void config_set_bool(config_t *config, const char *section,
|
||||
EXPORT void config_set_double(config_t *config, const char *section,
|
||||
const char *name, double value);
|
||||
|
||||
EXPORT const char *config_get_string(const config_t *config,
|
||||
EXPORT const char *config_get_string(config_t *config,
|
||||
const char *section, const char *name);
|
||||
EXPORT int64_t config_get_int(const config_t *config, const char *section,
|
||||
EXPORT int64_t config_get_int(config_t *config, const char *section,
|
||||
const char *name);
|
||||
EXPORT uint64_t config_get_uint(const config_t *config, const char *section,
|
||||
EXPORT uint64_t config_get_uint(config_t *config, const char *section,
|
||||
const char *name);
|
||||
EXPORT bool config_get_bool(const config_t *config, const char *section,
|
||||
EXPORT bool config_get_bool(config_t *config, const char *section,
|
||||
const char *name);
|
||||
EXPORT double config_get_double(const config_t *config, const char *section,
|
||||
EXPORT double config_get_double(config_t *config, const char *section,
|
||||
const char *name);
|
||||
|
||||
EXPORT bool config_remove_value(config_t *config, const char *section,
|
||||
@@ -107,20 +107,20 @@ EXPORT void config_set_default_double(config_t *config, const char *section,
|
||||
|
||||
/* These functions allow you to get the current default values rather than get
|
||||
* the actual values. Probably almost never really needed */
|
||||
EXPORT const char *config_get_default_string(const config_t *config,
|
||||
EXPORT const char *config_get_default_string(config_t *config,
|
||||
const char *section, const char *name);
|
||||
EXPORT int64_t config_get_default_int(const config_t *config,
|
||||
EXPORT int64_t config_get_default_int(config_t *config,
|
||||
const char *section, const char *name);
|
||||
EXPORT uint64_t config_get_default_uint(const config_t *config,
|
||||
EXPORT uint64_t config_get_default_uint(config_t *config,
|
||||
const char *section, const char *name);
|
||||
EXPORT bool config_get_default_bool(const config_t *config,
|
||||
EXPORT bool config_get_default_bool(config_t *config,
|
||||
const char *section, const char *name);
|
||||
EXPORT double config_get_default_double(const config_t *config,
|
||||
EXPORT double config_get_default_double(config_t *config,
|
||||
const char *section, const char *name);
|
||||
|
||||
EXPORT bool config_has_user_value(const config_t *config,
|
||||
EXPORT bool config_has_user_value(config_t *config,
|
||||
const char *section, const char *name);
|
||||
EXPORT bool config_has_default_value(const config_t *config,
|
||||
EXPORT bool config_has_default_value(config_t *config,
|
||||
const char *section, const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
Reference in New Issue
Block a user