Add sudo_gettime_uptime() to measure time while not sleeping.

This commit is contained in:
Todd C. Miller
2018-08-19 09:55:08 -06:00
parent e74d7e8721
commit b3227d3ed5
7 changed files with 245 additions and 37 deletions

114
aclocal.m4 vendored
View File

@@ -12,6 +12,120 @@
# PARTICULAR PURPOSE.
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
# longlong.m4 serial 17
dnl Copyright (C) 1999-2007, 2009-2016 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl From Paul Eggert.
# Define HAVE_LONG_LONG_INT if 'long long int' works.
# This fixes a bug in Autoconf 2.61, and can be faster
# than what's in Autoconf 2.62 through 2.68.
# Note: If the type 'long long int' exists but is only 32 bits large
# (as on some very old compilers), HAVE_LONG_LONG_INT will not be
# defined. In this case you can treat 'long long int' like 'long int'.
AC_DEFUN([AC_TYPE_LONG_LONG_INT],
[
AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT])
AC_CACHE_CHECK([for long long int], [ac_cv_type_long_long_int],
[ac_cv_type_long_long_int=yes
if test "x${ac_cv_prog_cc_c99-no}" = xno; then
ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
if test $ac_cv_type_long_long_int = yes; then
dnl Catch a bug in Tandem NonStop Kernel (OSS) cc -O circa 2004.
dnl If cross compiling, assume the bug is not important, since
dnl nobody cross compiles for this platform as far as we know.
AC_RUN_IFELSE(
[AC_LANG_PROGRAM(
[[@%:@include <limits.h>
@%:@ifndef LLONG_MAX
@%:@ define HALF \
(1LL << (sizeof (long long int) * CHAR_BIT - 2))
@%:@ define LLONG_MAX (HALF - 1 + HALF)
@%:@endif]],
[[long long int n = 1;
int i;
for (i = 0; ; i++)
{
long long int m = n << i;
if (m >> i != n)
return 1;
if (LLONG_MAX / 2 < m)
break;
}
return 0;]])],
[],
[ac_cv_type_long_long_int=no],
[:])
fi
fi])
if test $ac_cv_type_long_long_int = yes; then
AC_DEFINE([HAVE_LONG_LONG_INT], [1],
[Define to 1 if the system has the type 'long long int'.])
fi
])
# Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works.
# This fixes a bug in Autoconf 2.61, and can be faster
# than what's in Autoconf 2.62 through 2.68.
# Note: If the type 'unsigned long long int' exists but is only 32 bits
# large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT
# will not be defined. In this case you can treat 'unsigned long long int'
# like 'unsigned long int'.
AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT],
[
AC_CACHE_CHECK([for unsigned long long int],
[ac_cv_type_unsigned_long_long_int],
[ac_cv_type_unsigned_long_long_int=yes
if test "x${ac_cv_prog_cc_c99-no}" = xno; then
AC_LINK_IFELSE(
[_AC_TYPE_LONG_LONG_SNIPPET],
[],
[ac_cv_type_unsigned_long_long_int=no])
fi])
if test $ac_cv_type_unsigned_long_long_int = yes; then
AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], [1],
[Define to 1 if the system has the type 'unsigned long long int'.])
fi
])
# Expands to a C program that can be used to test for simultaneous support
# of 'long long' and 'unsigned long long'. We don't want to say that
# 'long long' is available if 'unsigned long long' is not, or vice versa,
# because too many programs rely on the symmetry between signed and unsigned
# integer types (excluding 'bool').
AC_DEFUN([_AC_TYPE_LONG_LONG_SNIPPET],
[
AC_LANG_PROGRAM(
[[/* For now, do not test the preprocessor; as of 2007 there are too many
implementations with broken preprocessors. Perhaps this can
be revisited in 2012. In the meantime, code should not expect
#if to work with literals wider than 32 bits. */
/* Test literals. */
long long int ll = 9223372036854775807ll;
long long int nll = -9223372036854775807LL;
unsigned long long int ull = 18446744073709551615ULL;
/* Test constant expressions. */
typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
? 1 : -1)];
typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
? 1 : -1)];
int i = 63;]],
[[/* Test availability of runtime routines for shift and division. */
long long int llmax = 9223372036854775807ll;
unsigned long long int ullmax = 18446744073709551615ull;
return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
| (llmax / ll) | (llmax % ll)
| (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
| (ullmax / ull) | (ullmax % ull));]])
])
m4_include([m4/ax_append_flag.m4])
m4_include([m4/ax_check_compile_flag.m4])
m4_include([m4/ax_check_link_flag.m4])

View File

@@ -470,7 +470,7 @@
/* Define to 1 if you have the <login_cap.h> header file. */
#undef HAVE_LOGIN_CAP_H
/* Define to 1 if the system has the type `long long int'. */
/* Define to 1 if the system has the type 'long long int'. */
#undef HAVE_LONG_LONG_INT
/* Define to 1 if you have the `lrand48' function. */
@@ -479,6 +479,9 @@
/* Define to 1 if you have the <machine/endian.h> header file. */
#undef HAVE_MACHINE_ENDIAN_H
/* Define to 1 if you have the `mach_continuous_time' function. */
#undef HAVE_MACH_CONTINUOUS_TIME
/* Define to 1 if you have the <maillock.h> header file. */
#undef HAVE_MAILLOCK_H
@@ -860,7 +863,7 @@
/* Define to 1 if you have the `unsetenv' function. */
#undef HAVE_UNSETENV
/* Define to 1 if the system has the type `unsigned long long int'. */
/* Define to 1 if the system has the type 'unsigned long long int'. */
#undef HAVE_UNSIGNED_LONG_LONG_INT
/* Define to 1 if you have the <util.h> header file. */

13
configure vendored
View File

@@ -16279,6 +16279,19 @@ done
fi
RTLD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES"
# Mach monotonic timer that runs while sleeping
for ac_func in mach_continuous_time
do :
ac_fn_c_check_func "$LINENO" "mach_continuous_time" "ac_cv_func_mach_continuous_time"
if test "x$ac_cv_func_mach_continuous_time" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_MACH_CONTINUOUS_TIME 1
_ACEOF
fi
done
# Undocumented API that dynamically allocates the groups.
for ac_func in getgrouplist_2
do :

View File

@@ -2215,6 +2215,9 @@ case "$host" in
fi
RTLD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES"
# Mach monotonic timer that runs while sleeping
AC_CHECK_FUNCS([mach_continuous_time])
# Undocumented API that dynamically allocates the groups.
AC_CHECK_FUNCS([getgrouplist_2], [AC_CHECK_DECLS([getgrouplist_2])])

View File

@@ -170,6 +170,8 @@ __dso_public char *sudo_gethostname_v1(void);
#define sudo_gethostname() sudo_gethostname_v1()
/* gettime.c */
__dso_public int sudo_gettime_awake_v1(struct timespec *ts);
#define sudo_gettime_awake(_a) sudo_gettime_awake_v1((_a))
__dso_public int sudo_gettime_mono_v1(struct timespec *ts);
#define sudo_gettime_mono(_a) sudo_gettime_mono_v1((_a))
__dso_public int sudo_gettime_real_v1(struct timespec *ts);

View File

@@ -34,13 +34,25 @@
#include "sudo_debug.h"
#include "sudo_util.h"
/* On Linux, CLOCK_MONOTONIC does not run while suspended. */
/*
* On Linux and FreeBSD, CLOCK_MONOTONIC does not run while sleeping.
* Linux provides CLOCK_BOOTTIME which runs while sleeping (FreeBSD does not).
* Some systems provide CLOCK_UPTIME which only runs while awake.
*/
#if defined(CLOCK_BOOTTIME)
# define SUDO_CLOCK_MONOTONIC CLOCK_BOOTTIME
# define SUDO_CLOCK_BOOTTIME CLOCK_BOOTTIME
#elif defined(CLOCK_MONOTONIC)
# define SUDO_CLOCK_MONOTONIC CLOCK_MONOTONIC
# define SUDO_CLOCK_BOOTTIME CLOCK_MONOTONIC
#endif
#if defined(CLOCK_UPTIME)
# define SUDO_CLOCK_AWAKE CLOCK_UPTIME
#elif defined(CLOCK_MONOTONIC)
# define SUDO_CLOCK_AWAKE CLOCK_MONOTONIC
#endif
/*
* Wall clock time, may run backward.
*/
#if defined(HAVE_CLOCK_GETTIME)
int
sudo_gettime_real_v1(struct timespec *ts)
@@ -72,24 +84,28 @@ sudo_gettime_real_v1(struct timespec *ts)
}
#endif
#if defined(HAVE_CLOCK_GETTIME) && defined(SUDO_CLOCK_MONOTONIC)
/*
* Monotonic time, only runs forward.
* We use a timer that only increments while sleeping, if possible.
*/
#if defined(HAVE_CLOCK_GETTIME) && defined(SUDO_CLOCK_BOOTTIME)
int
sudo_gettime_mono_v1(struct timespec *ts)
{
static int has_monoclock = -1;
debug_decl(sudo_gettime_mono, SUDO_DEBUG_UTIL)
/* Check whether the kernel/libc actually supports CLOCK_MONOTONIC. */
/* Check whether the kernel/libc actually supports a monotonic clock. */
# ifdef _SC_MONOTONIC_CLOCK
if (has_monoclock == -1)
has_monoclock = sysconf(_SC_MONOTONIC_CLOCK) != -1;
# endif
if (!has_monoclock)
debug_return_int(sudo_gettime_real(ts));
if (clock_gettime(SUDO_CLOCK_MONOTONIC, ts) == -1) {
if (clock_gettime(SUDO_CLOCK_BOOTTIME, ts) == -1) {
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
"clock_gettime(%d) failed, using wall clock",
(int)SUDO_CLOCK_MONOTONIC);
(int)SUDO_CLOCK_BOOTTIME);
has_monoclock = 0;
debug_return_int(sudo_gettime_real(ts));
}
@@ -105,7 +121,11 @@ sudo_gettime_mono_v1(struct timespec *ts)
if (timebase_info.denom == 0)
(void) mach_timebase_info(&timebase_info);
abstime = mach_absolute_time();
#ifdef HAVE_MACH_CONTINUOUS_TIME
abstime = mach_continuous_time(); /* runs while asleep */
#else
abstime = mach_absolute_time(); /* doesn't run while asleep */
#endif
nsec = abstime * timebase_info.numer / timebase_info.denom;
ts->tv_sec = nsec / 1000000000;
ts->tv_nsec = nsec % 1000000000;
@@ -119,3 +139,55 @@ sudo_gettime_mono_v1(struct timespec *ts)
return sudo_gettime_real(ts);
}
#endif
/*
* Monotonic time, only runs forward.
* We use a timer that only increments while awake, if possible.
*/
#if defined(HAVE_CLOCK_GETTIME) && defined(SUDO_CLOCK_AWAKE)
int
sudo_gettime_awake_v1(struct timespec *ts)
{
static int has_monoclock = -1;
debug_decl(sudo_gettime_awake, SUDO_DEBUG_UTIL)
/* Check whether the kernel/libc actually supports a monotonic clock. */
# ifdef _SC_MONOTONIC_CLOCK
if (has_monoclock == -1)
has_monoclock = sysconf(_SC_MONOTONIC_CLOCK) != -1;
# endif
if (!has_monoclock)
debug_return_int(sudo_gettime_real(ts));
if (clock_gettime(SUDO_CLOCK_AWAKE, ts) == -1) {
sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
"clock_gettime(%d) failed, using wall clock",
(int)SUDO_CLOCK_AWAKE);
has_monoclock = 0;
debug_return_int(sudo_gettime_real(ts));
}
debug_return_int(0);
}
#elif defined(__MACH__)
int
sudo_gettime_awake_v1(struct timespec *ts)
{
uint64_t abstime, nsec;
static mach_timebase_info_data_t timebase_info;
debug_decl(sudo_gettime_awake, SUDO_DEBUG_UTIL)
if (timebase_info.denom == 0)
(void) mach_timebase_info(&timebase_info);
abstime = mach_absolute_time();
nsec = abstime * timebase_info.numer / timebase_info.denom;
ts->tv_sec = nsec / 1000000000;
ts->tv_nsec = nsec % 1000000000;
debug_return_int(0);
}
#else
int
sudo_gettime_awake_v1(struct timespec *ts)
{
/* No monotonic uptime clock available, use wall clock. */
return sudo_gettime_real(ts);
}
#endif

View File

@@ -71,6 +71,7 @@ sudo_fatalx_nodebug_v1
sudo_get_ttysize_v1
sudo_getgrouplist2_v1
sudo_gethostname_v1
sudo_gettime_awake_v1
sudo_gettime_mono_v1
sudo_gettime_real_v1
sudo_lbuf_append_quoted_v1