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-g9e5710c


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  9e5710c8d1f435e4f44d9804a796a10955a367ef (commit)

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

commit 9e5710c8d1f435e4f44d9804a796a10955a367ef
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Mon Jan 11 02:02:53 2016 +0530

    Initialize tunable list with the GLIBC_TUNABLES environment variable

diff --git a/tunables/tunables.c b/tunables/tunables.c
index 2ae1050..ddd1934 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"
+
 static int
 t_strncmp (const char *a, const char *b, size_t len)
 {
@@ -46,6 +50,31 @@ t_strncmp (const char *a, const char *b, size_t len)
   return 0;
 }
 
+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
+    {
+      memcpy (out, in, len);
+      return out;
+    }
+}
+
 static bool
 get_next_env (char ***envp, char **name, size_t *namelen, char **val)
 {
@@ -74,14 +103,78 @@ get_next_env (char ***envp, char **name, size_t *namelen, char **val)
   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.  */
+/* Initialize tunables from the GLIBC_TUNABLES environment variable.  The
+   variable is set as colon separated name=value pairs.  */
 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))
+    {
+      if (!t_strncmp (envname, GLIBC_TUNABLES, sizeof (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_strncmp (name, tunable_list[i].name, SIZE_MAX) == 0)
+	    {
+	      tunable_list[i].val = value;
+	      break;
+	    }
+	}
+
+      if (end == ':')
+	p += len + 1;
+      else
+	goto out;
+    }
+out:
+  initialized = true;
 }
 strong_alias (__tunables_init, tunables_init)
 

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

commit 0353ad280945888461b61c73979ec70588b9b655
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Mon Jan 11 02:00:18 2016 +0530

    Tunables framework
    
    Macro and function to register a tunable and initialize it from the
    environment variable it is defined from.

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/conform/linknamespace.pl b/conform/linknamespace.pl
index d6a1850..4e8e287 100644
--- a/conform/linknamespace.pl
+++ b/conform/linknamespace.pl
@@ -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;
 }
diff --git a/csu/init-first.c b/csu/init-first.c
index 77c6e1c..f86a029 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..be12d98 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..5a65fc9
--- /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 "};"
+  printf "#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..00a75c1
--- /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..2ae1050
--- /dev/null
+++ b/tunables/tunables.c
@@ -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)
diff --git a/tunables/tunables.h b/tunables/tunables.h
new file mode 100644
index 0000000..095eda2
--- /dev/null
+++ b/tunables/tunables.h
@@ -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);		      \
+  }
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]