diff --git a/src/util/os_misc.c b/src/util/os_misc.c index 5b6eea1e0e8..a10c6084c17 100644 --- a/src/util/os_misc.c +++ b/src/util/os_misc.c @@ -26,9 +26,12 @@ **************************************************************************/ +#include "hash_table.h" +#include "macros.h" #include "os_misc.h" #include "os_file.h" -#include "macros.h" +#include "ralloc.h" +#include "simple_mtx.h" #include @@ -182,6 +185,49 @@ os_get_option(const char *name) return opt; } +static struct hash_table *options_tbl; +static simple_mtx_t options_tbl_mtx = SIMPLE_MTX_INITIALIZER; + +/** + * NOTE: The strings that allocated with ralloc_strdup(options_tbl, ...) + * are freed by _mesa_hash_table_destroy automatically + */ +static void +options_tbl_fini(void) +{ + _mesa_hash_table_destroy(options_tbl, NULL); +} + +const char * +os_get_option_cached(const char *name) +{ + char *opt = NULL; + simple_mtx_lock(&options_tbl_mtx); + if (!options_tbl) { + options_tbl = _mesa_hash_table_create(NULL, _mesa_hash_string, + _mesa_key_string_equal); + if (options_tbl == NULL) { + goto exit_mutex; + } + atexit(options_tbl_fini); + } + struct hash_entry *entry = _mesa_hash_table_search(options_tbl, name); + if (entry) { + opt = entry->data; + goto exit_mutex; + } + + char *name_dup = ralloc_strdup(options_tbl, name); + if (name_dup == NULL) { + goto exit_mutex; + } + opt = ralloc_strdup(options_tbl, os_get_option(name)); + _mesa_hash_table_insert(options_tbl, name_dup, (void *)opt); +exit_mutex: + simple_mtx_unlock(&options_tbl_mtx); + return opt; +} + /** * Return the size of the total physical memory. * \param size returns the size of the total physical memory diff --git a/src/util/os_misc.h b/src/util/os_misc.h index ea475018d33..9be6cbc50a5 100644 --- a/src/util/os_misc.h +++ b/src/util/os_misc.h @@ -90,6 +90,16 @@ os_log_message(const char *message); const char * os_get_option(const char *name); +/* + * Get an option. Should return NULL if specified option is not set. + * It's will save the option into hash table for the first time, and + * for latter calling, it's will return the value comes from hash table + * directly, and the returned value will always be valid before program exit + * The disadvantage is that setenv, unsetenv, putenv won't take effect + * after this function is called + */ +const char * +os_get_option_cached(const char *name); /* * Get the total amount of physical memory available on the system. diff --git a/src/util/u_debug.c b/src/util/u_debug.c index d7ae2f9be8d..07c02b572f0 100644 --- a/src/util/u_debug.c +++ b/src/util/u_debug.c @@ -166,6 +166,23 @@ debug_get_option(const char *name, const char *dfault) } +const char * +debug_get_option_cached(const char *name, const char *dfault) +{ + const char *result; + + result = os_get_option_cached(name); + if (!result) + result = dfault; + + if (debug_get_option_should_print()) + debug_printf("%s: %s = %s\n", __FUNCTION__, name, + result ? result : "(null)"); + + return result; +} + + /** * Reads an environment variable and interprets its value as a boolean. * Recognizes 0/n/no/f/false case insensitive as false. diff --git a/src/util/u_debug.h b/src/util/u_debug.h index ab65ef2e96c..61cee1c43bd 100644 --- a/src/util/u_debug.h +++ b/src/util/u_debug.h @@ -355,6 +355,9 @@ comma_separated_list_contains(const char *list, const char *s); const char * debug_get_option(const char *name, const char *dfault); +const char * +debug_get_option_cached(const char *name, const char *dfault); + bool debug_get_bool_option(const char *name, bool dfault);