@@ -158,6 +158,12 @@ will be used, and CFLAGS sets optimization options for the compiler.
By default for x86_64, the GNU C Library is built with vector math
library. Use this option to disable vector math library.
+'--enable-tunables'
+ Tunables support allows additional library parameters to be
+ customized at runtime for each application. This is an
+ experimental feature and affects startup time and is thus disabled
+ by default.
+
'--build=BUILD-SYSTEM'
'--host=HOST-SYSTEM'
These options are for cross-compiling. If you specify both options
@@ -883,6 +883,11 @@ CPPFLAGS = $(config-extra-cppflags) $(CPPUNDEFS) $(CPPFLAGS-config) \
$(foreach lib,$(libof-$(basename $(@F))) \
$(libof-$(<F)) $(libof-$(@F)),$(CPPFLAGS-$(lib))) \
$(CPPFLAGS-$(<F)) $(CPPFLAGS-$(@F)) $(CPPFLAGS-$(basename $(@F)))
+
+ifeq (yes,$(build-tunables))
+CPPFLAGS += -DTOP_NAMESPACE=glibc
+endif
+
override CFLAGS = -std=gnu11 -fgnu89-inline $(config-extra-cflags) \
$(filter-out %frame-pointer,$(+cflags)) $(+gccwarn-c) \
$(sysdep-CFLAGS) $(CFLAGS-$(suffix $@)) $(CFLAGS-$(<F)) \
@@ -1054,6 +1059,17 @@ $(common-objpfx)libc-modules.stmp: $(..)scripts/gen-libc-modules.awk \
endif
+# Build the tunables list header early since it could be used by any module in
+# glibc.
+ifeq (yes,$(build-tunables))
+before-compile += $(common-objpfx)dl-tunable-list.h
+
+$(common-objpfx)dl-tunable-list.h: $(..)scripts/gen-tunables.awk \
+ $(..)elf/dl-tunables.list
+ $(AWK) -f $^ > $@.tmp
+ mv $@{.tmp,}
+endif
+
common-generated += libc-modules.h libc-modules.stmp
# The name under which the run-time dynamic linker is installed.
new file mode 100644
@@ -0,0 +1,74 @@
+ TUNABLE FRAMEWORK
+ =================
+
+The tunable framework allows modules within glibc to register variables that
+may be tweaked through an environment variable or an API call. It aims to
+enforce a strict namespace rule to bring consistency to naming of these tunable
+environment variables across the project.
+
+ADDING A NEW TUNABLE
+--------------------
+
+The TOP_NAMESPACE is defined by default as 'glibc' and it may be overridden in
+distributions for specific tunables if they want to add their own tunables.
+Downstream implementations are discouraged from using the 'glibc' namespace for
+tunables they don't already have consensus to push upstream.
+
+There are two steps to adding a tunable:
+
+1. Add a tunable ID:
+
+Modules that wish to use the tunables interface must define the
+TUNABLE_NAMESPACE macro. Following this, for each tunable you want to
+add, make an entry in elf/dl-tunables.list. The format of the file is as
+follows:
+
+TOP_NAMESPACE {
+ NAMESPACE1 {
+ TUNABLE1 {
+ # tunable attributes, one per line
+ }
+ # A tunable with default attributes, i.e. string variable.
+ TUNABLE2
+ TUNABLE3 {
+ # its attributes
+ }
+ }
+ NAMESPACE2 {
+ ...
+ }
+}
+
+The list of allowed attributes are:
+
+- type: Data type. Defaults to STRING. Allowed types are:
+ INT_32, SIZE_T. Note that as of now the STRING type is
+ neither defined nor supported since no tunables need
+ it. It will be in future though, when needed.
+
+- minval: Optional minimum acceptable value
+
+- maxval: Optional maximum acceptable value
+
+- env_alias: An alias environment variable
+
+- secure_env_alias: Specify whether the environment variable should be read
+ for setuid binaries.
+
+2. Call either the TUNABLE_SET_VALUE and pass into it the tunable name and a
+ pointer to the variable that should be set with the tunable value.
+ If additional work needs to be done after setting the value, use the
+ TUNABLE_SET_VALUE_WITH_CALLBACK instead and additionally pass a pointer to
+ the function that should be called if the tunable value has been set.
+
+FUTURE WORK
+-----------
+
+The framework currently only allows a one-time initialization of variables
+through environment variables and in some cases, modification of variables via
+an API call. A future goals for this project include:
+
+- Setting system-wide and user-wide defaults for tunables through some
+ mechanism like a configuration file.
+
+- Allow tweaking of some tunables at runtime
@@ -240,4 +240,7 @@
/* PowerPC32 uses fctidz for floating point to long long conversions. */
#define HAVE_PPC_FCTIDZ 0
+/* Build glibc with tunables support. */
+#define BUILD_TUNABLES 0
+
#endif
@@ -91,6 +91,7 @@ use-nscd = @use_nscd@
build-hardcoded-path-in-tests= @hardcoded_path_in_tests@
build-pt-chown = @build_pt_chown@
enable-lock-elision = @enable_lock_elision@
+build-tunables = @build_tunables@
# Build tools.
CC = @CC@
@@ -659,6 +659,7 @@ multi_arch
base_machine
add_on_subdirs
add_ons
+build_tunables
build_pt_chown
build_nscd
link_obsolete_rpc
@@ -773,6 +774,7 @@ enable_systemtap
enable_build_nscd
enable_nscd
enable_pt_chown
+enable_tunables
enable_mathvec
with_cpu
'
@@ -1440,6 +1442,7 @@ Optional Features:
--disable-build-nscd disable building and installing the nscd daemon
--disable-nscd library functions will not contact the nscd daemon
--enable-pt_chown Enable building and installing pt_chown
+ --enable-tunables Enable tunables support
--enable-mathvec Enable building and installing mathvec [default
depends on architecture]
@@ -3646,6 +3649,19 @@ if test "$build_pt_chown" = yes; then
fi
+# Check whether --enable-tunables was given.
+if test "${enable_tunables+set}" = set; then :
+ enableval=$enable_tunables; build_tunables=$enableval
+else
+ build_tunables=no
+fi
+
+
+if test "$build_tunables" = yes; then
+ $as_echo "#define BUILD_TUNABLES 1" >>confdefs.h
+
+fi
+
# The abi-tags file uses a fairly simplistic model for name recognition that
# can't distinguish i486-pc-linux-gnu fully from i486-pc-gnu. So we mutate a
# $host_os of `gnu*' here to be `gnu-gnu*' just so that it can tell.
@@ -395,6 +395,16 @@ if test "$build_pt_chown" = yes; then
AC_DEFINE(HAVE_PT_CHOWN)
fi
+AC_ARG_ENABLE([tunables],
+ [AS_HELP_STRING([--enable-tunables],
+ [Enable tunables support])],
+ [build_tunables=$enableval],
+ [build_tunables=no])
+AC_SUBST(build_tunables)
+if test "$build_tunables" = yes; then
+ AC_DEFINE(BUILD_TUNABLES)
+fi
+
# The abi-tags file uses a fairly simplistic model for name recognition that
# can't distinguish i486-pc-linux-gnu fully from i486-pc-gnu. So we mutate a
# $host_os of `gnu*' here to be `gnu-gnu*' just so that it can tell.
@@ -28,6 +28,9 @@
#include <libc-internal.h>
#include <ldsodefs.h>
+#if BUILD_TUNABLES
+# include <elf/dl-tunables.h>
+#endif
/* Set nonzero if we have to be prepared for more than one libc being
used in the process. Safe assumption if initializer never runs. */
@@ -74,6 +77,10 @@ _init (int argc, char **argv, char **envp)
#ifndef SHARED
__libc_init_secure ();
+#if BUILD_TUNABLES
+ __tunables_init (envp);
+#endif
+
/* First the initialization which normally would be done by the
dynamic linker. */
_dl_non_dynamic_init ();
@@ -35,6 +35,11 @@ dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \
ifeq (yes,$(use-ldconfig))
dl-routines += dl-cache
endif
+
+ifeq (yes,$(build-tunables))
+dl-routines += dl-tunables
+endif
+
all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
# But they are absent from the shared libc, because that code is in ld.so.
elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \
@@ -64,5 +64,8 @@ ld {
# Pointer protection.
__pointer_chk_guard;
+
+ # Set value of a tunable.
+ __tunable_set_val;
}
}
new file mode 100644
@@ -0,0 +1,45 @@
+/* Tunable type information.
+
+ Copyright (C) 2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _TUNABLE_TYPES_H_
+# define _TUNABLE_TYPES_H_
+#include <stddef.h>
+
+typedef void (*tunable_callback_t) (void);
+
+typedef enum
+{
+ TUNABLE_TYPE_INT_32,
+ TUNABLE_TYPE_SIZE_T
+} tunable_type_code_t;
+
+typedef struct
+{
+ tunable_type_code_t type_code;
+ int64_t min;
+ int64_t max;
+} tunable_type_t;
+
+typedef union
+{
+ int64_t numval;
+ const char *strval;
+} tunable_val_t;
+
+#endif
new file mode 100644
@@ -0,0 +1,172 @@
+/* The tunable framework. See the README to know how to use the tunable in
+ a glibc module.
+
+ Copyright (C) 2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define TUNABLES_INTERNAL 1
+#include "dl-tunables.h"
+
+/* Compare environment names, bounded by the name hardcoded in glibc. */
+static bool
+is_name (const char *orig, const char *envname)
+{
+ for (;*orig != '\0' && *envname != '\0'; envname++, orig++)
+ if (*orig != *envname)
+ break;
+
+ /* The ENVNAME is immediately followed by a value. */
+ if (*orig == '\0' && *envname == '=')
+ return true;
+ else
+ return false;
+}
+
+static bool
+get_next_env (char ***envp, char **name, size_t *namelen, char **val)
+{
+ char **ev = *envp;
+
+ while (ev != NULL && *ev != '\0')
+ {
+ char *envline = *ev;
+ int len = 0;
+
+ while (envline[len] != '\0' && envline[len] != '=')
+ len++;
+
+ /* Just the name and no value, go to the next one. */
+ if (envline[len] == '\0')
+ continue;
+
+ *name = envline;
+ *namelen = len;
+ *val = &envline[len + 1];
+ *envp = ++ev;
+
+ return true;
+ }
+
+ return false;
+}
+
+
+#define RETURN_IF_INVALID_RANGE(__cur, __val) \
+({ \
+ __typeof ((__cur)->type.min) min = (__cur)->type.min; \
+ __typeof ((__cur)->type.max) max = (__cur)->type.max; \
+ if (min != max && ((__val) < min || (__val) > max)) \
+ return; \
+})
+
+/* Validate range of the input value and initialize the tunable CUR if it looks
+ good. */
+static void
+tunable_initialize (tunable_t *cur)
+{
+ switch (cur->type.type_code)
+ {
+ case TUNABLE_TYPE_INT_32:
+ {
+ int32_t val = (int32_t) __strtoul_internal (cur->strval, NULL, 0, 0);
+ RETURN_IF_INVALID_RANGE (cur, val);
+ cur->val.numval = (int64_t) val;
+ break;
+ }
+ case TUNABLE_TYPE_SIZE_T:
+ {
+ size_t val = (size_t) __strtoul_internal (cur->strval, NULL, 0, 0);
+ RETURN_IF_INVALID_RANGE (cur, val);
+ cur->val.numval = (int64_t) val;
+ break;
+ }
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+/* Initialize the tunables list from the environment. For now we only use the
+ ENV_ALIAS to find values. Later we will also use the tunable names to find
+ values. */
+void
+__tunables_init (char **envp)
+{
+ char *envname = NULL;
+ char *envval = NULL;
+ size_t len = 0;
+
+ while (get_next_env (&envp, &envname, &len, &envval))
+ {
+ for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
+ {
+ tunable_t *cur = &tunable_list[i];
+
+ /* Skip over tunables that have either been set already or should be
+ skipped. */
+ if (cur->strval != NULL || cur->env_alias == NULL
+ || (__libc_enable_secure && !cur->secure_env_alias))
+ continue;
+
+ const char *name = cur->env_alias;
+
+ /* We have a match. Initialize and move on to the next line. */
+ if (is_name (name, envname))
+ {
+ cur->strval = envval;
+ tunable_initialize (cur);
+ break;
+ }
+ }
+ }
+}
+
+/* Set the tunable value. This is called by the module that the tunable exists
+ in. */
+void
+__tunable_set_val (tunable_id_t id, void *valp, void (*callback) (void))
+{
+ tunable_t *cur = &tunable_list[id];
+
+ /* Sanity check: don't do anything if our tunable was not set during
+ initialization. */
+ if (cur->strval == NULL)
+ return;
+
+ switch (cur->type.type_code)
+ {
+ case TUNABLE_TYPE_INT_32:
+ {
+ *((int32_t *) valp) = (int32_t) cur->val.numval;
+ break;
+ }
+ case TUNABLE_TYPE_SIZE_T:
+ {
+ *((size_t *) valp) = (size_t) cur->val.numval;
+ break;
+ }
+ default:
+ __builtin_unreachable ();
+ }
+
+ if (callback)
+ callback ();
+}
new file mode 100644
@@ -0,0 +1,76 @@
+/* The tunable framework. See the README to know how to use the tunable in
+ a glibc module.
+
+ Copyright (C) 2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _TUNABLES_H_
+# define _TUNABLES_H_
+# include <stddef.h>
+# include "dl-tunable-types.h"
+
+/* A tunable. */
+struct _tunable
+{
+ const char *name; /* Internal name of the tunable. */
+ tunable_type_t type; /* Data type of the tunable. */
+ tunable_val_t val; /* The value. */
+ const char *strval; /* The string containing the value,
+ points into envp. */
+ /* Compatibility elements. */
+ const char *env_alias; /* The compatibility environment
+ variable name. */
+ bool secure_env_alias; /* Whether the environment variable
+ must be read even for setuid
+ binaries. */
+};
+
+typedef struct _tunable tunable_t;
+
+/* Full name for a tunable is top_ns.tunable_ns.id. */
+#define TUNABLE_NAME_S(top,ns,id) #top "." #ns "." #id
+
+# define TUNABLE_ENUM_NAME(top,ns,id) TUNABLE_ENUM_NAME1 (top,ns,id)
+# define TUNABLE_ENUM_NAME1(top,ns,id) top ## _ ## ns ## _ ## id
+
+#include "dl-tunable-list.h"
+
+extern void __tunables_init (char **);
+extern void __tunable_set_val (tunable_id_t, void *, void (*) (void));
+
+/* Check if the tunable has been set to a non-default value and if it is, copy
+ it over into __VAL. */
+# define TUNABLE_SET_VAL(__id,__val) \
+({ \
+ __tunable_set_val \
+ (TUNABLE_ENUM_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id), (__val), \
+ NULL); \
+})
+
+/* Same as TUNABLE_SET_VAL, but also set the callback function to __CB and call
+ it. */
+# define TUNABLE_SET_VAL_WITH_CALLBACK(__id,__val,__cb) \
+({ \
+ __tunable_set_val \
+ (TUNABLE_ENUM_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, __id), (__val), \
+ DL_TUNABLE_CALLBACK (__cb)); \
+})
+
+/* Namespace sanity for callback functions. Use this macro to keep the
+ namespace of the modules clean. */
+#define DL_TUNABLE_CALLBACK(__name) _dl_tunable_ ## __name
+#endif
new file mode 100644
@@ -0,0 +1,50 @@
+# Allowed attributes for tunables:
+#
+# type: Defaults to STRING
+# minval: Optional minimum acceptable value
+# maxval: Optional maximum acceptable value
+# env_alias: An alias environment variable
+# secure_env_alias: Specify whether the environment variable should be read for
+# setuid binaries.
+
+glibc {
+ malloc {
+ check {
+ type: INT_32
+ minval: 0
+ maxval: 3
+ env_alias: MALLOC_CHECK_
+ secure_env_alias: true
+ }
+ top_pad {
+ type: SIZE_T
+ env_alias: MALLOC_TOP_PAD_
+ }
+ perturb {
+ type: INT_32
+ minval: 0
+ maxval: 0xff
+ env_alias: MALLOC_PERTURB_
+ }
+ mmap_threshold {
+ type: SIZE_T
+ env_alias: MALLOC_MMAP_THRESHOLD_
+ }
+ trim_threshold {
+ type: SIZE_T
+ env_alias: MALLOC_TRIM_THRESHOLD_
+ }
+ mmap_max {
+ type: INT_32
+ env_alias: MALLOC_MMAP_MAX_
+ }
+ arena_max {
+ type: SIZE_T
+ env_alias: MALLOC_ARENA_MAX
+ }
+ arena_test {
+ type: SIZE_T
+ env_alias: MALLOC_ARENA_TEST
+ }
+ }
+}
@@ -44,6 +44,10 @@
#include <assert.h>
+#if BUILD_TUNABLES
+# include <dl-tunables.h>
+#endif
+
/* Avoid PLT use for our local calls at startup. */
extern __typeof (__mempcpy) __mempcpy attribute_hidden;
@@ -2346,6 +2350,10 @@ process_envvars (enum mode *modep)
enum mode mode = normal;
char *debug_output = NULL;
+#if BUILD_TUNABLES
+ __tunables_init (_environ);
+#endif
+
/* This is the default place for profiling data file. */
GLRO(dl_profile_output)
= &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0];
@@ -31,6 +31,8 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
tst-malloc-backtrace tst-malloc-thread-exit \
tst-malloc-thread-fail tst-malloc-fork-deadlock \
tst-mallocfork2
+tests-static := tst-malloc-usable-static
+tests += $(tests-static)
test-srcs = tst-mtrace
routines = malloc morecore mcheck mtrace obstack \
@@ -138,6 +140,7 @@ endif
tst-mcheck-ENV = MALLOC_CHECK_=3
tst-malloc-usable-ENV = MALLOC_CHECK_=3
+tst-malloc-usable-static-ENV = MALLOC_CHECK_=3
# Uncomment this for test releases. For public releases it is too expensive.
#CPPFLAGS-malloc.o += -DMALLOC_DEBUG=1
@@ -19,6 +19,11 @@
#include <stdbool.h>
+#if BUILD_TUNABLES
+# define TUNABLE_NAMESPACE malloc
+# include <elf/dl-tunables.h>
+#endif
+
/* Compile-time constants. */
#define HEAP_MIN_SIZE (32 * 1024)
@@ -204,6 +209,15 @@ __malloc_fork_unlock_child (void)
mutex_init (&list_lock);
}
+#if BUILD_TUNABLES
+void
+DL_TUNABLE_CALLBACK (set_mallopt_check) (void)
+{
+ if (check_action != 0)
+ __malloc_check_init ();
+}
+
+#else
/* Initialization routine. */
#include <string.h>
extern char **_environ;
@@ -238,6 +252,7 @@ next_env_entry (char ***position)
return result;
}
+#endif
#ifdef SHARED
@@ -272,6 +287,24 @@ ptmalloc_init (void)
#endif
thread_arena = &main_arena;
+
+#if BUILD_TUNABLES
+ /* Ensure initialization/consolidation and do it under a lock so that a
+ thread attempting to use the arena in parallel waits on us till we
+ finish. */
+ mutex_lock (&main_arena.mutex);
+ malloc_consolidate (&main_arena);
+
+ TUNABLE_SET_VAL_WITH_CALLBACK (check, &check_action, set_mallopt_check);
+ TUNABLE_SET_VAL (top_pad, &mp_.top_pad);
+ TUNABLE_SET_VAL (perturb, &perturb_byte);
+ TUNABLE_SET_VAL (mmap_threshold, &mp_.mmap_threshold);
+ TUNABLE_SET_VAL (trim_threshold, &mp_.trim_threshold);
+ TUNABLE_SET_VAL (mmap_max, &mp_.n_mmaps_max);
+ TUNABLE_SET_VAL (arena_max, &mp_.arena_max);
+ TUNABLE_SET_VAL (arena_test, &mp_.arena_test);
+ mutex_unlock (&main_arena.mutex);
+#else
const char *s = NULL;
if (__glibc_likely (_environ != NULL))
{
@@ -340,6 +373,8 @@ ptmalloc_init (void)
if (check_action != 0)
__malloc_check_init ();
}
+#endif
+
#if HAVE_MALLOC_INIT_HOOK
void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);
if (hook != NULL)
new file mode 100644
@@ -0,0 +1 @@
+#include <malloc/tst-malloc-usable.c>
@@ -189,6 +189,11 @@ configure with @option{--disable-werror}.
By default for x86_64, @theglibc{} is built with vector math library.
Use this option to disable vector math library.
+@item --enable-tunables
+Tunables support allows additional library parameters to be customized at
+runtime for each application. This is an experimental feature and affects
+startup time and is thus disabled by default.
+
@item --build=@var{build-system}
@itemx --host=@var{host-system}
These options are for cross-compiling. If you specify both options and
new file mode 100644
@@ -0,0 +1,157 @@
+# Generate dl-tunable-list.h from dl-tunables.list
+
+BEGIN {
+ tunable=""
+ ns=""
+ top_ns=""
+}
+
+# Skip over blank lines and comments.
+/^#/ {
+ next
+}
+
+/^[ \t]*$/ {
+ next
+}
+
+# Beginning of either a top namespace, tunable namespace or a tunable, decided
+# on the current value of TUNABLE, NS or TOP_NS.
+$2 == "{" {
+ if (top_ns == "") {
+ top_ns = $1
+ }
+ else if (ns == "") {
+ ns = $1
+ }
+ else if (tunable == "") {
+ tunable = $1
+ }
+ else {
+ printf ("Unexpected occurrence of '{': %s:%d\n", FILENAME, FNR)
+ exit 1
+ }
+
+ next
+}
+
+# End of either a top namespace, tunable namespace or a tunable.
+$1 == "}" {
+ if (tunable != "") {
+ # Tunables definition ended, now fill in default attributes.
+ if (!types[top_ns][ns][tunable]) {
+ types[top_ns][ns][tunable] = "STRING"
+ }
+ if (!minvals[top_ns][ns][tunable]) {
+ minvals[top_ns][ns][tunable] = "0"
+ }
+ if (!maxvals[top_ns][ns][tunable]) {
+ maxvals[top_ns][ns][tunable] = "0"
+ }
+ if (!env_alias[top_ns][ns][tunable]) {
+ env_alias[top_ns][ns][tunable] = "NULL"
+ }
+ if (!secure_env_alias[top_ns][ns][tunable]) {
+ secure_env_alias[top_ns][ns][tunable] = "false"
+ }
+
+ tunable = ""
+ }
+ else if (ns != "") {
+ ns = ""
+ }
+ else if (top_ns != "") {
+ top_ns = ""
+ }
+ else {
+ printf ("syntax error: extra }: %s:%d\n", FILENAME, FNR)
+ exit 1
+ }
+ next
+}
+
+# Everything else, which could either be a tunable without any attributes or a
+# tunable attribute.
+{
+ if (ns == "") {
+ printf("Line %d: Invalid tunable outside a namespace: %s\n", NR, $0)
+ exit 1
+ }
+
+ if (tunable == "") {
+ # We encountered a tunable without any attributes, so note it with a
+ # default.
+ types[top_ns][ns][$1] = "STRING"
+ next
+ }
+
+ # Otherwise, we have encountered a tunable attribute.
+ split($0, arr, ":")
+ attr = gensub(/^[ \t]+|[ \t]+$/, "", "g", arr[1])
+ val = gensub(/^[ \t]+|[ \t]+$/, "", "g", arr[2])
+
+ if (attr == "type") {
+ types[top_ns][ns][tunable] = val
+ }
+ else if (attr == "minval") {
+ minvals[top_ns][ns][tunable] = val
+ }
+ else if (attr == "maxval") {
+ maxvals[top_ns][ns][tunable] = val
+ }
+ else if (attr == "env_alias") {
+ env_alias[top_ns][ns][tunable] = sprintf("\"%s\"", val)
+ }
+ else if (attr == "secure_env_alias") {
+ if (val == "true" || val == "false") {
+ secure_env_alias[top_ns][ns][tunable] = val
+ }
+ else {
+ printf("Line %d: Invalid value (%s) for secure_env_alias: %s, ", NR, val,
+ $0)
+ print("Allowed values are 'true' or 'false'")
+ exit 1
+ }
+ }
+}
+
+END {
+ if (ns != "") {
+ print "Unterminated namespace. Is a closing brace missing?"
+ exit 1
+ }
+
+ print "/* AUTOGENERATED by gen-tunables.awk. */"
+ print "#ifndef _TUNABLES_H_"
+ print "# error \"Do not include this file directly.\""
+ print "# error \"Include tunables.h instead.\""
+ print "#endif"
+
+ # Now, the enum names
+ print "\ntypedef enum"
+ print "{"
+ for (t in types) {
+ for (n in types[t]) {
+ for (m in types[t][n]) {
+ printf (" TUNABLE_ENUM_NAME(%s, %s, %s),\n", t, n, m);
+ }
+ }
+ }
+ print "} tunable_id_t;\n"
+
+ # Finally, the tunable list.
+ print "\n#ifdef TUNABLES_INTERNAL"
+ print "static tunable_t tunable_list[] = {"
+ for (t in types) {
+ for (n in types[t]) {
+ for (m in types[t][n]) {
+ printf (" {TUNABLE_NAME_S(%s, %s, %s)", t, n, m)
+ printf (", {TUNABLE_TYPE_%s, %s, %s}, {.numval = 0}, NULL, %s, %s},\n",
+ types[t][n][m], minvals[t][n][m], maxvals[t][n][m],
+ env_alias[t][n][m], secure_env_alias[t][n][m]);
+ }
+ }
+ }
+ print "};"
+ print "#endif"
+}