This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch siddhesh/tunables created. glibc-2.22-647-gfc5d6de


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, siddhesh/tunables has been created
        at  fc5d6deabc5a1b5e9eb2456c2b3862bea25210df (commit)

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=fc5d6deabc5a1b5e9eb2456c2b3862bea25210df

commit fc5d6deabc5a1b5e9eb2456c2b3862bea25210df
Author: Siddhesh Poyarekar <sid@reserved-bit.com>
Date:   Mon Jan 11 16:41:43 2016 +0530

    Initialize tunable list with the GLIBC_TUNABLES environment variable
    
    Read tunables values from the users using the GLIBC_TUNABLES
    environment variable.  The value of this variable is a colon-separated
    list of name=value pairs.  So a typical string would look like this:
    
    GLIBC_TUNABLES=glibc.malloc.mmap_threshold=2048:glibc.malloc.trim_threshold=1024
    
    	* tunables/tunables.c: Include sys/mman.h and libc-internals.h.
    	(GLIBC_TUNABLES): New macro.
    	(t_strdup): New function.
    	(__tunables_init): Implement initializer.

diff --git a/tunables/tunables.c b/tunables/tunables.c
index 8834aff..d5090fd 100644
--- a/tunables/tunables.c
+++ b/tunables/tunables.c
@@ -24,12 +24,16 @@
 #include <stdbool.h>
 #include <unistd.h>
 #include <sys/param.h>
+#include <sys/mman.h>
+#include <libc-internal.h>
 
 extern char **__environ;
 
 #define TUNABLES_INTERNAL 1
 #include "tunables.h"
 
+#define GLIBC_TUNABLES "GLIBC_TUNABLES"
+
 /* We avoid calling into the C library as much as we can, especially functions
    that we know could use tunables in future for some reason or the other.  For
    example, we call mmap directly instead of malloc because malloc uses
@@ -57,6 +61,31 @@ t_strcmp (const char *a, const char *b)
   return *a - *b;
 }
 
+static char *
+t_strdup (const char *in)
+{
+  size_t len = 0;
+
+  while (in[len] != '\0')
+    len++;
+
+  /* Allocate enough number of pages.  Given the number of tunables this should
+     not exceed a single page but we err on the conservative side and try to
+     allocate space as needed.  */
+  size_t alloclen = ALIGN_UP (len + 1, __getpagesize ());
+
+  char *out = __mmap (NULL, alloclen, PROT_READ | PROT_WRITE,
+		      MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+
+  if (__glibc_unlikely (out == MAP_FAILED))
+    return NULL;
+  else
+    {
+      t_memcpy (out, in, len);
+      return out;
+    }
+}
+
 static bool
 get_next_env (char ***envp, char **name, size_t *namelen, char **val)
 {
@@ -93,7 +122,78 @@ get_next_env (char ***envp, char **name, size_t *namelen, char **val)
 void
 __tunables_init (char **envp)
 {
-  /* Empty for now.  */
+  static bool initialized = false;
+
+  if (__glibc_likely (initialized))
+    return;
+
+  char **evp = envp;
+  char *p = NULL;
+
+  char *envname;
+  size_t envnamelen;
+  char *envval;
+
+  while (get_next_env (&evp, &envname, &envnamelen, &envval))
+    {
+      char *name = alloca (envnamelen + 1);
+
+      t_memcpy (name, envname, envnamelen);
+      name[envnamelen] = '\0';
+
+      if (!t_strcmp (name, GLIBC_TUNABLES))
+	{
+	  p = t_strdup (envval);
+	  break;
+	}
+    }
+
+  if (p == NULL || *p == '\0')
+    goto out;
+
+  while (true)
+    {
+      char *name = p;
+      size_t len = 0;
+
+      /* First, find where the name ends.  */
+      while (p[len] != '=' && p[len] != '\0')
+	len++;
+
+      /* If we reach the end of the string before getting a valid name-value
+	 pair, bail out.  */
+      if (p[len] == '\0')
+	goto out;
+
+      p[len] = '\0';
+      p += len + 1;
+
+      char *value = p;
+      len = 0;
+
+      while (p[len] != ':' && p[len] != '\0')
+	len++;
+
+      char end = p[len];
+      p[len] = '\0';
+
+      /* Add the tunable if it exists.  */
+      for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
+	{
+	  if (t_strcmp (name, tunable_list[i].name) == 0)
+	    {
+	      tunable_list[i].val = value;
+	      break;
+	    }
+	}
+
+      if (end == ':')
+	p += len + 1;
+      else
+	goto out;
+    }
+out:
+  initialized = true;
 }
 libc_hidden_def (__tunables_init)
 

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=c9ffcb855d2cbfc69481855c0bc9ac6db162285d

commit c9ffcb855d2cbfc69481855c0bc9ac6db162285d
Author: Siddhesh Poyarekar <sid@reserved-bit.com>
Date:   Mon Jan 11 16:41:20 2016 +0530

    Add framework for tunables
    
    The tunables framework allows us to uniformly manage and expose global
    variables inside glibc as switches to users.  tunables/README has
    instructions for glibc developers to add new tunables.
    
    Tunables support can be enabled by passing the --enable-tunables
    configure flag to the configure script.  This patch only adds a
    framework and does not pose any limitations on how tunable values are
    read from the user.  It also adds environment variables used in malloc
    behaviour tweaking to the tunables framework as a PoC of the
    compatibility interface.
    
    	* manual/install.texi: Add --enable-tunables option.
    	* INSTALL: Regenerate.
    	* Makeconfig (CPPFLAGS): Define TOP_NAMESPACE.
    	(all-subdirs): Add tunables.
    	* config.h.in: Add BUILD_TUNABLES.
    	* config.make.in: Add build-tunables.
    	* configure.ac: Add --enable-tunables option.
    	* configure: Regenerate.
    	* csu/init-first.c: Include tunables.h.
    	(_init): Initialize tunables.
    	* nptl/nptl-init.c [BUILD_TUNABLES]: Include tunables.h.
    	(__pthread_initialize_minimal_internal): Accept argc, argv and
    	envp.  Initialize tunables.
    	* csu/libc-start.c (LIBC_START_MAIN): Adjust.
    	* malloc/arena.c [BUILD_TUNABLES]: Include tunables.h.  Define
    	TUNABLE_NAMESPACE.
    	(tunable_set_mallopt_top_pad, tunable_set_mallopt_perturb,
    	tunable_set_mallopt_mmap_max, tunable_set_mallopt_arena_max,
    	tunable_set_mallopt_arena_test,
    	tunable_set_mallopt_trim_threshold,
    	tunable_set_mallopt_mmap_threshold,
    	tunable_set_mallopt_check): New functions.
    	(ptmalloc_init): Use them and register tunables.
    	* scripts/gen-tunables.awk: New file.
    	* tunables/Makefile: New file.
    	* tunables/README: New file.
    	* tunables/Versions: New file.
    	* tunables/tunable-list.h: New auto-generated file.
    	* tunables/tunables.c: New file.
    	* tunables/tunables.h: New file.
    	* tunables/tunables.list: New file.

diff --git a/INSTALL b/INSTALL
index c70ea9f..dd06e2e 100644
--- a/INSTALL
+++ b/INSTALL
@@ -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
diff --git a/Makeconfig b/Makeconfig
index 87a22e8..8ac199b 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -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
diff --git a/config.h.in b/config.h.in
index ec9c8bc..9b07580 100644
--- a/config.h.in
+++ b/config.h.in
@@ -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
diff --git a/config.make.in b/config.make.in
index 05ed6ec..b158f51 100644
--- a/config.make.in
+++ b/config.make.in
@@ -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@
diff --git a/configure b/configure
index aa05d49..6fef02c 100755
--- a/configure
+++ b/configure
@@ -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.
diff --git a/configure.ac b/configure.ac
index ee7a3f1..41507ac 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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.
diff --git a/csu/init-first.c b/csu/init-first.c
index 77c6e1c..a4e0c54 100644
--- a/csu/init-first.c
+++ b/csu/init-first.c
@@ -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
diff --git a/csu/libc-start.c b/csu/libc-start.c
index f4aa01a..7629fec 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -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);
diff --git a/malloc/arena.c b/malloc/arena.c
index 1edb4d4..f773b10 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -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)();
diff --git a/manual/install.texi b/manual/install.texi
index de9d270..95392ea 100644
--- a/manual/install.texi
+++ b/manual/install.texi
@@ -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
diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
index bdbdfed..6667801 100644
--- a/nptl/nptl-init.c
+++ b/nptl/nptl-init.c
@@ -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);
diff --git a/scripts/gen-tunables.awk b/scripts/gen-tunables.awk
new file mode 100644
index 0000000..ccbf789
--- /dev/null
+++ b/scripts/gen-tunables.awk
@@ -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 "};"
+  print "#endif"
+}
diff --git a/tunables/Makefile b/tunables/Makefile
new file mode 100644
index 0000000..44439f6
--- /dev/null
+++ b/tunables/Makefile
@@ -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
diff --git a/tunables/README b/tunables/README
new file mode 100644
index 0000000..02a3f7a
--- /dev/null
+++ b/tunables/README
@@ -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.
diff --git a/tunables/Versions b/tunables/Versions
new file mode 100644
index 0000000..4c68b0e
--- /dev/null
+++ b/tunables/Versions
@@ -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;
+  }
+}
diff --git a/tunables/tunable-list.h b/tunables/tunable-list.h
new file mode 100644
index 0000000..2b1caa4
--- /dev/null
+++ b/tunables/tunable-list.h
@@ -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
diff --git a/tunables/tunables.c b/tunables/tunables.c
new file mode 100644
index 0000000..8834aff
--- /dev/null
+++ b/tunables/tunables.c
@@ -0,0 +1,163 @@
+/* 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"
+
+/* We avoid calling into the C library as much as we can, especially functions
+   that we know could use tunables in future for some reason or the other.  For
+   example, we call mmap directly instead of malloc because malloc uses
+   tunables.  Similarly, the string functions may use tunables in future to
+   select optimal routines and we want to make sure we stay out of the way and
+   not invoke their initializers before the tunable list has been
+   initialized.  */
+
+static void
+t_memcpy (char *dest, const char *src, size_t len)
+{
+  for (size_t i = 0; i < len; i++)
+    dest[i] = src[i];
+}
+
+static int
+t_strcmp (const char *a, const char *b)
+{
+  size_t i = 0;
+
+  for (i = 0; *a != '\0' && *b != '\0'; i++, a++, b++)
+    if (*a != *b)
+      return *a - *b;
+
+  return *a - *b;
+}
+
+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;
+}
+
+/* Initialize tunables from the GLIBC_TUNABLES environment variable.  The
+   variable is set as colon separated name=value pairs.  This routine may be
+   called from the constructor of either libpthread.so or lic.so.  Constructor
+   calls for libraries are protected by the dl_load_lock, so this routine won't
+   be called concurrently from diferent threads.  */
+void
+__tunables_init (char **envp)
+{
+  /* Empty for now.  */
+}
+libc_hidden_def (__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;
+	  char *ename = alloca (len + 1);
+
+	  t_memcpy (ename, envname, len);
+	  ename[len] = '\0';
+
+	  /* We have a match.  Initialize and move on to the next line.  */
+	  if (t_strcmp (ename, name) == 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;
+    }
+}
+libc_hidden_def (__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;
+    }
+}
+libc_hidden_def (__tunable_register)
diff --git a/tunables/tunables.h b/tunables/tunables.h
new file mode 100644
index 0000000..6aef30e
--- /dev/null
+++ b/tunables/tunables.h
@@ -0,0 +1,110 @@
+/* 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;
+};
+
+
+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 **);
+
+/* Avoid a PLT reference when called from within libc.so.  */
+libc_hidden_proto (__compat_tunables_init_envvars)
+libc_hidden_proto (__tunable_register)
+libc_hidden_proto (__tunables_init)
+
+/* 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);		      \
+  }
diff --git a/tunables/tunables.list b/tunables/tunables.list
new file mode 100644
index 0000000..f1335cc
--- /dev/null
+++ b/tunables/tunables.list
@@ -0,0 +1,12 @@
+glibc {
+  malloc {
+    check
+    top_pad
+    perturb
+    mmap_threshold
+    trim_threshold
+    mmap_max
+    arena_max
+    arena_test
+  }
+}

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=9485cb586f36cadba166dd46d4017f059f091048

commit 9485cb586f36cadba166dd46d4017f059f091048
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Sun Jan 10 12:30:47 2016 +0530

    revert elf changes

diff --git a/elf/dl-environ.c b/elf/dl-environ.c
index 1f03d45..5240e9d 100644
--- a/elf/dl-environ.c
+++ b/elf/dl-environ.c
@@ -21,6 +21,35 @@
 #include <unistd.h>
 #include <ldsodefs.h>
 
+/* Walk through the environment of the process and return all entries
+   starting with `LD_'.  */
+char *
+internal_function
+_dl_next_ld_env_entry (char ***position)
+{
+  char **current = *position;
+  char *result = NULL;
+
+  while (*current != NULL)
+    {
+      if (__builtin_expect ((*current)[0] == 'L', 0)
+	  && (*current)[1] == 'D' && (*current)[2] == '_')
+	{
+	  result = &(*current)[3];
+
+	  /* Save current position for next visit.  */
+	  *position = ++current;
+
+	  break;
+	}
+
+      ++current;
+    }
+
+  return result;
+}
+
+
 /* In ld.so __environ is not exported.  */
 extern char **__environ attribute_hidden;
 
diff --git a/elf/rtld.c b/elf/rtld.c
index d8153ac..647661c 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2337,20 +2337,6 @@ process_dl_audit (char *str)
    all the entries.  */
 extern char **_environ attribute_hidden;
 
-#include <tunables/tunables.h>
-
-static bool
-get_ld_env_entry (char *runp, char **envline)
-{
-  if (__glibc_unlikely (runp[0] == 'L') && runp[1] == 'D' && runp[2] == '_')
-    {
-      *envline = &runp[3];
-      return true;
-    }
-
-  *envline = runp;
-  return false;
-}
 
 static void
 process_envvars (enum mode *modep)
@@ -2364,30 +2350,19 @@ process_envvars (enum mode *modep)
   GLRO(dl_profile_output)
     = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0];
 
-  for (runp = _environ; *runp != NULL; ++runp)
+  while ((envline = _dl_next_ld_env_entry (&runp)) != NULL)
     {
       size_t len = 0;
 
-      bool is_ld_entry = get_ld_env_entry (*runp, &envline);
-
       while (envline[len] != '\0' && envline[len] != '=')
 	++len;
 
       if (envline[len] != '=')
-	/* This is a variable at the end of the string without
+	/* This is a "LD_" variable at the end of the string without
 	   a '=' character.  Ignore it since otherwise we will access
 	   invalid memory below.  */
 	continue;
 
-      /* Tunables list.  */
-      if (!__libc_enable_secure && len == 14
-	  && memcmp (envline, "GLIBC_TUNABLES", 14) == 0)
-	tunables_init (&envline[15]);
-
-      /* From here on, only process the LD_* variables.  */
-      if (!is_ld_entry)
-	continue;
-
       switch (len)
 	{
 	case 4:

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=b8bd478c1453d8181495a14cbb765a168f132444

commit b8bd478c1453d8181495a14cbb765a168f132444
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Sun Jan 10 12:30:26 2016 +0530

    Changes to elf

diff --git a/elf/dl-environ.c b/elf/dl-environ.c
index 5240e9d..1f03d45 100644
--- a/elf/dl-environ.c
+++ b/elf/dl-environ.c
@@ -21,35 +21,6 @@
 #include <unistd.h>
 #include <ldsodefs.h>
 
-/* Walk through the environment of the process and return all entries
-   starting with `LD_'.  */
-char *
-internal_function
-_dl_next_ld_env_entry (char ***position)
-{
-  char **current = *position;
-  char *result = NULL;
-
-  while (*current != NULL)
-    {
-      if (__builtin_expect ((*current)[0] == 'L', 0)
-	  && (*current)[1] == 'D' && (*current)[2] == '_')
-	{
-	  result = &(*current)[3];
-
-	  /* Save current position for next visit.  */
-	  *position = ++current;
-
-	  break;
-	}
-
-      ++current;
-    }
-
-  return result;
-}
-
-
 /* In ld.so __environ is not exported.  */
 extern char **__environ attribute_hidden;
 
diff --git a/elf/rtld.c b/elf/rtld.c
index 647661c..d8153ac 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2337,6 +2337,20 @@ process_dl_audit (char *str)
    all the entries.  */
 extern char **_environ attribute_hidden;
 
+#include <tunables/tunables.h>
+
+static bool
+get_ld_env_entry (char *runp, char **envline)
+{
+  if (__glibc_unlikely (runp[0] == 'L') && runp[1] == 'D' && runp[2] == '_')
+    {
+      *envline = &runp[3];
+      return true;
+    }
+
+  *envline = runp;
+  return false;
+}
 
 static void
 process_envvars (enum mode *modep)
@@ -2350,19 +2364,30 @@ process_envvars (enum mode *modep)
   GLRO(dl_profile_output)
     = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0];
 
-  while ((envline = _dl_next_ld_env_entry (&runp)) != NULL)
+  for (runp = _environ; *runp != NULL; ++runp)
     {
       size_t len = 0;
 
+      bool is_ld_entry = get_ld_env_entry (*runp, &envline);
+
       while (envline[len] != '\0' && envline[len] != '=')
 	++len;
 
       if (envline[len] != '=')
-	/* This is a "LD_" variable at the end of the string without
+	/* This is a variable at the end of the string without
 	   a '=' character.  Ignore it since otherwise we will access
 	   invalid memory below.  */
 	continue;
 
+      /* Tunables list.  */
+      if (!__libc_enable_secure && len == 14
+	  && memcmp (envline, "GLIBC_TUNABLES", 14) == 0)
+	tunables_init (&envline[15]);
+
+      /* From here on, only process the LD_* variables.  */
+      if (!is_ld_entry)
+	continue;
+
       switch (len)
 	{
 	case 4:

-----------------------------------------------------------------------


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]