@@ -164,6 +164,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)) \
@@ -1098,6 +1103,10 @@ all-subdirs = csu assert ctype locale intl catgets math setjmp signal \
crypt localedata timezone rt conform debug mathvec \
$(add-on-subdirs) dlfcn elf
+ifeq (yes,$(build-tunables))
+all-subdirs += tunables
+endif
+
ifndef avoid-generated
# sysd-sorted itself will contain rules making the sysd-sorted target
# depend on Depend files. But if you just added a Depend file to an
@@ -231,4 +231,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
@@ -90,6 +90,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]
@@ -3642,6 +3645,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.
@@ -392,6 +392,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.
@@ -50,8 +50,10 @@ close (STDSYMS) || die ("close $stdsyms_file: $!\n");
# * False positive: matherr only used conditionally. matherrf/matherrl are used
# by IA64 too for the same reason.
#
+# * False positive: tunable_register, compat_tunables_init_envvars,
+# tunables_init. These functions are in the glibc internal namespace.
@whitelist = qw(stdin stdout stderr re_syntax_options matherr matherrf
- matherrl);
+ matherrl tunable_register compat_tunables_init_envvars tunables_init);
foreach my $sym (@whitelist) {
$stdsyms{$sym} = 1;
}
@@ -26,6 +26,9 @@
#include <sys/param.h>
#include <sys/types.h>
#include <libc-internal.h>
+#if BUILD_TUNABLES
+# include <tunables/tunables.h>
+#endif
#include <ldsodefs.h>
@@ -96,6 +99,10 @@ _init (int argc, char **argv, char **envp)
#if defined SHARED && !defined NO_CTORS_DTORS_SECTIONS
__libc_global_ctors ();
#endif
+
+#if BUILD_TUNABLES
+ tunables_init (__environ);
+#endif
}
/* This function is defined here so that if this file ever gets into
@@ -32,7 +32,7 @@ extern int __libc_multiple_libcs;
#include <tls.h>
#ifndef SHARED
# include <dl-osinfo.h>
-extern void __pthread_initialize_minimal (void);
+extern void __pthread_initialize_minimal (int, char **, char **);
# ifndef THREAD_SET_STACK_GUARD
/* Only exported for architectures that don't store the stack guard canary
in thread local area. */
@@ -193,7 +193,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
/* Initialize the thread library at least a bit since the libgcc
functions are using thread functions if these are available and
we need to setup errno. */
- __pthread_initialize_minimal ();
+ __pthread_initialize_minimal (argc, argv, __environ);
/* Set up the stack checker's canary. */
uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
@@ -19,6 +19,11 @@
#include <stdbool.h>
+#if BUILD_TUNABLES
+# define TUNABLE_NAMESPACE malloc
+# include <tunables/tunables.h>
+#endif
+
/* Compile-time constants. */
#define HEAP_MIN_SIZE (32 * 1024)
@@ -332,6 +337,61 @@ ptmalloc_unlock_all2 (void)
# endif
#endif /* !NO_THREADS */
+#if BUILD_TUNABLES
+static void
+tunable_set_mallopt_top_pad (const char *val)
+{
+ __libc_mallopt (M_TOP_PAD, atoi (val));
+}
+
+static void
+tunable_set_mallopt_perturb (const char *val)
+{
+ __libc_mallopt (M_PERTURB, atoi (val));
+}
+
+static void
+tunable_set_mallopt_mmap_max (const char *val)
+{
+ __libc_mallopt (M_MMAP_MAX, atoi (val));
+}
+
+static void
+tunable_set_mallopt_arena_max (const char *val)
+{
+ __libc_mallopt (M_ARENA_MAX, atoi (val));
+}
+
+static void
+tunable_set_mallopt_arena_test (const char *val)
+{
+ __libc_mallopt (M_ARENA_TEST, atoi (val));
+}
+
+static void
+tunable_set_mallopt_trim_threshold (const char *val)
+{
+ __libc_mallopt (M_TRIM_THRESHOLD, atoi (val));
+}
+
+static void
+tunable_set_mallopt_mmap_threshold (const char *val)
+{
+ __libc_mallopt (M_MMAP_THRESHOLD, atoi (val));
+}
+
+static void
+tunable_set_mallopt_check (const char *val)
+{
+ if (val[0])
+ {
+ __libc_mallopt (M_CHECK_ACTION, (int) (val[0] - '0'));
+ if (check_action != 0)
+ __malloc_check_init ();
+ }
+}
+
+#else
/* Initialization routine. */
#include <string.h>
extern char **_environ;
@@ -366,6 +426,7 @@ next_env_entry (char ***position)
return result;
}
+#endif
#ifdef SHARED
@@ -401,6 +462,29 @@ ptmalloc_init (void)
thread_arena = &main_arena;
thread_atfork (ptmalloc_lock_all, ptmalloc_unlock_all, ptmalloc_unlock_all2);
+
+#if BUILD_TUNABLES
+ COMPAT_TUNABLES_NAMESPACE_BEGIN (8);
+
+ COMPAT_TUNABLE_REGISTER_SECURE (check, "MALLOC_CHECK_",
+ tunable_set_mallopt_check);
+ COMPAT_TUNABLE_REGISTER (top_pad, "MALLOC_TOP_PAD_",
+ tunable_set_mallopt_top_pad);
+ COMPAT_TUNABLE_REGISTER (perturb, "MALLOC_PERTURB_",
+ tunable_set_mallopt_perturb);
+ COMPAT_TUNABLE_REGISTER (mmap_threshold, "MALLOC_MMAP_THRESHOLD_",
+ tunable_set_mallopt_mmap_threshold);
+ COMPAT_TUNABLE_REGISTER (trim_threshold, "MALLOC_TRIM_THRESHOLD_",
+ tunable_set_mallopt_trim_threshold);
+ COMPAT_TUNABLE_REGISTER (mmap_max, "MALLOC_MMAP_MAX_",
+ tunable_set_mallopt_mmap_max);
+ COMPAT_TUNABLE_REGISTER (arena_max, "MALLOC_ARENA_MAX",
+ tunable_set_mallopt_arena_max);
+ COMPAT_TUNABLE_REGISTER (arena_test, "MALLOC_ARENA_TEST",
+ tunable_set_mallopt_arena_test);
+
+ COMPAT_TUNABLES_NAMESPACE_INIT ();
+#else
const char *s = NULL;
if (__glibc_likely (_environ != NULL))
{
@@ -469,6 +553,8 @@ ptmalloc_init (void)
if (check_action != 0)
__malloc_check_init ();
}
+#endif
+
void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);
if (hook != NULL)
(*hook)();
@@ -195,6 +195,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
@@ -38,6 +38,9 @@
#include <kernel-features.h>
#include <libc-internal.h>
#include <pthread-pids.h>
+#if BUILD_TUNABLES
+# include <tunables/tunables.h>
+#endif
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
/* Pointer to the corresponding variable in libc. */
@@ -297,7 +300,7 @@ extern void **__libc_dl_error_tsd (void) __attribute__ ((const));
static bool __nptl_initial_report_events __attribute_used__;
void
-__pthread_initialize_minimal_internal (void)
+__pthread_initialize_minimal_internal (int argc, char **argv, char **envp)
{
#ifndef SHARED
/* Unlike in the dynamically linked case the dynamic linker has not
@@ -311,6 +314,10 @@ __pthread_initialize_minimal_internal (void)
__asm __volatile ("");
#endif
+#if BUILD_TUNABLES
+ tunables_init (envp);
+#endif
+
/* Minimal initialization of the thread descriptor. */
struct pthread *pd = THREAD_SELF;
__pthread_initialize_pids (pd);
new file mode 100644
@@ -0,0 +1,84 @@
+# Generate tunable-list.h from tunables.list
+
+BEGIN {
+ ns=""
+ top_ns=""
+}
+
+$2 == "{" {
+ if (top_ns == "") {
+ top_ns = $1
+ }
+ else if (ns == "") {
+ ns = $1
+ count = 0
+ }
+ else {
+ printf ("Unexpected occurrence of '{' inside a namespace: %s:%d\n",
+ FILENAME, FNR)
+ exit 1
+ }
+
+ next
+}
+
+$1 == "}" {
+ if (ns != "") {
+ ns = ""
+ }
+ else if (top_ns != "") {
+ top_ns = ""
+ }
+ else {
+ printf ("syntax error: extra }: %s:%d\n", FILENAME, FNR)
+ exit 1
+ }
+ next
+}
+
+{
+ if (ns == "") {
+ print "Invalid tunable outside a namespace"
+ exit 1
+ }
+ val[top_ns][ns][count] = $1
+ count = count + 1
+}
+
+END {
+ if (ns != "") {
+ print "Unterminated namespace. Is a closing brace missing?"
+ exit 1
+ }
+
+ print "/* Print a full tunable enum name. */"
+ print "#include <stddef.h>"
+ print "#define TUNABLE_ENUM_NAME(top,ns,id) TUNABLE_ENUM_NAME1 (top,ns,id)"
+ print "#define TUNABLE_ENUM_NAME1(top,ns,id) top ## _ ## ns ## _ ## id\n"
+
+ print "/* Full name for a tunable is top_ns.tunable_ns.id. */"
+ print "#define TUNABLE_NAME_S(top,ns,id) #top \".\" #ns \".\" #id\n"
+
+ print "typedef enum"
+ print "{"
+ for (t in val) {
+ for (n in val[t]) {
+ for (c in val[t][n]) {
+ printf (" TUNABLE_ENUM_NAME(%s, %s, %s),\n", t, n, val[t][n][c]);
+ }
+ }
+ }
+ print "} tunable_id_t;\n"
+ print "#ifdef TUNABLES_INTERNAL"
+ print "static tunable_t tunable_list[] = {"
+ for (t in val) {
+ for (n in val[t]) {
+ for (c in val[t][n]) {
+ printf (" {TUNABLE_NAME_S(%s, %s, %s), NULL, NULL, false},\n",
+ t, n, val[t][n][c], t, n, val[t][n][c]);
+ }
+ }
+ }
+ print "};"
+ printf "#endif"
+}
new file mode 100644
@@ -0,0 +1,33 @@
+# 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/>.
+
+#
+# Makefile for tunables.
+#
+subdir := tunables
+
+include ../Makeconfig
+
+routines = tunables
+
+$(objpfx)tunables.os: tunable-list.h
+
+tunable-list.h: $(..)scripts/gen-tunables.awk tunables.list
+ $(AWK) -f $^ > $@.tmp
+ mv $@{.tmp,}
+
+include ../Rules
new file mode 100644
@@ -0,0 +1,93 @@
+ 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
+register, call the TUNABLE_REGISTER macro.
+
+The TUNABLE_REGISTER macro takes the following arguments:
+
+- id: The short name of the tunable. It will be concatenated with
+ the TOP_NAMESPACE and TUNABLE_NAMESPACE to build the full ID of
+ the tunable.
+
+- setter: A function that accepts a string input and initializes the
+ tunable variable. The prototype of the function should be as
+ follows:
+
+ void setter_func (const char *)
+
+2. Add to tunables.list:
+
+This file nests tunable ids inside their tunable namespace within curly braces
+and multiple such namespaces are in turn nested inside their top namespaces in
+a similar manner. The malloc and resolv snippets for example could look like
+this:
+
+glibc {
+ malloc {
+ check
+ top_pad
+ }
+ resolv {
+ secure_dns
+ }
+}
+
+Add your tunable in this hierarchy using the proper nesting for your namespace
+and top namespace. If the top namespace is not glibc, create a new snippet
+with its own hierarchy, separate from the glibc hierarchy.
+
+ADDING A LEGACY TUNABLE
+-----------------------
+
+One may add tunables for variables that are currently controlled by users with
+environment variables. Multiple such variables should be defined together for
+better performance by using the COMPAT_TUNABLES_NAMESPACE_BEGIN macro, which
+accepts a numeric parameter with the number of tunables you intend to register
+in the block.
+
+Individual tunables are then registered using the COMPAT_TUNABLE_REGISTER and
+COMPAT_TUNABLE_REGISTER_SECURE macros. They take the following parameters:
+
+- id: The tunable ID, similar to the normal way of adding a tunable
+
+- env: The name of the legacy environment variable so that one may
+ read its value and use it.
+
+- setter: The setter function, similar to the normal way of adding a
+ tunable.
+
+COMPAT_TUNABLE_REGISTER reads the environment variable only for non-setuid
+binaries, whereas COMPAT_TUNABLE_REGISTER_SECURE always attempts to read the
+environment variable. Use COMPAT_TUNABLE_REGISTER_SECURE with care.
+
+You will also have to add the tunable id to tunables/tunables.list.
+
+DO NOT ADD NEW TUNABLES USING THIS MECHANISM!
+
+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 goal for this project is to allow tweaking of some
+values in a running process, possibly through some kind of shared memory
+mechanism.
new file mode 100644
@@ -0,0 +1,8 @@
+# Exports from tunables should only be in the GLIBC_PRIVATE namespace.
+libc {
+ GLIBC_PRIVATE {
+ compat_tunables_init_envvars;
+ tunables_init;
+ tunable_register;
+ }
+}
new file mode 100644
@@ -0,0 +1,32 @@
+/* Print a full tunable enum name. */
+#include <stddef.h>
+#define TUNABLE_ENUM_NAME(top,ns,id) TUNABLE_ENUM_NAME1 (top,ns,id)
+#define TUNABLE_ENUM_NAME1(top,ns,id) top ## _ ## ns ## _ ## id
+
+/* Full name for a tunable is top_ns.tunable_ns.id. */
+#define TUNABLE_NAME_S(top,ns,id) #top "." #ns "." #id
+
+typedef enum
+{
+ TUNABLE_ENUM_NAME(glibc, malloc, check),
+ TUNABLE_ENUM_NAME(glibc, malloc, top_pad),
+ TUNABLE_ENUM_NAME(glibc, malloc, perturb),
+ TUNABLE_ENUM_NAME(glibc, malloc, mmap_threshold),
+ TUNABLE_ENUM_NAME(glibc, malloc, trim_threshold),
+ TUNABLE_ENUM_NAME(glibc, malloc, mmap_max),
+ TUNABLE_ENUM_NAME(glibc, malloc, arena_max),
+ TUNABLE_ENUM_NAME(glibc, malloc, arena_test),
+} tunable_id_t;
+
+#ifdef TUNABLES_INTERNAL
+static tunable_t tunable_list[] = {
+ {TUNABLE_NAME_S(glibc, malloc, check), NULL, NULL, false},
+ {TUNABLE_NAME_S(glibc, malloc, top_pad), NULL, NULL, false},
+ {TUNABLE_NAME_S(glibc, malloc, perturb), NULL, NULL, false},
+ {TUNABLE_NAME_S(glibc, malloc, mmap_threshold), NULL, NULL, false},
+ {TUNABLE_NAME_S(glibc, malloc, trim_threshold), NULL, NULL, false},
+ {TUNABLE_NAME_S(glibc, malloc, mmap_max), NULL, NULL, false},
+ {TUNABLE_NAME_S(glibc, malloc, arena_max), NULL, NULL, false},
+ {TUNABLE_NAME_S(glibc, malloc, arena_test), NULL, NULL, false},
+};
+#endif
new file mode 100644
@@ -0,0 +1,147 @@
+/* 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 <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+extern char **__environ;
+
+#define TUNABLES_INTERNAL 1
+#include "tunables.h"
+
+static int
+t_strncmp (const char *a, const char *b, size_t len)
+{
+ size_t i = 0;
+
+ for (i = 0; i < len && *a != '\0' && *b != '\0'; i++, a++, b++)
+ if (*a != *b)
+ return *a - *b;
+
+ /* If we weren't limited by LEN, then one of the strings terminated. */
+ if (i < len)
+ return *a - *b;
+
+ return 0;
+}
+
+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;
+}
+
+/* This is where tunables will be read in from either an environment variable,
+ a set of environment variables or some other source and then initialized.
+ Caller should pass it the environment variable; __environ may not be
+ reliable if it is called earlier than libc.so initialization. */
+void
+__tunables_init (char **envp)
+{
+ /* Empty for now. */
+}
+strong_alias (__tunables_init, tunables_init)
+
+/* Initialize all tunables using its legacy environment variable values whose
+ names are passed in ENVVARS. */
+void
+__compat_tunables_init_envvars (struct compat_tunable_env *envvars, int count)
+{
+ /* Traverse through the environment to find environment variables we may need
+ to set. */
+ char **envp = __environ;
+ char *envname = NULL;
+ char *envval = NULL;
+ size_t len = 0;
+
+ while (get_next_env (&envp, &envname, &len, &envval))
+ {
+ int init_count = 0;
+ for (int i = 0; i < count; i++)
+ {
+ tunable_id_t t = envvars[i].id;
+ tunable_t *cur = &tunable_list[t];
+
+ /* Skip over tunables that have already been initialized. */
+ if (cur->initialized)
+ {
+ init_count++;
+ continue;
+ }
+
+ const char *name = envvars[i].env;
+
+ /* We have a match. Initialize and move on to the next line. */
+ if (t_strncmp (envname, name, len) == 0)
+ {
+ cur->val = envval;
+ cur->set (cur->val);
+ cur->initialized = true;
+ break;
+ }
+ }
+
+ /* All of the tunable envvars have been initialized. */
+ if (count == init_count)
+ break;
+ }
+}
+strong_alias (__compat_tunables_init_envvars, compat_tunables_init_envvars)
+
+/* Initialize a tunable and set its value. */
+void
+__tunable_register (tunable_id_t id, tunable_setter_t set_func)
+{
+ tunable_t *cur = &tunable_list[id];
+
+ cur->set = set_func;
+ if (cur->val != NULL)
+ {
+ set_func (cur->val);
+ cur->initialized = true;
+ }
+}
+strong_alias (__tunable_register, tunable_register)
new file mode 100644
@@ -0,0 +1,111 @@
+/* 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 <stdbool.h>
+
+typedef void (*tunable_setter_t) (const char *);
+
+/* A tunable. */
+struct _tunable
+{
+ const char *name;
+ const char *val;
+ tunable_setter_t set;
+ bool initialized;
+};
+
+typedef struct _tunable tunable_t;
+
+#include "tunable-list.h"
+
+struct compat_tunable_env
+{
+ tunable_id_t id;
+ const char *env;
+};
+
+/* Avoid a PLT reference when called from within libc.so. */
+#if IS_IN (libc) && !defined TUNABLES_INTERNAL
+# define compat_tunables_init_envvars __compat_tunables_init_envvars
+# define tunable_register __tunable_register
+# define tunables_init __tunables_init
+#endif
+
+extern void compat_tunables_init_envvars (struct compat_tunable_env *, int);
+extern void tunable_register (tunable_id_t, tunable_setter_t);
+extern void tunables_init (char **);
+
+/* Register a tunable ID in namespace NS inside the glibc top namespace with
+ SET as the setter function. */
+#define TUNABLE_REGISTER(ns,id,set) \
+ TUNABLE_REGISTER_FULL (TOP_NAMESPACE, ns, id, set)
+
+/* Register a tunable ID in namespace NS inside the TNS top namespace with
+ SET as the setter function. */
+#define TUNABLE_REGISTER_FULL(tns,ns,id,set) \
+ tunable_register (TUNABLE_ENUM_NAME (tns, ns, id), (set))
+
+
+
+/* COMPATIBILITY INTERFACE. These macros should be used to define tunables for
+ variables that are currently being controlled using environment variables.
+ New tunables must not use this interface. */
+
+#define _ADD_COMPAT_TUNABLE_ENV(__id,__env) \
+({ \
+ envvars[envvars_cnt].id = TUNABLE_ENUM_NAME (TOP_NAMESPACE, \
+ TUNABLE_NAMESPACE, __id); \
+ envvars[envvars_cnt++].env = (__env); \
+})
+
+/* Start registering tunables in the current namespace. */
+#define COMPAT_TUNABLES_NAMESPACE_BEGIN(size) \
+ { \
+ struct compat_tunable_env envvars[size]; \
+ int envvars_cnt = 0;
+
+/* Register a tunable. This macro validates that the call is OK and then calls
+ tunable_init to do the real work of adding the tunable and setting its value
+ based on its environment variable(s). */
+#define COMPAT_TUNABLE_REGISTER(id,env,set) \
+({ \
+ assert (envvars_cnt < (sizeof (envvars) \
+ / sizeof (struct compat_tunable_env))); \
+ if (!__libc_enable_secure) \
+ _ADD_COMPAT_TUNABLE_ENV (id, env); \
+ TUNABLE_REGISTER (TUNABLE_NAMESPACE, id, set); \
+})
+
+/* Does exactly the same thing as TUNABLE_REGISTER, except that it allows the
+ tunable to look for environment variable values even for setuid binaries.
+ This is a separate macro and not just another parameter in TUNABLE_REGISTER
+ to avoid accidentally setting a secure flag where it is not required. */
+#define COMPAT_TUNABLE_REGISTER_SECURE(id,env,set) \
+({ \
+ assert (envvars_cnt < (sizeof (envvars) \
+ / sizeof (struct compat_tunable_env))); \
+ _ADD_COMPAT_TUNABLE_ENV(id, env); \
+ TUNABLE_REGISTER (TUNABLE_NAMESPACE, id, set); \
+})
+
+/* Initialize tunables in the namespace. */
+#define COMPAT_TUNABLES_NAMESPACE_INIT() \
+ compat_tunables_init_envvars (envvars, envvars_cnt); \
+ }
new file mode 100644
@@ -0,0 +1,12 @@
+glibc {
+ malloc {
+ check
+ top_pad
+ perturb
+ mmap_threshold
+ trim_threshold
+ mmap_max
+ arena_max
+ arena_test
+ }
+}