diff options
Diffstat (limited to 'test/kernel/adjtime.c')
-rw-r--r-- | test/kernel/adjtime.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/test/kernel/adjtime.c b/test/kernel/adjtime.c new file mode 100644 index 0000000..0ca8ff2 --- /dev/null +++ b/test/kernel/adjtime.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) Miroslav Lichvar 2015 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* Test the system adjtime() function. Check the range of supported offset, + support for readonly operation, and slew rate with different update + intervals and offsets. */ + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <unistd.h> + +static int +diff_tv(struct timeval *tv1, struct timeval *tv2) +{ + return 1000000 * (tv1->tv_sec - tv2->tv_sec) + (tv1->tv_usec - tv2->tv_usec); +} + +static struct timeval +usec_to_tv(int usec) +{ + struct timeval tv; + + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + + return tv; +} + +static int +try_adjtime(struct timeval *new, struct timeval *old) +{ + int r; + + r = adjtime(new, old); + if (r) + printf("adjtime() failed : %s ", strerror(errno)); + return r; +} + +static void +reset_adjtime(void) +{ + struct timeval tv; + + tv = usec_to_tv(0); + try_adjtime(&tv, NULL); +} + +static void +test_range(void) +{ + struct timeval tv; + int i; + + printf("range:\n"); + + for (i = 0; i < sizeof (time_t) * 8; i++) { + tv.tv_usec = 0; + tv.tv_sec = (1ULL << i) - 1; + printf("%20lld s : ", (long long)tv.tv_sec); + printf("%s\n", !try_adjtime(&tv, NULL) ? "ok" : ""); + tv.tv_sec = ~tv.tv_sec; + printf("%20lld s : ", (long long)tv.tv_sec); + printf("%s\n", !try_adjtime(&tv, NULL) ? "ok" : ""); + } +} + +static void +test_readonly(void) +{ + struct timeval tv1, tv2; + int i, r; + + printf("readonly:\n"); + + for (i = 0; i <= 20; i++) { + tv1 = usec_to_tv(1 << i); + + printf("%9d us : ", 1 << i); + try_adjtime(&tv1, NULL); + r = !try_adjtime(NULL, &tv2) && !diff_tv(&tv1, &tv2); + printf("%s\n", r ? "ok" : "fail"); + } +} + +static void +test_readwrite(void) +{ + struct timeval tv1, tv2, tv3; + int i, r; + + printf("readwrite:\n"); + + for (i = 0; i <= 20; i++) { + tv1 = usec_to_tv(1 << i); + tv3 = usec_to_tv(0); + + printf("%9d us : ", 1 << i); + try_adjtime(&tv1, NULL); + r = !try_adjtime(&tv3, &tv2) && !diff_tv(&tv1, &tv2); + printf("%s\n", r ? "ok" : "fail"); + } +} + +static void +xusleep(int usec) +{ + struct timeval tv; + + tv = usec_to_tv(usec); + select(0, NULL, NULL, NULL, &tv); +} + +static void +test_slew(void) +{ + struct timeval tv1, tv2, tv3; + int i, j, k, diff, min, has_min; + + printf("slew:\n"); + + for (i = 9; i <= 20; i++) { + printf("%9d us : ", 1 << i); + for (j = 4; j <= 20; j += 4) { + for (min = has_min = 0, k = 4; k < 16; k += 2) { + + tv1 = usec_to_tv(1 << j); + tv3 = usec_to_tv(0); + + xusleep(1 << i); + reset_adjtime(); + + xusleep(1 << i); + if (try_adjtime(&tv1, NULL)) + continue; + + xusleep(1 << i); + if (try_adjtime(&tv3, &tv2)) + continue; + + diff = diff_tv(&tv1, &tv2); + if (!has_min || min > diff) { + min = diff; + has_min = 1; + } + } + + if (!has_min) + continue; + + printf(" %5d (%d)", min, 1 << j); + fflush(stdout); + } + printf("\n"); + } +} + +int +main() +{ + test_range(); + test_readonly(); + test_readwrite(); + test_slew(); + + reset_adjtime(); + + return 0; +} |