Add confirm_conf option

If the confirm_conf option is set, when the program starts, each of
the four malloc_conf strings will be printed, and each option will
be printed when being set.
This commit is contained in:
Yinan Zhang 2019-04-30 13:54:00 -07:00 committed by Qi Wang
parent 4c63b0e76a
commit c92ac30601
6 changed files with 204 additions and 115 deletions

View File

@ -904,6 +904,23 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
</para></listitem>
</varlistentry>
<varlistentry id="opt.confirm_conf">
<term>
<mallctl>opt.confirm_conf</mallctl>
(<type>bool</type>)
<literal>r-</literal>
</term>
<listitem><para>Confirm-runtime-options-when-program-starts
enabled/disabled. If true, the string specified via
<option>--with-malloc-conf</option>, the string pointed to by the
global variable <varname>malloc_conf</varname>, the <quote>name</quote>
of the file referenced by the symbolic link named
<filename class="symlink">/etc/malloc.conf</filename>, and the value of
the environment variable <envar>MALLOC_CONF</envar>, will be printed in
order. Then, each option being set will be individually printed. This
option is disabled by default.</para></listitem>
</varlistentry>
<varlistentry id="opt.abort_conf">
<term>
<mallctl>opt.abort_conf</mallctl>

View File

@ -10,6 +10,7 @@ extern bool malloc_slow;
/* Run-time options. */
extern bool opt_abort;
extern bool opt_abort_conf;
extern bool opt_confirm_conf;
extern const char *opt_junk;
extern bool opt_junk_alloc;
extern bool opt_junk_free;

View File

@ -81,6 +81,7 @@ CTL_PROTO(config_utrace)
CTL_PROTO(config_xmalloc)
CTL_PROTO(opt_abort)
CTL_PROTO(opt_abort_conf)
CTL_PROTO(opt_confirm_conf)
CTL_PROTO(opt_metadata_thp)
CTL_PROTO(opt_retain)
CTL_PROTO(opt_dss)
@ -304,6 +305,7 @@ static const ctl_named_node_t config_node[] = {
static const ctl_named_node_t opt_node[] = {
{NAME("abort"), CTL(opt_abort)},
{NAME("abort_conf"), CTL(opt_abort_conf)},
{NAME("confirm_conf"), CTL(opt_confirm_conf)},
{NAME("metadata_thp"), CTL(opt_metadata_thp)},
{NAME("retain"), CTL(opt_retain)},
{NAME("dss"), CTL(opt_dss)},
@ -1741,6 +1743,7 @@ CTL_RO_CONFIG_GEN(config_xmalloc, bool)
CTL_RO_NL_GEN(opt_abort, opt_abort, bool)
CTL_RO_NL_GEN(opt_abort_conf, opt_abort_conf, bool)
CTL_RO_NL_GEN(opt_confirm_conf, opt_confirm_conf, bool)
CTL_RO_NL_GEN(opt_metadata_thp, metadata_thp_mode_names[opt_metadata_thp],
const char *)
CTL_RO_NL_GEN(opt_retain, opt_retain, bool)

View File

@ -43,6 +43,8 @@ bool opt_abort_conf =
false
#endif
;
/* Intentionally default off, even with debug builds. */
bool opt_confirm_conf = false;
const char *opt_junk =
#if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
"true"
@ -929,93 +931,140 @@ malloc_slow_flag_init(void) {
malloc_slow = (malloc_slow_flags != 0);
}
/* Number of sources for initializing malloc_conf */
#define MALLOC_CONF_NSOURCES 4
static const char *
obtain_malloc_conf(unsigned which_source, char buf[PATH_MAX + 1]) {
if (config_debug) {
static unsigned read_source = 0;
/*
* Each source should only be read once, to minimize # of
* syscalls on init.
*/
assert(read_source++ == which_source);
}
assert(which_source < MALLOC_CONF_NSOURCES);
const char *ret;
switch (which_source) {
case 0:
ret = config_malloc_conf;
break;
case 1:
if (je_malloc_conf != NULL) {
/* Use options that were compiled into the program. */
ret = je_malloc_conf;
} else {
/* No configuration specified. */
ret = NULL;
}
break;
case 2: {
ssize_t linklen = 0;
#ifndef _WIN32
int saved_errno = errno;
const char *linkname =
# ifdef JEMALLOC_PREFIX
"/etc/"JEMALLOC_PREFIX"malloc.conf"
# else
"/etc/malloc.conf"
# endif
;
/*
* Try to use the contents of the "/etc/malloc.conf" symbolic
* link's name.
*/
#ifndef JEMALLOC_READLINKAT
linklen = readlink(linkname, buf, PATH_MAX);
#else
linklen = readlinkat(AT_FDCWD, linkname, buf, PATH_MAX);
#endif
if (linklen == -1) {
/* No configuration specified. */
linklen = 0;
/* Restore errno. */
set_errno(saved_errno);
}
#endif
buf[linklen] = '\0';
ret = buf;
break;
} case 3: {
const char *envname =
#ifdef JEMALLOC_PREFIX
JEMALLOC_CPREFIX"MALLOC_CONF"
#else
"MALLOC_CONF"
#endif
;
if ((ret = jemalloc_secure_getenv(envname)) != NULL) {
/*
* Do nothing; opts is already initialized to the value
* of the MALLOC_CONF environment variable.
*/
} else {
/* No configuration specified. */
ret = NULL;
}
break;
} default:
not_reached();
ret = NULL;
}
return ret;
}
static void
malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
malloc_conf_init_helper(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS],
bool initial_call, const char *opts_cache[MALLOC_CONF_NSOURCES],
char buf[PATH_MAX + 1]) {
static const char *opts_explain[MALLOC_CONF_NSOURCES] = {
"string specified via --with-malloc-conf",
"string pointed to by the global variable malloc_conf",
"\"name\" of the file referenced by the symbolic link named "
"/etc/malloc.conf",
"value of the environment variable MALLOC_CONF"
};
unsigned i;
char buf[PATH_MAX + 1];
const char *opts, *k, *v;
size_t klen, vlen;
for (i = 0; i < 4; i++) {
for (i = 0; i < MALLOC_CONF_NSOURCES; i++) {
/* Get runtime configuration. */
switch (i) {
case 0:
opts = config_malloc_conf;
break;
case 1:
if (je_malloc_conf != NULL) {
/*
* Use options that were compiled into the
* program.
*/
opts = je_malloc_conf;
} else {
/* No configuration specified. */
buf[0] = '\0';
opts = buf;
}
break;
case 2: {
ssize_t linklen = 0;
#ifndef _WIN32
int saved_errno = errno;
const char *linkname =
# ifdef JEMALLOC_PREFIX
"/etc/"JEMALLOC_PREFIX"malloc.conf"
# else
"/etc/malloc.conf"
# endif
;
/*
* Try to use the contents of the "/etc/malloc.conf"
* symbolic link's name.
*/
#ifndef JEMALLOC_READLINKAT
linklen = readlink(linkname, buf, sizeof(buf) - 1);
#else
linklen = readlinkat(AT_FDCWD, linkname, buf,
sizeof(buf) - 1);
#endif
if (linklen == -1) {
/* No configuration specified. */
linklen = 0;
/* Restore errno. */
set_errno(saved_errno);
}
#endif
buf[linklen] = '\0';
opts = buf;
break;
} case 3: {
const char *envname =
#ifdef JEMALLOC_PREFIX
JEMALLOC_CPREFIX"MALLOC_CONF"
#else
"MALLOC_CONF"
#endif
;
if ((opts = jemalloc_secure_getenv(envname)) != NULL) {
/*
* Do nothing; opts is already initialized to
* the value of the MALLOC_CONF environment
* variable.
*/
} else {
/* No configuration specified. */
buf[0] = '\0';
opts = buf;
}
break;
} default:
not_reached();
buf[0] = '\0';
opts = buf;
if (initial_call) {
opts_cache[i] = obtain_malloc_conf(i, buf);
}
opts = opts_cache[i];
if (!initial_call && opt_confirm_conf) {
malloc_printf(
"<jemalloc>: malloc_conf #%u (%s): \"%s\"\n",
i + 1, opts_explain[i], opts != NULL ? opts : "");
}
if (opts == NULL) {
continue;
}
while (*opts != '\0' && !malloc_conf_next(&opts, &k, &klen, &v,
&vlen)) {
#define CONF_ERROR(msg, k, klen, v, vlen) \
if (!initial_call) { \
malloc_conf_error( \
msg, k, klen, v, vlen); \
cur_opt_valid = false; \
}
#define CONF_CONTINUE { \
if (!initial_call && opt_confirm_conf \
&& cur_opt_valid) { \
malloc_printf("<jemalloc>: Set "\
"conf value: %.*s:%.*s\n", \
(int)klen, k, (int)vlen, v);\
} \
continue; \
}
#define CONF_MATCH(n) \
(sizeof(n)-1 == klen && strncmp(n, k, klen) == 0)
#define CONF_MATCH_VALUE(n) \
@ -1027,11 +1076,10 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
} else if (CONF_MATCH_VALUE("false")) { \
o = false; \
} else { \
malloc_conf_error( \
"Invalid conf value", \
CONF_ERROR("Invalid conf value",\
k, klen, v, vlen); \
} \
continue; \
CONF_CONTINUE; \
}
/*
* One of the CONF_MIN macros below expands, in one of the use points,
@ -1054,8 +1102,7 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
um = malloc_strtoumax(v, &end, 0); \
if (get_errno() != 0 || (uintptr_t)end -\
(uintptr_t)v != vlen) { \
malloc_conf_error( \
"Invalid conf value", \
CONF_ERROR("Invalid conf value",\
k, klen, v, vlen); \
} else if (clip) { \
if (check_min(um, (t)(min))) { \
@ -1069,7 +1116,7 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
} else { \
if (check_min(um, (t)(min)) || \
check_max(um, (t)(max))) { \
malloc_conf_error( \
CONF_ERROR( \
"Out-of-range " \
"conf value", \
k, klen, v, vlen); \
@ -1077,7 +1124,7 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
o = (t)um; \
} \
} \
continue; \
CONF_CONTINUE; \
}
#define CONF_HANDLE_UNSIGNED(o, n, min, max, check_min, check_max, \
clip) \
@ -1095,18 +1142,17 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
l = strtol(v, &end, 0); \
if (get_errno() != 0 || (uintptr_t)end -\
(uintptr_t)v != vlen) { \
malloc_conf_error( \
"Invalid conf value", \
CONF_ERROR("Invalid conf value",\
k, klen, v, vlen); \
} else if (l < (ssize_t)(min) || l > \
(ssize_t)(max)) { \
malloc_conf_error( \
CONF_ERROR( \
"Out-of-range conf value", \
k, klen, v, vlen); \
} else { \
o = l; \
} \
continue; \
CONF_CONTINUE; \
}
#define CONF_HANDLE_CHAR_P(o, n, d) \
if (CONF_MATCH(n)) { \
@ -1115,7 +1161,14 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
sizeof(o)-1; \
strncpy(o, v, cpylen); \
o[cpylen] = '\0'; \
continue; \
CONF_CONTINUE; \
}
bool cur_opt_valid = true;
CONF_HANDLE_BOOL(opt_confirm_conf, "confirm_conf")
if (initial_call) {
continue;
}
CONF_HANDLE_BOOL(opt_abort, "abort")
@ -1132,10 +1185,10 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
}
}
if (!match) {
malloc_conf_error("Invalid conf value",
CONF_ERROR("Invalid conf value",
k, klen, v, vlen);
}
continue;
CONF_CONTINUE;
}
CONF_HANDLE_BOOL(opt_retain, "retain")
if (strncmp("dss", k, klen) == 0) {
@ -1145,7 +1198,7 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
if (strncmp(dss_prec_names[i], v, vlen)
== 0) {
if (extent_dss_prec_set(i)) {
malloc_conf_error(
CONF_ERROR(
"Error setting dss",
k, klen, v, vlen);
} else {
@ -1157,10 +1210,10 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
}
}
if (!match) {
malloc_conf_error("Invalid conf value",
CONF_ERROR("Invalid conf value",
k, klen, v, vlen);
}
continue;
CONF_CONTINUE;
}
CONF_HANDLE_UNSIGNED(opt_narenas, "narenas", 1,
UINT_MAX, CONF_CHECK_MIN, CONF_DONT_CHECK_MAX,
@ -1178,14 +1231,14 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
if (err || bin_update_shard_size(
bin_shard_sizes, size_start,
size_end, nshards)) {
malloc_conf_error(
CONF_ERROR(
"Invalid settings for "
"bin_shards", k, klen, v,
vlen);
break;
}
} while (vlen_left > 0);
continue;
CONF_CONTINUE;
}
CONF_HANDLE_SSIZE_T(opt_dirty_decay_ms,
"dirty_decay_ms", -1, NSTIME_SEC_MAX * KQU(1000) <
@ -1198,7 +1251,7 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
CONF_HANDLE_BOOL(opt_stats_print, "stats_print")
if (CONF_MATCH("stats_print_opts")) {
init_opt_stats_print_opts(v, vlen);
continue;
CONF_CONTINUE;
}
if (config_fill) {
if (CONF_MATCH("junk")) {
@ -1219,11 +1272,11 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
opt_junk_alloc = false;
opt_junk_free = true;
} else {
malloc_conf_error(
"Invalid conf value", k,
klen, v, vlen);
CONF_ERROR(
"Invalid conf value",
k, klen, v, vlen);
}
continue;
CONF_CONTINUE;
}
CONF_HANDLE_BOOL(opt_zero, "zero")
}
@ -1260,7 +1313,7 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
if (strncmp(percpu_arena_mode_names[i],
v, vlen) == 0) {
if (!have_percpu_arena) {
malloc_conf_error(
CONF_ERROR(
"No getcpu support",
k, klen, v, vlen);
}
@ -1270,10 +1323,10 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
}
}
if (!match) {
malloc_conf_error("Invalid conf value",
CONF_ERROR("Invalid conf value",
k, klen, v, vlen);
}
continue;
CONF_CONTINUE;
}
CONF_HANDLE_BOOL(opt_background_thread,
"background_thread");
@ -1299,13 +1352,12 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
sc_data, slab_start,
slab_end, (int)pgs);
} else {
malloc_conf_error(
"Invalid settings for "
"slab_sizes", k, klen, v,
vlen);
CONF_ERROR("Invalid settings "
"for slab_sizes",
k, klen, v, vlen);
}
} while (!err && vlen_left > 0);
continue;
CONF_CONTINUE;
}
if (config_prof) {
CONF_HANDLE_BOOL(opt_prof, "prof")
@ -1334,7 +1386,7 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
vlen : sizeof(log_var_names) - 1);
strncpy(log_var_names, v, cpylen);
log_var_names[cpylen] = '\0';
continue;
CONF_CONTINUE;
}
}
if (CONF_MATCH("thp")) {
@ -1343,7 +1395,7 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
if (strncmp(thp_mode_names[i],v, vlen)
== 0) {
if (!have_madvise_huge) {
malloc_conf_error(
CONF_ERROR(
"No THP support",
k, klen, v, vlen);
}
@ -1353,13 +1405,14 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
}
}
if (!match) {
malloc_conf_error("Invalid conf value",
CONF_ERROR("Invalid conf value",
k, klen, v, vlen);
}
continue;
CONF_CONTINUE;
}
malloc_conf_error("Invalid conf pair", k, klen, v,
vlen);
CONF_ERROR("Invalid conf pair", k, klen, v, vlen);
#undef CONF_ERROR
#undef CONF_CONTINUE
#undef CONF_MATCH
#undef CONF_MATCH_VALUE
#undef CONF_HANDLE_BOOL
@ -1382,6 +1435,19 @@ malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
atomic_store_b(&log_init_done, true, ATOMIC_RELEASE);
}
static void
malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
const char *opts_cache[MALLOC_CONF_NSOURCES] = {NULL, NULL, NULL, NULL};
char buf[PATH_MAX + 1];
/* The first call only set the confirm_conf option and opts_cache */
malloc_conf_init_helper(NULL, NULL, true, opts_cache, buf);
malloc_conf_init_helper(sc_data, bin_shard_sizes, false, opts_cache,
NULL);
}
#undef MALLOC_CONF_NSOURCES
static bool
malloc_init_hard_needed(void) {
if (malloc_initialized() || (IS_INITIALIZER && malloc_init_state ==

View File

@ -1065,6 +1065,7 @@ stats_general_print(emitter_t *emitter) {
OPT_WRITE_BOOL("abort")
OPT_WRITE_BOOL("abort_conf")
OPT_WRITE_BOOL("confirm_conf")
OPT_WRITE_BOOL("retain")
OPT_WRITE_CHAR_P("dss")
OPT_WRITE_UNSIGNED("narenas")

View File

@ -159,6 +159,7 @@ TEST_BEGIN(test_mallctl_opt) {
TEST_MALLCTL_OPT(bool, abort, always);
TEST_MALLCTL_OPT(bool, abort_conf, always);
TEST_MALLCTL_OPT(bool, confirm_conf, always);
TEST_MALLCTL_OPT(const char *, metadata_thp, always);
TEST_MALLCTL_OPT(bool, retain, always);
TEST_MALLCTL_OPT(const char *, dss, always);