about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSiddhesh Poyarekar <siddhesh@sourceware.org>2017-05-17 13:11:55 +0530
committerSiddhesh Poyarekar <siddhesh@sourceware.org>2017-05-17 13:11:55 +0530
commitad2f35cb396d24391150675fb55311c98d1e1592 (patch)
treebc4daee1bc3f9609bebbd29c8ecf53d46f5e8ab7
parentd13103074ab5c7614eeb94f88a61803ed8f3e878 (diff)
downloadglibc-ad2f35cb396d24391150675fb55311c98d1e1592.tar.gz
glibc-ad2f35cb396d24391150675fb55311c98d1e1592.tar.xz
glibc-ad2f35cb396d24391150675fb55311c98d1e1592.zip
tunables: Add support for tunables of uint64_t type
Recognize the uint64_t type in addition to the current int32_t and
size_t.  This allows addition of tunables of uint64_t types.  In
addition to adding the uint64_t type, this patch also consolidates
validation and reading of integer types in tunables.

One notable change is that of overflow computation in
tunables_strtoul.  The function was lifted from __internal_strtoul,
but it does not need the boundary condition check (i.e. result ==
ULONG_MAX) since it does not need to set errno.  As a result the check
can be simplified, which I have now done.

	* elf/dl-tunable-types.h (tunable_type_code_t): New type
	TUNABLE_TYPE_UINT_64.
	* elf/dl-tunables.c (tunables_strtoul): Return uint64_t.
	Simplify computation of overflow.
	(tunable_set_val_if_valid_range_signed,
	tunable_set_val_if_valid_range_unsigned): Remove and replace
	with this...
	(TUNABLE_SET_VAL_IF_VALID_RANGE): ... New macro.
	(tunable_initialize): Adjust.  Add uint64_t support.
	(__tunable_set_val): Add uint64_t support.
	* README.tunables: Document it.
-rw-r--r--ChangeLog12
-rw-r--r--README.tunables3
-rw-r--r--elf/dl-tunable-types.h1
-rw-r--r--elf/dl-tunables.c94
4 files changed, 55 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index a4a88e530c..2570bf4afb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2017-05-17  Siddhesh Poyarekar  <siddhesh@sourceware.org>
 
+	* elf/dl-tunable-types.h (tunable_type_code_t): New type
+	TUNABLE_TYPE_UINT_64.
+	* elf/dl-tunables.c (tunables_strtoul): Return uint64_t.
+	Simplify computation of overflow.
+	(tunable_set_val_if_valid_range_signed,
+	tunable_set_val_if_valid_range_unsigned): Remove and replace
+	with this...
+	(TUNABLE_SET_VAL_IF_VALID_RANGE): ... New macro.
+	(tunable_initialize): Adjust.  Add uint64_t support.
+	(__tunable_set_val): Add uint64_t support.
+	* README.tunables: Document it.
+
 	* scripts/gen-tunables.awk: Recognize 'default' keyword in
 	dl-tunables.list.
 	* README.tunables: Document it.
diff --git a/README.tunables b/README.tunables
index 3f16b5d827..0e9b0d7a47 100644
--- a/README.tunables
+++ b/README.tunables
@@ -48,7 +48,8 @@ TOP_NAMESPACE {
 The list of allowed attributes are:
 
 - type:			Data type.  Defaults to STRING.  Allowed types are:
-			INT_32, SIZE_T and STRING.
+			INT_32, UINT_64, SIZE_T and STRING.  Numeric types may
+			be in octal or hexadecimal format too.
 
 - minval:		Optional minimum acceptable value.  For a string type
 			this is the minimum length of the value.
diff --git a/elf/dl-tunable-types.h b/elf/dl-tunable-types.h
index 37a4e8021f..1d516df08f 100644
--- a/elf/dl-tunable-types.h
+++ b/elf/dl-tunable-types.h
@@ -24,6 +24,7 @@
 typedef enum
 {
   TUNABLE_TYPE_INT_32,
+  TUNABLE_TYPE_UINT_64,
   TUNABLE_TYPE_SIZE_T,
   TUNABLE_TYPE_STRING
 } tunable_type_code_t;
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
index ebf48bb389..8d72e268ef 100644
--- a/elf/dl-tunables.c
+++ b/elf/dl-tunables.c
@@ -105,10 +105,10 @@ get_next_env (char **envp, char **name, size_t *namelen, char **val,
 /* A stripped down strtoul-like implementation for very early use.  It does not
    set errno if the result is outside bounds because it gets called before
    errno may have been set up.  */
-static unsigned long int
+static uint64_t
 tunables_strtoul (const char *nptr)
 {
-  unsigned long int result = 0;
+  uint64_t result = 0;
   long int sign = 1;
   unsigned max_digit;
 
@@ -144,7 +144,7 @@ tunables_strtoul (const char *nptr)
 
   while (1)
     {
-      unsigned long int digval;
+      int digval;
       if (*nptr >= '0' && *nptr <= '0' + max_digit)
         digval = *nptr - '0';
       else if (base == 16)
@@ -159,9 +159,8 @@ tunables_strtoul (const char *nptr)
       else
         break;
 
-      if (result > ULONG_MAX / base
-	  || (result == ULONG_MAX / base && digval > ULONG_MAX % base))
-	return ULONG_MAX;
+      if (result >= (UINT64_MAX - digval) / base)
+	return UINT64_MAX;
       result *= base;
       result += digval;
       ++nptr;
@@ -170,68 +169,50 @@ tunables_strtoul (const char *nptr)
   return result * sign;
 }
 
-/* Initialize the internal type if the value validates either using the
-   explicit constraints of the tunable or with the implicit constraints of its
-   type.  */
-static void
-tunable_set_val_if_valid_range_signed (tunable_t *cur, const char *strval,
-				int64_t default_min, int64_t default_max)
-{
-  int64_t val = (int64_t) tunables_strtoul (strval);
-
-  int64_t min = cur->type.min;
-  int64_t max = cur->type.max;
-
-  if (min == max)
-    {
-      min = default_min;
-      max = default_max;
-    }
-
-  if (val >= min && val <= max)
-    {
-      cur->val.numval = val;
-      cur->strval = strval;
-    }
-}
-
-static void
-tunable_set_val_if_valid_range_unsigned (tunable_t *cur, const char *strval,
-					 uint64_t default_min, uint64_t default_max)
-{
-  uint64_t val = (uint64_t) tunables_strtoul (strval);
-
-  uint64_t min = cur->type.min;
-  uint64_t max = cur->type.max;
-
-  if (min == max)
-    {
-      min = default_min;
-      max = default_max;
-    }
-
-  if (val >= min && val <= max)
-    {
-      cur->val.numval = val;
-      cur->strval = strval;
-    }
-}
+#define TUNABLE_SET_VAL_IF_VALID_RANGE(__cur, __val, __type, __default_min, \
+				       __default_max)			      \
+({									      \
+  __type min = (__cur)->type.min;					      \
+  __type max = (__cur)->type.max;					      \
+									      \
+  if (min == max)							      \
+    {									      \
+      min = __default_min;						      \
+      max = __default_max;						      \
+    }									      \
+									      \
+  if ((__type) (__val) >= min && (__type) (val) <= max)			      \
+    {									      \
+      (__cur)->val.numval = val;					      \
+      (__cur)->strval = strval;						      \
+    }									      \
+})
 
 /* Validate range of the input value and initialize the tunable CUR if it looks
    good.  */
 static void
 tunable_initialize (tunable_t *cur, const char *strval)
 {
+  uint64_t val;
+
+  if (cur->type.type_code != TUNABLE_TYPE_STRING)
+    val = tunables_strtoul (strval);
+
   switch (cur->type.type_code)
     {
     case TUNABLE_TYPE_INT_32:
 	{
-	  tunable_set_val_if_valid_range_signed (cur, strval, INT32_MIN, INT32_MAX);
+	  TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, int64_t, INT32_MIN, INT32_MAX);
+	  break;
+	}
+    case TUNABLE_TYPE_UINT_64:
+	{
+	  TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t, 0, UINT64_MAX);
 	  break;
 	}
     case TUNABLE_TYPE_SIZE_T:
 	{
-	  tunable_set_val_if_valid_range_unsigned (cur, strval, 0, SIZE_MAX);
+	  TUNABLE_SET_VAL_IF_VALID_RANGE (cur, val, uint64_t, 0, SIZE_MAX);
 	  break;
 	}
     case TUNABLE_TYPE_STRING:
@@ -461,6 +442,11 @@ __tunable_set_val (tunable_id_t id, void *valp, tunable_callback_t callback)
 
   switch (cur->type.type_code)
     {
+    case TUNABLE_TYPE_UINT_64:
+	{
+	  *((uint64_t *) valp) = (uint64_t) cur->val.numval;
+	  break;
+	}
     case TUNABLE_TYPE_INT_32:
 	{
 	  *((int32_t *) valp) = (int32_t) cur->val.numval;