forked from Minki/linux
b841065043
There is no need to keep timers tests in sync with external timers repo. Drop support for !KTEST to support for building and running timers tests without kselftest framework. Reference: https://lkml.org/lkml/2017/8/10/952 Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com> Acked-by: John Stultz <john.stultz@linaro.org>
329 lines
6.4 KiB
C
329 lines
6.4 KiB
C
/* valid adjtimex test
|
|
* by: John Stultz <john.stultz@linaro.org>
|
|
* (C) Copyright Linaro 2015
|
|
* Licensed under the GPLv2
|
|
*
|
|
* This test validates adjtimex interface with valid
|
|
* and invalid test data.
|
|
*
|
|
* Usage: valid-adjtimex
|
|
*
|
|
* To build:
|
|
* $ gcc valid-adjtimex.c -o valid-adjtimex -lrt
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <sys/timex.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include "../kselftest.h"
|
|
|
|
#define NSEC_PER_SEC 1000000000LL
|
|
#define USEC_PER_SEC 1000000LL
|
|
|
|
#define ADJ_SETOFFSET 0x0100
|
|
|
|
#include <sys/syscall.h>
|
|
static int clock_adjtime(clockid_t id, struct timex *tx)
|
|
{
|
|
return syscall(__NR_clock_adjtime, id, tx);
|
|
}
|
|
|
|
|
|
/* clear NTP time_status & time_state */
|
|
int clear_time_state(void)
|
|
{
|
|
struct timex tx;
|
|
int ret;
|
|
|
|
tx.modes = ADJ_STATUS;
|
|
tx.status = 0;
|
|
ret = adjtimex(&tx);
|
|
return ret;
|
|
}
|
|
|
|
#define NUM_FREQ_VALID 32
|
|
#define NUM_FREQ_OUTOFRANGE 4
|
|
#define NUM_FREQ_INVALID 2
|
|
|
|
long valid_freq[NUM_FREQ_VALID] = {
|
|
-499<<16,
|
|
-450<<16,
|
|
-400<<16,
|
|
-350<<16,
|
|
-300<<16,
|
|
-250<<16,
|
|
-200<<16,
|
|
-150<<16,
|
|
-100<<16,
|
|
-75<<16,
|
|
-50<<16,
|
|
-25<<16,
|
|
-10<<16,
|
|
-5<<16,
|
|
-1<<16,
|
|
-1000,
|
|
1<<16,
|
|
5<<16,
|
|
10<<16,
|
|
25<<16,
|
|
50<<16,
|
|
75<<16,
|
|
100<<16,
|
|
150<<16,
|
|
200<<16,
|
|
250<<16,
|
|
300<<16,
|
|
350<<16,
|
|
400<<16,
|
|
450<<16,
|
|
499<<16,
|
|
};
|
|
|
|
long outofrange_freq[NUM_FREQ_OUTOFRANGE] = {
|
|
-1000<<16,
|
|
-550<<16,
|
|
550<<16,
|
|
1000<<16,
|
|
};
|
|
|
|
#define LONG_MAX (~0UL>>1)
|
|
#define LONG_MIN (-LONG_MAX - 1)
|
|
|
|
long invalid_freq[NUM_FREQ_INVALID] = {
|
|
LONG_MAX,
|
|
LONG_MIN,
|
|
};
|
|
|
|
int validate_freq(void)
|
|
{
|
|
struct timex tx;
|
|
int ret, pass = 0;
|
|
int i;
|
|
|
|
clear_time_state();
|
|
|
|
memset(&tx, 0, sizeof(struct timex));
|
|
/* Set the leap second insert flag */
|
|
|
|
printf("Testing ADJ_FREQ... ");
|
|
for (i = 0; i < NUM_FREQ_VALID; i++) {
|
|
tx.modes = ADJ_FREQUENCY;
|
|
tx.freq = valid_freq[i];
|
|
|
|
ret = adjtimex(&tx);
|
|
if (ret < 0) {
|
|
printf("[FAIL]\n");
|
|
printf("Error: adjtimex(ADJ_FREQ, %ld - %ld ppm\n",
|
|
valid_freq[i], valid_freq[i]>>16);
|
|
pass = -1;
|
|
goto out;
|
|
}
|
|
tx.modes = 0;
|
|
ret = adjtimex(&tx);
|
|
if (tx.freq != valid_freq[i]) {
|
|
printf("Warning: freq value %ld not what we set it (%ld)!\n",
|
|
tx.freq, valid_freq[i]);
|
|
}
|
|
}
|
|
for (i = 0; i < NUM_FREQ_OUTOFRANGE; i++) {
|
|
tx.modes = ADJ_FREQUENCY;
|
|
tx.freq = outofrange_freq[i];
|
|
|
|
ret = adjtimex(&tx);
|
|
if (ret < 0) {
|
|
printf("[FAIL]\n");
|
|
printf("Error: adjtimex(ADJ_FREQ, %ld - %ld ppm\n",
|
|
outofrange_freq[i], outofrange_freq[i]>>16);
|
|
pass = -1;
|
|
goto out;
|
|
}
|
|
tx.modes = 0;
|
|
ret = adjtimex(&tx);
|
|
if (tx.freq == outofrange_freq[i]) {
|
|
printf("[FAIL]\n");
|
|
printf("ERROR: out of range value %ld actually set!\n",
|
|
tx.freq);
|
|
pass = -1;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
if (sizeof(long) == 8) { /* this case only applies to 64bit systems */
|
|
for (i = 0; i < NUM_FREQ_INVALID; i++) {
|
|
tx.modes = ADJ_FREQUENCY;
|
|
tx.freq = invalid_freq[i];
|
|
ret = adjtimex(&tx);
|
|
if (ret >= 0) {
|
|
printf("[FAIL]\n");
|
|
printf("Error: No failure on invalid ADJ_FREQUENCY %ld\n",
|
|
invalid_freq[i]);
|
|
pass = -1;
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("[OK]\n");
|
|
out:
|
|
/* reset freq to zero */
|
|
tx.modes = ADJ_FREQUENCY;
|
|
tx.freq = 0;
|
|
ret = adjtimex(&tx);
|
|
|
|
return pass;
|
|
}
|
|
|
|
|
|
int set_offset(long long offset, int use_nano)
|
|
{
|
|
struct timex tmx = {};
|
|
int ret;
|
|
|
|
tmx.modes = ADJ_SETOFFSET;
|
|
if (use_nano) {
|
|
tmx.modes |= ADJ_NANO;
|
|
|
|
tmx.time.tv_sec = offset / NSEC_PER_SEC;
|
|
tmx.time.tv_usec = offset % NSEC_PER_SEC;
|
|
|
|
if (offset < 0 && tmx.time.tv_usec) {
|
|
tmx.time.tv_sec -= 1;
|
|
tmx.time.tv_usec += NSEC_PER_SEC;
|
|
}
|
|
} else {
|
|
tmx.time.tv_sec = offset / USEC_PER_SEC;
|
|
tmx.time.tv_usec = offset % USEC_PER_SEC;
|
|
|
|
if (offset < 0 && tmx.time.tv_usec) {
|
|
tmx.time.tv_sec -= 1;
|
|
tmx.time.tv_usec += USEC_PER_SEC;
|
|
}
|
|
}
|
|
|
|
ret = clock_adjtime(CLOCK_REALTIME, &tmx);
|
|
if (ret < 0) {
|
|
printf("(sec: %ld usec: %ld) ", tmx.time.tv_sec, tmx.time.tv_usec);
|
|
printf("[FAIL]\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int set_bad_offset(long sec, long usec, int use_nano)
|
|
{
|
|
struct timex tmx = {};
|
|
int ret;
|
|
|
|
tmx.modes = ADJ_SETOFFSET;
|
|
if (use_nano)
|
|
tmx.modes |= ADJ_NANO;
|
|
|
|
tmx.time.tv_sec = sec;
|
|
tmx.time.tv_usec = usec;
|
|
ret = clock_adjtime(CLOCK_REALTIME, &tmx);
|
|
if (ret >= 0) {
|
|
printf("Invalid (sec: %ld usec: %ld) did not fail! ", tmx.time.tv_sec, tmx.time.tv_usec);
|
|
printf("[FAIL]\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int validate_set_offset(void)
|
|
{
|
|
printf("Testing ADJ_SETOFFSET... ");
|
|
|
|
/* Test valid values */
|
|
if (set_offset(NSEC_PER_SEC - 1, 1))
|
|
return -1;
|
|
|
|
if (set_offset(-NSEC_PER_SEC + 1, 1))
|
|
return -1;
|
|
|
|
if (set_offset(-NSEC_PER_SEC - 1, 1))
|
|
return -1;
|
|
|
|
if (set_offset(5 * NSEC_PER_SEC, 1))
|
|
return -1;
|
|
|
|
if (set_offset(-5 * NSEC_PER_SEC, 1))
|
|
return -1;
|
|
|
|
if (set_offset(5 * NSEC_PER_SEC + NSEC_PER_SEC / 2, 1))
|
|
return -1;
|
|
|
|
if (set_offset(-5 * NSEC_PER_SEC - NSEC_PER_SEC / 2, 1))
|
|
return -1;
|
|
|
|
if (set_offset(USEC_PER_SEC - 1, 0))
|
|
return -1;
|
|
|
|
if (set_offset(-USEC_PER_SEC + 1, 0))
|
|
return -1;
|
|
|
|
if (set_offset(-USEC_PER_SEC - 1, 0))
|
|
return -1;
|
|
|
|
if (set_offset(5 * USEC_PER_SEC, 0))
|
|
return -1;
|
|
|
|
if (set_offset(-5 * USEC_PER_SEC, 0))
|
|
return -1;
|
|
|
|
if (set_offset(5 * USEC_PER_SEC + USEC_PER_SEC / 2, 0))
|
|
return -1;
|
|
|
|
if (set_offset(-5 * USEC_PER_SEC - USEC_PER_SEC / 2, 0))
|
|
return -1;
|
|
|
|
/* Test invalid values */
|
|
if (set_bad_offset(0, -1, 1))
|
|
return -1;
|
|
if (set_bad_offset(0, -1, 0))
|
|
return -1;
|
|
if (set_bad_offset(0, 2 * NSEC_PER_SEC, 1))
|
|
return -1;
|
|
if (set_bad_offset(0, 2 * USEC_PER_SEC, 0))
|
|
return -1;
|
|
if (set_bad_offset(0, NSEC_PER_SEC, 1))
|
|
return -1;
|
|
if (set_bad_offset(0, USEC_PER_SEC, 0))
|
|
return -1;
|
|
if (set_bad_offset(0, -NSEC_PER_SEC, 1))
|
|
return -1;
|
|
if (set_bad_offset(0, -USEC_PER_SEC, 0))
|
|
return -1;
|
|
|
|
printf("[OK]\n");
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
if (validate_freq())
|
|
return ksft_exit_fail();
|
|
|
|
if (validate_set_offset())
|
|
return ksft_exit_fail();
|
|
|
|
return ksft_exit_pass();
|
|
}
|