util: Add helpers for various one-time-init patters
A fairly common pattern for debug envvars is something like:
static int should_print = -1;
if (should_print < 0)
should_print = env_var_as_unsigned("NIR_PRINT", 0);
Unfortunately helgrind doesn't realize that we expect to always get the
same return value, so we don't actually care about the race condition
here.
Add a helper get_once() and do_once macros, with extra locking to make
helgrind/drd happy. Note that other than the nir usages (which are
limited to debug builds), other usages are not in hot-paths.
Signed-off-by: Rob Clark <robdclark@chromium.org>
Reviewed-by: Kristian H. Kristensen <hoegsberg@google.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7644>
This commit is contained in:
@@ -27,6 +27,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "util/simple_mtx.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -50,4 +52,63 @@ env_var_as_unsigned(const char *var_name, unsigned default_value);
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Helper for arbitrary one-time initialization, with additional locking
|
||||
* to ensure the initialization only happens once (and to make tools like
|
||||
* helgrind happy).
|
||||
*/
|
||||
#define do_once for( \
|
||||
struct __do_once_data *__d = ({ \
|
||||
static struct __do_once_data __sd = { \
|
||||
.lock = _SIMPLE_MTX_INITIALIZER_NP, \
|
||||
.done = false, \
|
||||
}; \
|
||||
simple_mtx_lock(&__sd.lock); \
|
||||
&__sd; \
|
||||
}); \
|
||||
({ \
|
||||
if (__d->done) \
|
||||
simple_mtx_unlock(&__d->lock); \
|
||||
!__d->done; \
|
||||
}); \
|
||||
__d->done = true)
|
||||
|
||||
struct __do_once_data {
|
||||
simple_mtx_t lock;
|
||||
bool done;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper for one-time debug value from env-var, and other similar cases,
|
||||
* where the expression is expected to return the same value each time.
|
||||
*
|
||||
* This has additional locking, compared to open-coding the initialization,
|
||||
* to make tools like helgrind happy.
|
||||
*/
|
||||
#define get_once(__expr) ({ \
|
||||
static __typeof__(__expr) __val; \
|
||||
do_once { \
|
||||
__val = __expr; \
|
||||
} \
|
||||
__val; \
|
||||
})
|
||||
|
||||
/**
|
||||
* Alternative version of get_once() which has no locking in release builds,
|
||||
* suitable for hot-paths.
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
#define get_once_nolock(__expr) ({ \
|
||||
static bool __once; \
|
||||
static __typeof__(__expr) __val; \
|
||||
if (!__once) { \
|
||||
__val = __expr; \
|
||||
__once = true; \
|
||||
} \
|
||||
__val; \
|
||||
})
|
||||
#else
|
||||
#define get_once_nolock(__expr) get_once(__expr)
|
||||
#endif
|
||||
|
||||
#endif /* _UTIL_DEBUG_H */
|
||||
|
||||
+5
-28
@@ -40,6 +40,7 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "util/debug.h"
|
||||
#include "util/os_misc.h"
|
||||
#include "util/detect_os.h"
|
||||
#include "util/macros.h"
|
||||
@@ -407,52 +408,28 @@ debug_get_flags_option(const char *name,
|
||||
static const char * \
|
||||
debug_get_option_ ## suffix (void) \
|
||||
{ \
|
||||
static bool first = true; \
|
||||
static const char * value; \
|
||||
if (first) { \
|
||||
first = false; \
|
||||
value = debug_get_option(name, dfault); \
|
||||
} \
|
||||
return value; \
|
||||
return get_once_nolock(debug_get_option(name, dfault)); \
|
||||
}
|
||||
|
||||
#define DEBUG_GET_ONCE_BOOL_OPTION(sufix, name, dfault) \
|
||||
static bool \
|
||||
debug_get_option_ ## sufix (void) \
|
||||
{ \
|
||||
static bool first = true; \
|
||||
static bool value; \
|
||||
if (first) { \
|
||||
first = false; \
|
||||
value = debug_get_bool_option(name, dfault); \
|
||||
} \
|
||||
return value; \
|
||||
return get_once_nolock(debug_get_bool_option(name, dfault)); \
|
||||
}
|
||||
|
||||
#define DEBUG_GET_ONCE_NUM_OPTION(sufix, name, dfault) \
|
||||
static long \
|
||||
debug_get_option_ ## sufix (void) \
|
||||
{ \
|
||||
static bool first = true; \
|
||||
static long value; \
|
||||
if (first) { \
|
||||
first = false; \
|
||||
value = debug_get_num_option(name, dfault); \
|
||||
} \
|
||||
return value; \
|
||||
return get_once_nolock(debug_get_num_option(name, dfault)); \
|
||||
}
|
||||
|
||||
#define DEBUG_GET_ONCE_FLAGS_OPTION(sufix, name, flags, dfault) \
|
||||
static unsigned long \
|
||||
debug_get_option_ ## sufix (void) \
|
||||
{ \
|
||||
static bool first = true; \
|
||||
static unsigned long value; \
|
||||
if (first) { \
|
||||
first = false; \
|
||||
value = debug_get_flags_option(name, flags, dfault); \
|
||||
} \
|
||||
return value; \
|
||||
return get_once_nolock(debug_get_flags_option(name, flags, dfault)); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user