[PATCHv2 2/2] Initialize tunable list with the GLIBC_TUNABLES environment variable

Siddhesh Poyarekar sid@reserved-bit.com
Sat Jan 16 18:56:00 GMT 2016


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.
---
 tunables/tunables.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 101 insertions(+), 1 deletion(-)

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)
 
-- 
2.5.0



More information about the Libc-alpha mailing list