Blame jemalloc/include/jemalloc/internal/log.h

Packit 345191
#ifndef JEMALLOC_INTERNAL_LOG_H
Packit 345191
#define JEMALLOC_INTERNAL_LOG_H
Packit 345191
Packit 345191
#include "jemalloc/internal/atomic.h"
Packit 345191
#include "jemalloc/internal/malloc_io.h"
Packit 345191
#include "jemalloc/internal/mutex.h"
Packit 345191
Packit 345191
#ifdef JEMALLOC_LOG
Packit 345191
#  define JEMALLOC_LOG_VAR_BUFSIZE 1000
Packit 345191
#else
Packit 345191
#  define JEMALLOC_LOG_VAR_BUFSIZE 1
Packit 345191
#endif
Packit 345191
Packit 345191
#define JEMALLOC_LOG_BUFSIZE 4096
Packit 345191
Packit 345191
/*
Packit 345191
 * The log malloc_conf option is a '|'-delimited list of log_var name segments
Packit 345191
 * which should be logged.  The names are themselves hierarchical, with '.' as
Packit 345191
 * the delimiter (a "segment" is just a prefix in the log namespace).  So, if
Packit 345191
 * you have:
Packit 345191
 *
Packit 345191
 * log("arena", "log msg for arena"); // 1
Packit 345191
 * log("arena.a", "log msg for arena.a"); // 2
Packit 345191
 * log("arena.b", "log msg for arena.b"); // 3
Packit 345191
 * log("arena.a.a", "log msg for arena.a.a"); // 4
Packit 345191
 * log("extent.a", "log msg for extent.a"); // 5
Packit 345191
 * log("extent.b", "log msg for extent.b"); // 6
Packit 345191
 *
Packit 345191
 * And your malloc_conf option is "log=arena.a|extent", then lines 2, 4, 5, and
Packit 345191
 * 6 will print at runtime.  You can enable logging from all log vars by
Packit 345191
 * writing "log=.".
Packit 345191
 *
Packit 345191
 * None of this should be regarded as a stable API for right now.  It's intended
Packit 345191
 * as a debugging interface, to let us keep around some of our printf-debugging
Packit 345191
 * statements.
Packit 345191
 */
Packit 345191
Packit 345191
extern char log_var_names[JEMALLOC_LOG_VAR_BUFSIZE];
Packit 345191
extern atomic_b_t log_init_done;
Packit 345191
Packit 345191
typedef struct log_var_s log_var_t;
Packit 345191
struct log_var_s {
Packit 345191
	/*
Packit 345191
	 * Lowest bit is "inited", second lowest is "enabled".  Putting them in
Packit 345191
	 * a single word lets us avoid any fences on weak architectures.
Packit 345191
	 */
Packit 345191
	atomic_u_t state;
Packit 345191
	const char *name;
Packit 345191
};
Packit 345191
Packit 345191
#define LOG_NOT_INITIALIZED 0U
Packit 345191
#define LOG_INITIALIZED_NOT_ENABLED 1U
Packit 345191
#define LOG_ENABLED 2U
Packit 345191
Packit 345191
#define LOG_VAR_INIT(name_str) {ATOMIC_INIT(LOG_NOT_INITIALIZED), name_str}
Packit 345191
Packit 345191
/*
Packit 345191
 * Returns the value we should assume for state (which is not necessarily
Packit 345191
 * accurate; if logging is done before logging has finished initializing, then
Packit 345191
 * we default to doing the safe thing by logging everything).
Packit 345191
 */
Packit 345191
unsigned log_var_update_state(log_var_t *log_var);
Packit 345191
Packit 345191
/* We factor out the metadata management to allow us to test more easily. */
Packit 345191
#define log_do_begin(log_var)						\
Packit 345191
if (config_log) {							\
Packit 345191
	unsigned log_state = atomic_load_u(&(log_var).state,		\
Packit 345191
	    ATOMIC_RELAXED);						\
Packit 345191
	if (unlikely(log_state == LOG_NOT_INITIALIZED)) {		\
Packit 345191
		log_state = log_var_update_state(&(log_var));		\
Packit 345191
		assert(log_state != LOG_NOT_INITIALIZED);		\
Packit 345191
	}								\
Packit 345191
	if (log_state == LOG_ENABLED) {					\
Packit 345191
		{
Packit 345191
			/* User code executes here. */
Packit 345191
#define log_do_end(log_var)						\
Packit 345191
		}							\
Packit 345191
	}								\
Packit 345191
}
Packit 345191
Packit 345191
/*
Packit 345191
 * MSVC has some preprocessor bugs in its expansion of __VA_ARGS__ during
Packit 345191
 * preprocessing.  To work around this, we take all potential extra arguments in
Packit 345191
 * a var-args functions.  Since a varargs macro needs at least one argument in
Packit 345191
 * the "...", we accept the format string there, and require that the first
Packit 345191
 * argument in this "..." is a const char *.
Packit 345191
 */
Packit 345191
static inline void
Packit 345191
log_impl_varargs(const char *name, ...) {
Packit 345191
	char buf[JEMALLOC_LOG_BUFSIZE];
Packit 345191
	va_list ap;
Packit 345191
Packit 345191
	va_start(ap, name);
Packit 345191
	const char *format = va_arg(ap, const char *);
Packit 345191
	size_t dst_offset = 0;
Packit 345191
	dst_offset += malloc_snprintf(buf, JEMALLOC_LOG_BUFSIZE, "%s: ", name);
Packit 345191
	dst_offset += malloc_vsnprintf(buf + dst_offset,
Packit 345191
	    JEMALLOC_LOG_BUFSIZE - dst_offset, format, ap);
Packit 345191
	dst_offset += malloc_snprintf(buf + dst_offset,
Packit 345191
	    JEMALLOC_LOG_BUFSIZE - dst_offset, "\n");
Packit 345191
	va_end(ap);
Packit 345191
Packit 345191
	malloc_write(buf);
Packit 345191
}
Packit 345191
Packit 345191
/* Call as log("log.var.str", "format_string %d", arg_for_format_string); */
Packit 345191
#define LOG(log_var_str, ...)						\
Packit 345191
do {									\
Packit 345191
	static log_var_t log_var = LOG_VAR_INIT(log_var_str);		\
Packit 345191
	log_do_begin(log_var)						\
Packit 345191
		log_impl_varargs((log_var).name, __VA_ARGS__);		\
Packit 345191
	log_do_end(log_var)						\
Packit 345191
} while (0)
Packit 345191
Packit 345191
#endif /* JEMALLOC_INTERNAL_LOG_H */