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.
This commit is contained in:
Siddhesh Poyarekar 2017-05-17 13:11:55 +05:30
parent d13103074a
commit ad2f35cb39
4 changed files with 55 additions and 55 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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;