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.21-653-g73f7d93


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  73f7d93699b403aafc2b4b4115d2bc188b38501f (commit)

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

commit 73f7d93699b403aafc2b4b4115d2bc188b38501f
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Fri May 15 18:19:14 2015 +0530

    Add malloc env vars to tunables
    
    Fix up everything in tunables along the way

diff --git a/malloc/arena.c b/malloc/arena.c
index 5448b0a..08217a3 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -20,6 +20,7 @@
 #include <stdbool.h>
 
 #define TUNABLE_NAMESPACE MALLOC
+#include <tunables/tunables.h>
 
 /* Compile-time constants.  */
 
@@ -307,53 +308,72 @@ ptmalloc_unlock_all2 (void)
 # endif
 #endif  /* !NO_THREADS */
 
-/* Initialization routine. */
-#include <string.h>
-extern char **_environ;
 
-static char *
-internal_function
-next_env_entry (char ***position)
+#ifdef SHARED
+static void *
+__failing_morecore (ptrdiff_t d)
 {
-  char **current = *position;
-  char *result = NULL;
+  return (void *) MORECORE_FAILURE;
+}
 
-  while (*current != NULL)
-    {
-      if (__builtin_expect ((*current)[0] == 'M', 0)
-          && (*current)[1] == 'A'
-          && (*current)[2] == 'L'
-          && (*current)[3] == 'L'
-          && (*current)[4] == 'O'
-          && (*current)[5] == 'C'
-          && (*current)[6] == '_')
-        {
-          result = &(*current)[7];
+extern struct dl_open_hook *_dl_open_hook;
+libc_hidden_proto (_dl_open_hook);
+#endif
 
-          /* Save current position for next visit.  */
-          *position = ++current;
+static void
+tunable_set_mallopt_top_pad (const char *val)
+{
+  __libc_mallopt (M_TOP_PAD, atoi (val));
+}
 
-          break;
-        }
+static void
+tunable_set_mallopt_perturb (const char *val)
+{
+  __libc_mallopt (M_PERTURB, atoi (val));
+}
 
-      ++current;
-    }
+static void
+tunable_set_mallopt_mmap_max (const char *val)
+{
+  __libc_mallopt (M_MMAP_MAX, atoi (val));
+}
 
-  return result;
+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));
+}
 
-#ifdef SHARED
-static void *
-__failing_morecore (ptrdiff_t d)
+static void
+tunable_set_mallopt_trim_threshold (const char *val)
 {
-  return (void *) MORECORE_FAILURE;
+  __libc_mallopt (M_TRIM_THRESHOLD, atoi (val));
 }
 
-extern struct dl_open_hook *_dl_open_hook;
-libc_hidden_proto (_dl_open_hook);
-#endif
+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 ();
+    }
+}
 
+/* Initialization routine. */
 static void
 ptmalloc_init (void)
 {
@@ -377,74 +397,22 @@ ptmalloc_init (void)
   tsd_key_create (&arena_key, NULL);
   tsd_setspecific (arena_key, (void *) &main_arena);
   thread_atfork (ptmalloc_lock_all, ptmalloc_unlock_all, ptmalloc_unlock_all2);
-  const char *s = NULL;
-  if (__glibc_likely (_environ != NULL))
-    {
-      char **runp = _environ;
-      char *envline;
 
-      while (__builtin_expect ((envline = next_env_entry (&runp)) != NULL,
-                               0))
-        {
-          size_t len = strcspn (envline, "=");
+  TUNABLES_NAMESPACE_BEGIN (8);
 
-          if (envline[len] != '=')
-            /* This is a "MALLOC_" variable at the end of the string
-               without a '=' character.  Ignore it since otherwise we
-               will access invalid memory below.  */
-            continue;
+  TUNABLE_REGISTER_SECURE (CHECK, "MALLOC_CHECK_", tunable_set_mallopt_check);
+  TUNABLE_REGISTER (TOP_PAD, "MALLOC_TOP_PAD_", tunable_set_mallopt_top_pad);
+  TUNABLE_REGISTER (PERTURB, "MALLOC_PERTURB_", tunable_set_mallopt_perturb);
+  TUNABLE_REGISTER (MMAP_THRESHOLD, "MALLOC_MMAP_THRESHOLD_",
+		    tunable_set_mallopt_mmap_threshold);
+  TUNABLE_REGISTER (TRIM_THRESHOLD, "MALLOC_TRIM_THRESHOLD_",
+		    tunable_set_mallopt_trim_threshold);
+  TUNABLE_REGISTER (MMAP_MAX, "MALLOC_MMAP_MAX_", tunable_set_mallopt_mmap_max);
+  TUNABLE_REGISTER (ARENA_MAX, "MALLOC_ARENA_MAX", tunable_set_mallopt_arena_max);
+  TUNABLE_REGISTER (ARENA_TEST, "MALLOC_ARENA_TEST", tunable_set_mallopt_arena_test);
+
+  TUNABLES_NAMESPACE_INIT ();
 
-          switch (len)
-            {
-            case 6:
-              if (memcmp (envline, "CHECK_", 6) == 0)
-                s = &envline[7];
-              break;
-            case 8:
-              if (!__builtin_expect (__libc_enable_secure, 0))
-                {
-                  if (memcmp (envline, "TOP_PAD_", 8) == 0)
-                    __libc_mallopt (M_TOP_PAD, atoi (&envline[9]));
-                  else if (memcmp (envline, "PERTURB_", 8) == 0)
-                    __libc_mallopt (M_PERTURB, atoi (&envline[9]));
-                }
-              break;
-            case 9:
-              if (!__builtin_expect (__libc_enable_secure, 0))
-                {
-                  if (memcmp (envline, "MMAP_MAX_", 9) == 0)
-                    __libc_mallopt (M_MMAP_MAX, atoi (&envline[10]));
-                  else if (memcmp (envline, "ARENA_MAX", 9) == 0)
-                    __libc_mallopt (M_ARENA_MAX, atoi (&envline[10]));
-                }
-              break;
-            case 10:
-              if (!__builtin_expect (__libc_enable_secure, 0))
-                {
-                  if (memcmp (envline, "ARENA_TEST", 10) == 0)
-                    __libc_mallopt (M_ARENA_TEST, atoi (&envline[11]));
-                }
-              break;
-            case 15:
-              if (!__builtin_expect (__libc_enable_secure, 0))
-                {
-                  if (memcmp (envline, "TRIM_THRESHOLD_", 15) == 0)
-                    __libc_mallopt (M_TRIM_THRESHOLD, atoi (&envline[16]));
-                  else if (memcmp (envline, "MMAP_THRESHOLD_", 15) == 0)
-                    __libc_mallopt (M_MMAP_THRESHOLD, atoi (&envline[16]));
-                }
-              break;
-            default:
-              break;
-            }
-        }
-    }
-  if (s && s[0])
-    {
-      __libc_mallopt (M_CHECK_ACTION, (int) (s[0] - '0'));
-      if (check_action != 0)
-        __malloc_check_init ();
-    }
   void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);
   if (hook != NULL)
     (*hook)();
diff --git a/tunables/tunable-list.h b/tunables/tunable-list.h
index e5083d5..0554420 100644
--- a/tunables/tunable-list.h
+++ b/tunables/tunable-list.h
@@ -1,8 +1,12 @@
 typedef enum
 {
   GLIBC_MALLOC,
+  GLIBC_MALLOC_CHECK,
+  GLIBC_MALLOC_TOP_PAD,
+  GLIBC_MALLOC_PERTURB,
   GLIBC_MALLOC_MMAP_THRESHOLD,
   GLIBC_MALLOC_TRIM_THRESHOLD,
+  GLIBC_MALLOC_MMAP_MAX,
   GLIBC_MALLOC_ARENA_MAX,
   GLIBC_MALLOC_ARENA_TEST,
   TUNABLES_MAX
diff --git a/tunables/tunables.c b/tunables/tunables.c
index 2e1157f..f0acd84 100644
--- a/tunables/tunables.c
+++ b/tunables/tunables.c
@@ -33,10 +33,15 @@ struct _tunable
 {
   char *name;
   char *alias;
-  void *val;
-  size_t size;
-  tunable_type_t type;
+  union
+    {
+      int ns_size;
+      tunable_setter_t set;
+    } data;
+#define set data.set
+#define ns_size data.ns_size
   bool initialized;
+  bool enable_secure;
 };
 
 /* The full list of tunables.  */
@@ -46,30 +51,14 @@ static tunable_t tunable_list[TUNABLES_MAX];
 void
 tunables_namespace_begin (tunable_id_t id, size_t size)
 {
-  tunable_list[id].size = size;
-}
-
-/* Set the value of a tunable from its environment variable(s).  */
-static void
-tunable_set (tunable_t *t, const char *val)
-{
-  switch (t->type & ~TUNABLE_TYPE_SECURE)
-    {
-    case TUNABLE_TYPE_SIZE_T:
-      *(size_t *) t->val = strtoul (val, NULL, 0);
-    case TUNABLE_TYPE_STRING:
-      memcpy (t->val, val, t->size);
-    default:
-      __builtin_trap ();
-    }
-  t->initialized = true;
+  tunable_list[id].ns_size = size;
 }
 
 /* Initialize all tunables in the namespace group specified by ID.  */
 void
 tunables_init (tunable_id_t id)
 {
-  int end = tunable_list[id].size;
+  int end = tunable_list[id].ns_size;
 
   /* Traverse through the environment to find environment variables we may need
      to set.  */
@@ -86,17 +75,16 @@ tunables_init (tunable_id_t id)
       if (envline[len] == '\0')
 	continue;
 
-      for (int i = id; i < end; i++)
+      for (int i = id + 1; i < end; i++)
 	{
 	  /* Skip over tunables that are either initialized or are not safe to
 	     load for setuid binaries.  */
-	  if ((__libc_enable_secure
-	       && (tunable_list[id].type & TUNABLE_TYPE_SECURE) == 0)
-	      || tunable_list[id].initialized)
+	  if ((__libc_enable_secure && !tunable_list[i].enable_secure)
+	      || tunable_list[i].initialized)
 	    continue;
 
-	  const char *name = tunable_list[id].name;
-	  const char *alias = tunable_list[id].alias;
+	  const char *name = tunable_list[i].name;
+	  const char *alias = tunable_list[i].alias;
 	  char *val = NULL;
 
 	  if (memcmp (envline, name, MIN(len, strlen (name))) == 0)
@@ -106,7 +94,8 @@ tunables_init (tunable_id_t id)
 
 	  if (val != NULL)
 	    {
-	      tunable_set (&tunable_list[id], val);
+	      tunable_list[i].set (val);
+	      tunable_list[i].initialized = true;
 	      break;
 	    }
 	}
@@ -117,11 +106,10 @@ tunables_init (tunable_id_t id)
 /* Initialize a tunable and set its value via the set environment variable.  */
 void
 tunable_register (tunable_id_t id, const char *name, const char *alias,
-		void *val, size_t size, tunable_type_t type)
+		  tunable_setter_t set_func, bool secure)
 {
   tunable_list[id].name = __strdup (name);
   tunable_list[id].alias = alias ? __strdup (alias) : NULL;
-  tunable_list[id].val = val;
-  tunable_list[id].size = size;
-  tunable_list[id].type = type;
+  tunable_list[id].set = set_func;
+  tunable_list[id].enable_secure = secure;
 }
diff --git a/tunables/tunables.h b/tunables/tunables.h
index 448c5d0..4143dc5 100644
--- a/tunables/tunables.h
+++ b/tunables/tunables.h
@@ -20,36 +20,51 @@
 
 #include "tunable-list.h"
 
-typedef enum
-{
-  TUNABLE_TYPE_SECURE,
-  TUNABLE_TYPE_SIZE_T = 1 << 1,
-  TUNABLE_TYPE_STRING = 1 << 2
-} tunable_type_t;
-
+typedef void (*tunable_setter_t) (const char *);
 typedef struct _tunable tunable_t;
 
+extern void tunables_namespace_begin (tunable_id_t, size_t);
+extern void tunable_register (tunable_id_t, const char *, const char *,
+			      tunable_setter_t, bool);
+extern void tunables_init (tunable_id_t);
+
 /* Build a full tunable name from a top namespace, tunable namespace and the
    id.  */
-#define FULL_NAME(top,ns,id) (top ## _ ## ns ## _ ## id)
+#define FULL_NAME(top,ns,id) FULL_NAME1 (top,ns,id)
+#define FULL_NAME1(top,ns,id) (top ## _ ## ns ## _ ## id)
+
 #define FULL_NAME_S(top,ns,id) (#top "_" #ns "_" #id)
 
+#define NS_NAME(top, ns) NS_NAME1(top, ns)
+#define NS_NAME1(top, ns) (top ## _ ## ns)
+
 /* Start registering tunables in the current namespace.  */
 #define TUNABLES_NAMESPACE_BEGIN(size) \
-  tunables_namespace_begin (TUNABLE_NAMESPACE, size)
+  tunables_namespace_begin (NS_NAME(TOP_NAMESPACE, TUNABLE_NAMESPACE), size)
 
 /* 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 TUNABLE_REGISTER(id,alias,val,size,type) \
+#define TUNABLE_REGISTER(id,alias,set) \
+({									      \
+  tunable_register (FULL_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, id),	      \
+		    FULL_NAME_S (TOP_NAMESPACE, TUNABLE_NAMESPACE, id),	      \
+		    (alias), (set), false);				      \
+									      \
+})
+
+/* 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 TUNABLE_REGISTER_SECURE(id,alias,set) \
 ({									      \
-  static_assert (FULL_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, id)	      \
-		 < TUNABLES_MAX);					      \
   tunable_register (FULL_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, id),	      \
 		    FULL_NAME_S (TOP_NAMESPACE, TUNABLE_NAMESPACE, id),	      \
-		    (alias), (val), (size), (type));			      \
+		    (alias), (set), true);				      \
 									      \
 })
 
+/* Initialize tunables in the namespace.  */
 #define TUNABLES_NAMESPACE_INIT() \
-  tunables_init (TUNABLE_NAMESPACE, size)
+  tunables_init (NS_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE))
diff --git a/tunables/tunables.list b/tunables/tunables.list
index 3ef02c6..4ab93e4 100644
--- a/tunables/tunables.list
+++ b/tunables/tunables.list
@@ -1,7 +1,11 @@
 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=ca101a22f8ad3d81f7ecb2d25f99caee8193296f

commit ca101a22f8ad3d81f7ecb2d25f99caee8193296f
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Fri May 15 16:31:05 2015 +0530

    Generate tunable IDs from a list file

diff --git a/scripts/gen-tunables.awk b/scripts/gen-tunables.awk
new file mode 100644
index 0000000..eefe518
--- /dev/null
+++ b/scripts/gen-tunables.awk
@@ -0,0 +1,64 @@
+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 "typedef enum"
+  print "{"
+  for (t in val) {
+    for (n in val[t]) {
+      printf ("  %s_%s,\n", t, n);
+      for (c in val[t][n]) {
+        printf ("  %s_%s_%s,\n", t, n, val[t][n][c]);
+      }
+    }
+  }
+  print "  TUNABLES_MAX"
+  print "} tunable_id_t;"
+}
diff --git a/tunables/Makefile b/tunables/Makefile
index cf73f26..ebc43de 100644
--- a/tunables/Makefile
+++ b/tunables/Makefile
@@ -24,4 +24,10 @@ 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
index 37da2e6..48c6260 100644
--- a/tunables/README
+++ b/tunables/README
@@ -14,9 +14,16 @@ 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 intend to push upstream.
 
+There are two steps to adding tunables:
+
+1. Add tunable IDs:
+
+TODO: finish this.
+
 Modules that wish to use the tunables interface must define the
-TUNABLE_NAMESPACE macro.  A tunable may then be added by adding the full ID of
-the tunable to the tunable_id_t enum and then calling the TUNABLE_REGISTER
+TUNABLE_NAMESPACE macro.  To begin registering tunables, call the
+TUNABLE_NAMESPACE_BEGIN() macro.  Tunables may be added by adding the full ID
+of the tunable to the tunable_id_t enum and then calling the TUNABLE_REGISTER
 macro when it wants to read the environment variables to initialize the
 variable that is to be tuned.
 
@@ -36,7 +43,9 @@ The TUNABLE_REGISTER macro takes the following arguments:
 - size:		Size of the tunable variable.
 
 - type:		Type of the tunable variable.  It must be one of the values
-		defined in the tunable_type_t enum.
+		defined in the tunable_type_t enum.  If a value is safe to load
+		for setuid binaries, the type should be the OR of the actual
+		type and TUNABLE_TYPE_SECURE.
 
 Future work:
 ------------
diff --git a/tunables/tunable-list.h b/tunables/tunable-list.h
new file mode 100644
index 0000000..e5083d5
--- /dev/null
+++ b/tunables/tunable-list.h
@@ -0,0 +1,9 @@
+typedef enum
+{
+  GLIBC_MALLOC,
+  GLIBC_MALLOC_MMAP_THRESHOLD,
+  GLIBC_MALLOC_TRIM_THRESHOLD,
+  GLIBC_MALLOC_ARENA_MAX,
+  GLIBC_MALLOC_ARENA_TEST,
+  TUNABLES_MAX
+} tunable_id_t;
diff --git a/tunables/tunables.h b/tunables/tunables.h
index 5e1120d..448c5d0 100644
--- a/tunables/tunables.h
+++ b/tunables/tunables.h
@@ -18,6 +18,8 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include "tunable-list.h"
+
 typedef enum
 {
   TUNABLE_TYPE_SECURE,
@@ -27,28 +29,25 @@ typedef enum
 
 typedef struct _tunable tunable_t;
 
-/* Add your tunable IDs here.  */
-typedef enum
-{
-  TUNABLES_MAX
-} tunable_id_t;
-
+/* Build a full tunable name from a top namespace, tunable namespace and the
+   id.  */
 #define FULL_NAME(top,ns,id) (top ## _ ## ns ## _ ## id)
 #define FULL_NAME_S(top,ns,id) (#top "_" #ns "_" #id)
 
+/* Start registering tunables in the current namespace.  */
 #define TUNABLES_NAMESPACE_BEGIN(size) \
   tunables_namespace_begin (TUNABLE_NAMESPACE, size)
 
 /* 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 TUNABLE_REGISTER(id,alias,val,size,type,secure) \
+#define TUNABLE_REGISTER(id,alias,val,size,type) \
 ({									      \
   static_assert (FULL_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, id)	      \
 		 < TUNABLES_MAX);					      \
-  tunable_init (FULL_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, id),	      \
-		FULL_NAME_S (TOP_NAMESPACE, TUNABLE_NAMESPACE, id),	      \
-		(alias), (val), (size), (type), (secure));		      \
+  tunable_register (FULL_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, id),	      \
+		    FULL_NAME_S (TOP_NAMESPACE, TUNABLE_NAMESPACE, id),	      \
+		    (alias), (val), (size), (type));			      \
 									      \
 })
 
diff --git a/tunables/tunables.list b/tunables/tunables.list
new file mode 100644
index 0000000..3ef02c6
--- /dev/null
+++ b/tunables/tunables.list
@@ -0,0 +1,8 @@
+GLIBC {
+  MALLOC {
+    MMAP_THRESHOLD
+    TRIM_THRESHOLD
+    ARENA_MAX
+    ARENA_TEST
+  }
+}

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

commit ac2c885a57fa7a50251aa38400a0f186e39f9bf6
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Fri May 15 13:16:52 2015 +0530

    malloc tunables support

diff --git a/malloc/arena.c b/malloc/arena.c
index 21ecc5a..5448b0a 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -19,6 +19,8 @@
 
 #include <stdbool.h>
 
+#define TUNABLE_NAMESPACE MALLOC
+
 /* Compile-time constants.  */
 
 #define HEAP_MIN_SIZE (32 * 1024)

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

commit eb89f3552a7629e0218c4082f0afaeb2fc8eddaa
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Fri May 15 13:16:24 2015 +0530

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

diff --git a/Makeconfig b/Makeconfig
index f136b88..cf3da30 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -883,7 +883,8 @@ CPPFLAGS = $(config-extra-cppflags) $(CPPUNDEFS) $(CPPFLAGS-config) \
 	   $(CPPFLAGS-$(suffix $@)) \
 	   $(foreach lib,$(libof-$(basename $(@F))) \
 			 $(libof-$(<F)) $(libof-$(@F)),$(CPPFLAGS-$(lib))) \
-	   $(CPPFLAGS-$(<F)) $(CPPFLAGS-$(@F)) $(CPPFLAGS-$(basename $(@F)))
+	   $(CPPFLAGS-$(<F)) $(CPPFLAGS-$(@F)) $(CPPFLAGS-$(basename $(@F))) \
+	   -DTOP_NAMESPACE=GLIBC
 override CFLAGS	= -std=gnu99 $(gnu89-inline-CFLAGS) $(config-extra-cflags) \
 		  $(filter-out %frame-pointer,$(+cflags)) $(+gccwarn-c) \
 		  $(sysdep-CFLAGS) $(CFLAGS-$(suffix $@)) $(CFLAGS-$(<F)) \
@@ -1097,7 +1098,7 @@ all-subdirs = csu assert ctype locale intl catgets math setjmp signal	    \
 	      grp pwd posix io termios resource misc socket sysvipc gmon    \
 	      gnulib iconv iconvdata wctype manual shadow gshadow po argp   \
 	      crypt localedata timezone rt conform debug mathvec	    \
-	      $(add-on-subdirs) dlfcn elf
+	      $(add-on-subdirs) dlfcn elf tunables
 
 ifndef avoid-generated
 # sysd-sorted itself will contain rules making the sysd-sorted target
diff --git a/tunables/Makefile b/tunables/Makefile
new file mode 100644
index 0000000..cf73f26
--- /dev/null
+++ b/tunables/Makefile
@@ -0,0 +1,27 @@
+# Copyright (C) 2015 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
+
+include ../Rules
diff --git a/tunables/README b/tunables/README
new file mode 100644
index 0000000..37da2e6
--- /dev/null
+++ b/tunables/README
@@ -0,0 +1,48 @@
+			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 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 intend to push upstream.
+
+Modules that wish to use the tunables interface must define the
+TUNABLE_NAMESPACE macro.  A tunable may then be added by adding the full ID of
+the tunable to the tunable_id_t enum and then calling the TUNABLE_REGISTER
+macro when it wants to read the environment variables to initialize the
+variable that is to be tuned.
+
+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.  It must match the tunable ID added to the
+		tunable_id_t enum.
+
+- alias:	The old name of the tunable.  This is for compatibility, to
+		support porting of already existing environment variables into
+		the tunables framework.
+
+- val:		A pointer to the variable that is to be tuned.
+
+- size:		Size of the tunable variable.
+
+- type:		Type of the tunable variable.  It must be one of the values
+		defined in the tunable_type_t enum.
+
+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..b47493f
--- /dev/null
+++ b/tunables/Versions
@@ -0,0 +1,6 @@
+# Exports from tunables should only be in the GLIBC_PRIVATE namespace.
+libc {
+  GLIBC_PRIVATE {
+    tunable_init;
+  }
+}
diff --git a/tunables/tunables.c b/tunables/tunables.c
new file mode 100644
index 0000000..2e1157f
--- /dev/null
+++ b/tunables/tunables.c
@@ -0,0 +1,127 @@
+/* The tunable framework.  See the README to know how to use the tunable in
+   a glibc module.
+
+   Copyright (C) 2015 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>
+#include "tunables.h"
+
+extern char **__environ;
+
+/* A tunable.  */
+struct _tunable
+{
+  char *name;
+  char *alias;
+  void *val;
+  size_t size;
+  tunable_type_t type;
+  bool initialized;
+};
+
+/* The full list of tunables.  */
+static tunable_t tunable_list[TUNABLES_MAX];
+
+
+void
+tunables_namespace_begin (tunable_id_t id, size_t size)
+{
+  tunable_list[id].size = size;
+}
+
+/* Set the value of a tunable from its environment variable(s).  */
+static void
+tunable_set (tunable_t *t, const char *val)
+{
+  switch (t->type & ~TUNABLE_TYPE_SECURE)
+    {
+    case TUNABLE_TYPE_SIZE_T:
+      *(size_t *) t->val = strtoul (val, NULL, 0);
+    case TUNABLE_TYPE_STRING:
+      memcpy (t->val, val, t->size);
+    default:
+      __builtin_trap ();
+    }
+  t->initialized = true;
+}
+
+/* Initialize all tunables in the namespace group specified by ID.  */
+void
+tunables_init (tunable_id_t id)
+{
+  int end = tunable_list[id].size;
+
+  /* Traverse through the environment to find environment variables we may need
+     to set.  */
+  char **envp = __environ;
+  while (*envp != NULL)
+    {
+      char *envline = *envp;
+      int len = 0;
+
+      while (envline[len] != '\0' && envline[len] != '=')
+	len++;
+
+      /* Just the name and no value.  */
+      if (envline[len] == '\0')
+	continue;
+
+      for (int i = id; i < end; i++)
+	{
+	  /* Skip over tunables that are either initialized or are not safe to
+	     load for setuid binaries.  */
+	  if ((__libc_enable_secure
+	       && (tunable_list[id].type & TUNABLE_TYPE_SECURE) == 0)
+	      || tunable_list[id].initialized)
+	    continue;
+
+	  const char *name = tunable_list[id].name;
+	  const char *alias = tunable_list[id].alias;
+	  char *val = NULL;
+
+	  if (memcmp (envline, name, MIN(len, strlen (name))) == 0)
+	    val = &envline[len + 1];
+	  else if (memcmp (envline, alias, MIN(len, strlen (alias))) == 0)
+	    val = &envline[len + 1];
+
+	  if (val != NULL)
+	    {
+	      tunable_set (&tunable_list[id], val);
+	      break;
+	    }
+	}
+      envp++;
+    }
+}
+
+/* Initialize a tunable and set its value via the set environment variable.  */
+void
+tunable_register (tunable_id_t id, const char *name, const char *alias,
+		void *val, size_t size, tunable_type_t type)
+{
+  tunable_list[id].name = __strdup (name);
+  tunable_list[id].alias = alias ? __strdup (alias) : NULL;
+  tunable_list[id].val = val;
+  tunable_list[id].size = size;
+  tunable_list[id].type = type;
+}
diff --git a/tunables/tunables.h b/tunables/tunables.h
new file mode 100644
index 0000000..5e1120d
--- /dev/null
+++ b/tunables/tunables.h
@@ -0,0 +1,56 @@
+/* The tunable framework.  See the README to know how to use the tunable in
+   a glibc module.
+
+   Copyright (C) 2015 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/>.  */
+
+typedef enum
+{
+  TUNABLE_TYPE_SECURE,
+  TUNABLE_TYPE_SIZE_T = 1 << 1,
+  TUNABLE_TYPE_STRING = 1 << 2
+} tunable_type_t;
+
+typedef struct _tunable tunable_t;
+
+/* Add your tunable IDs here.  */
+typedef enum
+{
+  TUNABLES_MAX
+} tunable_id_t;
+
+#define FULL_NAME(top,ns,id) (top ## _ ## ns ## _ ## id)
+#define FULL_NAME_S(top,ns,id) (#top "_" #ns "_" #id)
+
+#define TUNABLES_NAMESPACE_BEGIN(size) \
+  tunables_namespace_begin (TUNABLE_NAMESPACE, size)
+
+/* 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 TUNABLE_REGISTER(id,alias,val,size,type,secure) \
+({									      \
+  static_assert (FULL_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, id)	      \
+		 < TUNABLES_MAX);					      \
+  tunable_init (FULL_NAME (TOP_NAMESPACE, TUNABLE_NAMESPACE, id),	      \
+		FULL_NAME_S (TOP_NAMESPACE, TUNABLE_NAMESPACE, id),	      \
+		(alias), (val), (size), (type), (secure));		      \
+									      \
+})
+
+#define TUNABLES_NAMESPACE_INIT() \
+  tunables_init (TUNABLE_NAMESPACE, size)

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


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]