Home | History | Annotate | Download | only in internal
      1 #ifndef JEMALLOC_INTERNAL_LOG_H
      2 #define JEMALLOC_INTERNAL_LOG_H
      3 
      4 #include "jemalloc/internal/atomic.h"
      5 #include "jemalloc/internal/malloc_io.h"
      6 #include "jemalloc/internal/mutex.h"
      7 
      8 #ifdef JEMALLOC_LOG
      9 #  define JEMALLOC_LOG_VAR_BUFSIZE 1000
     10 #else
     11 #  define JEMALLOC_LOG_VAR_BUFSIZE 1
     12 #endif
     13 
     14 #define JEMALLOC_LOG_BUFSIZE 4096
     15 
     16 /*
     17  * The log malloc_conf option is a '|'-delimited list of log_var name segments
     18  * which should be logged.  The names are themselves hierarchical, with '.' as
     19  * the delimiter (a "segment" is just a prefix in the log namespace).  So, if
     20  * you have:
     21  *
     22  * log("arena", "log msg for arena"); // 1
     23  * log("arena.a", "log msg for arena.a"); // 2
     24  * log("arena.b", "log msg for arena.b"); // 3
     25  * log("arena.a.a", "log msg for arena.a.a"); // 4
     26  * log("extent.a", "log msg for extent.a"); // 5
     27  * log("extent.b", "log msg for extent.b"); // 6
     28  *
     29  * And your malloc_conf option is "log=arena.a|extent", then lines 2, 4, 5, and
     30  * 6 will print at runtime.  You can enable logging from all log vars by
     31  * writing "log=.".
     32  *
     33  * None of this should be regarded as a stable API for right now.  It's intended
     34  * as a debugging interface, to let us keep around some of our printf-debugging
     35  * statements.
     36  */
     37 
     38 extern char log_var_names[JEMALLOC_LOG_VAR_BUFSIZE];
     39 extern atomic_b_t log_init_done;
     40 
     41 typedef struct log_var_s log_var_t;
     42 struct log_var_s {
     43 	/*
     44 	 * Lowest bit is "inited", second lowest is "enabled".  Putting them in
     45 	 * a single word lets us avoid any fences on weak architectures.
     46 	 */
     47 	atomic_u_t state;
     48 	const char *name;
     49 };
     50 
     51 #define LOG_NOT_INITIALIZED 0U
     52 #define LOG_INITIALIZED_NOT_ENABLED 1U
     53 #define LOG_ENABLED 2U
     54 
     55 #define LOG_VAR_INIT(name_str) {ATOMIC_INIT(LOG_NOT_INITIALIZED), name_str}
     56 
     57 /*
     58  * Returns the value we should assume for state (which is not necessarily
     59  * accurate; if logging is done before logging has finished initializing, then
     60  * we default to doing the safe thing by logging everything).
     61  */
     62 unsigned log_var_update_state(log_var_t *log_var);
     63 
     64 /* We factor out the metadata management to allow us to test more easily. */
     65 #define log_do_begin(log_var)						\
     66 if (config_log) {							\
     67 	unsigned log_state = atomic_load_u(&(log_var).state,		\
     68 	    ATOMIC_RELAXED);						\
     69 	if (unlikely(log_state == LOG_NOT_INITIALIZED)) {		\
     70 		log_state = log_var_update_state(&(log_var));		\
     71 		assert(log_state != LOG_NOT_INITIALIZED);		\
     72 	}								\
     73 	if (log_state == LOG_ENABLED) {					\
     74 		{
     75 			/* User code executes here. */
     76 #define log_do_end(log_var)						\
     77 		}							\
     78 	}								\
     79 }
     80 
     81 /*
     82  * MSVC has some preprocessor bugs in its expansion of __VA_ARGS__ during
     83  * preprocessing.  To work around this, we take all potential extra arguments in
     84  * a var-args functions.  Since a varargs macro needs at least one argument in
     85  * the "...", we accept the format string there, and require that the first
     86  * argument in this "..." is a const char *.
     87  */
     88 static inline void
     89 log_impl_varargs(const char *name, ...) {
     90 	char buf[JEMALLOC_LOG_BUFSIZE];
     91 	va_list ap;
     92 
     93 	va_start(ap, name);
     94 	const char *format = va_arg(ap, const char *);
     95 	size_t dst_offset = 0;
     96 	dst_offset += malloc_snprintf(buf, JEMALLOC_LOG_BUFSIZE, "%s: ", name);
     97 	dst_offset += malloc_vsnprintf(buf + dst_offset,
     98 	    JEMALLOC_LOG_BUFSIZE - dst_offset, format, ap);
     99 	dst_offset += malloc_snprintf(buf + dst_offset,
    100 	    JEMALLOC_LOG_BUFSIZE - dst_offset, "\n");
    101 	va_end(ap);
    102 
    103 	malloc_write(buf);
    104 }
    105 
    106 /* Call as log("log.var.str", "format_string %d", arg_for_format_string); */
    107 #define LOG(log_var_str, ...)						\
    108 do {									\
    109 	static log_var_t log_var = LOG_VAR_INIT(log_var_str);		\
    110 	log_do_begin(log_var)						\
    111 		log_impl_varargs((log_var).name, __VA_ARGS__);		\
    112 	log_do_end(log_var)						\
    113 } while (0)
    114 
    115 #endif /* JEMALLOC_INTERNAL_LOG_H */
    116