15bccfe41SJohn Stultz /* Leap second stress test 25bccfe41SJohn Stultz * by: John Stultz (john.stultz@linaro.org) 35bccfe41SJohn Stultz * (C) Copyright IBM 2012 45bccfe41SJohn Stultz * (C) Copyright 2013, 2015 Linaro Limited 55bccfe41SJohn Stultz * Licensed under the GPLv2 65bccfe41SJohn Stultz * 75bccfe41SJohn Stultz * This test signals the kernel to insert a leap second 85bccfe41SJohn Stultz * every day at midnight GMT. This allows for stessing the 95bccfe41SJohn Stultz * kernel's leap-second behavior, as well as how well applications 105bccfe41SJohn Stultz * handle the leap-second discontinuity. 115bccfe41SJohn Stultz * 125bccfe41SJohn Stultz * Usage: leap-a-day [-s] [-i <num>] 135bccfe41SJohn Stultz * 145bccfe41SJohn Stultz * Options: 155bccfe41SJohn Stultz * -s: Each iteration, set the date to 10 seconds before midnight GMT. 165bccfe41SJohn Stultz * This speeds up the number of leapsecond transitions tested, 175bccfe41SJohn Stultz * but because it calls settimeofday frequently, advancing the 185bccfe41SJohn Stultz * time by 24 hours every ~16 seconds, it may cause application 195bccfe41SJohn Stultz * disruption. 205bccfe41SJohn Stultz * 215bccfe41SJohn Stultz * -i: Number of iterations to run (default: infinite) 225bccfe41SJohn Stultz * 235bccfe41SJohn Stultz * Other notes: Disabling NTP prior to running this is advised, as the two 245bccfe41SJohn Stultz * may conflict in their commands to the kernel. 255bccfe41SJohn Stultz * 265bccfe41SJohn Stultz * To build: 275bccfe41SJohn Stultz * $ gcc leap-a-day.c -o leap-a-day -lrt 285bccfe41SJohn Stultz * 295bccfe41SJohn Stultz * This program is free software: you can redistribute it and/or modify 305bccfe41SJohn Stultz * it under the terms of the GNU General Public License as published by 315bccfe41SJohn Stultz * the Free Software Foundation, either version 2 of the License, or 325bccfe41SJohn Stultz * (at your option) any later version. 335bccfe41SJohn Stultz * 345bccfe41SJohn Stultz * This program is distributed in the hope that it will be useful, 355bccfe41SJohn Stultz * but WITHOUT ANY WARRANTY; without even the implied warranty of 365bccfe41SJohn Stultz * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 375bccfe41SJohn Stultz * GNU General Public License for more details. 385bccfe41SJohn Stultz */ 395bccfe41SJohn Stultz 405bccfe41SJohn Stultz 415bccfe41SJohn Stultz 425bccfe41SJohn Stultz #include <stdio.h> 435bccfe41SJohn Stultz #include <stdlib.h> 445bccfe41SJohn Stultz #include <time.h> 455bccfe41SJohn Stultz #include <sys/time.h> 465bccfe41SJohn Stultz #include <sys/timex.h> 470c4a5fc9SJohn Stultz #include <sys/errno.h> 485bccfe41SJohn Stultz #include <string.h> 495bccfe41SJohn Stultz #include <signal.h> 505bccfe41SJohn Stultz #include <unistd.h> 515bccfe41SJohn Stultz #include "../kselftest.h" 525bccfe41SJohn Stultz 535bccfe41SJohn Stultz #define NSEC_PER_SEC 1000000000ULL 545bccfe41SJohn Stultz #define CLOCK_TAI 11 555bccfe41SJohn Stultz 560c4a5fc9SJohn Stultz time_t next_leap; 570c4a5fc9SJohn Stultz int error_found; 580c4a5fc9SJohn Stultz 595bccfe41SJohn Stultz /* returns 1 if a <= b, 0 otherwise */ 605bccfe41SJohn Stultz static inline int in_order(struct timespec a, struct timespec b) 615bccfe41SJohn Stultz { 625bccfe41SJohn Stultz if (a.tv_sec < b.tv_sec) 635bccfe41SJohn Stultz return 1; 645bccfe41SJohn Stultz if (a.tv_sec > b.tv_sec) 655bccfe41SJohn Stultz return 0; 665bccfe41SJohn Stultz if (a.tv_nsec > b.tv_nsec) 675bccfe41SJohn Stultz return 0; 685bccfe41SJohn Stultz return 1; 695bccfe41SJohn Stultz } 705bccfe41SJohn Stultz 715bccfe41SJohn Stultz struct timespec timespec_add(struct timespec ts, unsigned long long ns) 725bccfe41SJohn Stultz { 735bccfe41SJohn Stultz ts.tv_nsec += ns; 745bccfe41SJohn Stultz while (ts.tv_nsec >= NSEC_PER_SEC) { 755bccfe41SJohn Stultz ts.tv_nsec -= NSEC_PER_SEC; 765bccfe41SJohn Stultz ts.tv_sec++; 775bccfe41SJohn Stultz } 785bccfe41SJohn Stultz return ts; 795bccfe41SJohn Stultz } 805bccfe41SJohn Stultz 815bccfe41SJohn Stultz char *time_state_str(int state) 825bccfe41SJohn Stultz { 835bccfe41SJohn Stultz switch (state) { 845bccfe41SJohn Stultz case TIME_OK: return "TIME_OK"; 855bccfe41SJohn Stultz case TIME_INS: return "TIME_INS"; 865bccfe41SJohn Stultz case TIME_DEL: return "TIME_DEL"; 875bccfe41SJohn Stultz case TIME_OOP: return "TIME_OOP"; 885bccfe41SJohn Stultz case TIME_WAIT: return "TIME_WAIT"; 895bccfe41SJohn Stultz case TIME_BAD: return "TIME_BAD"; 905bccfe41SJohn Stultz } 915bccfe41SJohn Stultz return "ERROR"; 925bccfe41SJohn Stultz } 935bccfe41SJohn Stultz 945bccfe41SJohn Stultz /* clear NTP time_status & time_state */ 955bccfe41SJohn Stultz int clear_time_state(void) 965bccfe41SJohn Stultz { 975bccfe41SJohn Stultz struct timex tx; 985bccfe41SJohn Stultz int ret; 995bccfe41SJohn Stultz 1005bccfe41SJohn Stultz /* 1015bccfe41SJohn Stultz * We have to call adjtime twice here, as kernels 1025bccfe41SJohn Stultz * prior to 6b1859dba01c7 (included in 3.5 and 1035bccfe41SJohn Stultz * -stable), had an issue with the state machine 1045bccfe41SJohn Stultz * and wouldn't clear the STA_INS/DEL flag directly. 1055bccfe41SJohn Stultz */ 1065bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 1075bccfe41SJohn Stultz tx.status = STA_PLL; 1085bccfe41SJohn Stultz ret = adjtimex(&tx); 1095bccfe41SJohn Stultz 1105bccfe41SJohn Stultz /* Clear maxerror, as it can cause UNSYNC to be set */ 1115bccfe41SJohn Stultz tx.modes = ADJ_MAXERROR; 1125bccfe41SJohn Stultz tx.maxerror = 0; 1135bccfe41SJohn Stultz ret = adjtimex(&tx); 1145bccfe41SJohn Stultz 1155bccfe41SJohn Stultz /* Clear the status */ 1165bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 1175bccfe41SJohn Stultz tx.status = 0; 1185bccfe41SJohn Stultz ret = adjtimex(&tx); 1195bccfe41SJohn Stultz 1205bccfe41SJohn Stultz return ret; 1215bccfe41SJohn Stultz } 1225bccfe41SJohn Stultz 1235bccfe41SJohn Stultz /* Make sure we cleanup on ctrl-c */ 1245bccfe41SJohn Stultz void handler(int unused) 1255bccfe41SJohn Stultz { 1265bccfe41SJohn Stultz clear_time_state(); 1275bccfe41SJohn Stultz exit(0); 1285bccfe41SJohn Stultz } 1295bccfe41SJohn Stultz 1300c4a5fc9SJohn Stultz void sigalarm(int signo) 1310c4a5fc9SJohn Stultz { 1320c4a5fc9SJohn Stultz struct timex tx; 1330c4a5fc9SJohn Stultz int ret; 1340c4a5fc9SJohn Stultz 1350c4a5fc9SJohn Stultz tx.modes = 0; 1360c4a5fc9SJohn Stultz ret = adjtimex(&tx); 1370c4a5fc9SJohn Stultz 13851a16c1eSJohn Stultz if (tx.time.tv_sec < next_leap) { 13951a16c1eSJohn Stultz printf("Error: Early timer expiration! (Should be %ld)\n", next_leap); 14051a16c1eSJohn Stultz error_found = 1; 14151a16c1eSJohn Stultz printf("adjtimex: %10ld sec + %6ld us (%i)\t%s\n", 14251a16c1eSJohn Stultz tx.time.tv_sec, 1430c4a5fc9SJohn Stultz tx.time.tv_usec, 1440c4a5fc9SJohn Stultz tx.tai, 1450c4a5fc9SJohn Stultz time_state_str(ret)); 1460c4a5fc9SJohn Stultz } 1470c4a5fc9SJohn Stultz if (ret != TIME_WAIT) { 14851a16c1eSJohn Stultz printf("Error: Timer seeing incorrect NTP state? (Should be TIME_WAIT)\n"); 1490c4a5fc9SJohn Stultz error_found = 1; 15051a16c1eSJohn Stultz printf("adjtimex: %10ld sec + %6ld us (%i)\t%s\n", 15151a16c1eSJohn Stultz tx.time.tv_sec, 15251a16c1eSJohn Stultz tx.time.tv_usec, 15351a16c1eSJohn Stultz tx.tai, 15451a16c1eSJohn Stultz time_state_str(ret)); 1550c4a5fc9SJohn Stultz } 1560c4a5fc9SJohn Stultz } 1570c4a5fc9SJohn Stultz 1580c4a5fc9SJohn Stultz 1595bccfe41SJohn Stultz /* Test for known hrtimer failure */ 1605bccfe41SJohn Stultz void test_hrtimer_failure(void) 1615bccfe41SJohn Stultz { 1625bccfe41SJohn Stultz struct timespec now, target; 1635bccfe41SJohn Stultz 1645bccfe41SJohn Stultz clock_gettime(CLOCK_REALTIME, &now); 1655bccfe41SJohn Stultz target = timespec_add(now, NSEC_PER_SEC/2); 1665bccfe41SJohn Stultz clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &target, NULL); 1675bccfe41SJohn Stultz clock_gettime(CLOCK_REALTIME, &now); 1685bccfe41SJohn Stultz 1690c4a5fc9SJohn Stultz if (!in_order(target, now)) { 1705bccfe41SJohn Stultz printf("ERROR: hrtimer early expiration failure observed.\n"); 1710c4a5fc9SJohn Stultz error_found = 1; 1720c4a5fc9SJohn Stultz } 1735bccfe41SJohn Stultz } 1745bccfe41SJohn Stultz 1755bccfe41SJohn Stultz int main(int argc, char **argv) 1765bccfe41SJohn Stultz { 1770c4a5fc9SJohn Stultz timer_t tm1; 1780c4a5fc9SJohn Stultz struct itimerspec its1; 1790c4a5fc9SJohn Stultz struct sigevent se; 1800c4a5fc9SJohn Stultz struct sigaction act; 1810c4a5fc9SJohn Stultz int signum = SIGRTMAX; 182*98b74e1fSJohn Stultz int settime = 1; 1835bccfe41SJohn Stultz int tai_time = 0; 1845bccfe41SJohn Stultz int insert = 1; 185*98b74e1fSJohn Stultz int iterations = 10; 1865bccfe41SJohn Stultz int opt; 1875bccfe41SJohn Stultz 1885bccfe41SJohn Stultz /* Process arguments */ 1895bccfe41SJohn Stultz while ((opt = getopt(argc, argv, "sti:")) != -1) { 1905bccfe41SJohn Stultz switch (opt) { 191*98b74e1fSJohn Stultz case 'w': 192*98b74e1fSJohn Stultz printf("Only setting leap-flag, not changing time. It could take up to a day for leap to trigger.\n"); 193*98b74e1fSJohn Stultz settime = 0; 1945bccfe41SJohn Stultz break; 1955bccfe41SJohn Stultz case 'i': 1965bccfe41SJohn Stultz iterations = atoi(optarg); 1975bccfe41SJohn Stultz break; 1985bccfe41SJohn Stultz case 't': 1995bccfe41SJohn Stultz tai_time = 1; 2005bccfe41SJohn Stultz break; 2015bccfe41SJohn Stultz default: 202*98b74e1fSJohn Stultz printf("Usage: %s [-w] [-i <iterations>]\n", argv[0]); 203*98b74e1fSJohn Stultz printf(" -w: Set flag and wait for leap second each iteration"); 204*98b74e1fSJohn Stultz printf(" (default sets time to right before leapsecond)\n"); 205*98b74e1fSJohn Stultz printf(" -i: Number of iterations (-1 = infinite, default is 10)\n"); 2065bccfe41SJohn Stultz printf(" -t: Print TAI time\n"); 2075bccfe41SJohn Stultz exit(-1); 2085bccfe41SJohn Stultz } 2095bccfe41SJohn Stultz } 2105bccfe41SJohn Stultz 2115bccfe41SJohn Stultz /* Make sure TAI support is present if -t was used */ 2125bccfe41SJohn Stultz if (tai_time) { 2135bccfe41SJohn Stultz struct timespec ts; 2145bccfe41SJohn Stultz 2155bccfe41SJohn Stultz if (clock_gettime(CLOCK_TAI, &ts)) { 2165bccfe41SJohn Stultz printf("System doesn't support CLOCK_TAI\n"); 2175bccfe41SJohn Stultz ksft_exit_fail(); 2185bccfe41SJohn Stultz } 2195bccfe41SJohn Stultz } 2205bccfe41SJohn Stultz 2215bccfe41SJohn Stultz signal(SIGINT, handler); 2225bccfe41SJohn Stultz signal(SIGKILL, handler); 2235bccfe41SJohn Stultz 2240c4a5fc9SJohn Stultz /* Set up timer signal handler: */ 2250c4a5fc9SJohn Stultz sigfillset(&act.sa_mask); 2260c4a5fc9SJohn Stultz act.sa_flags = 0; 2270c4a5fc9SJohn Stultz act.sa_handler = sigalarm; 2280c4a5fc9SJohn Stultz sigaction(signum, &act, NULL); 2290c4a5fc9SJohn Stultz 2305bccfe41SJohn Stultz if (iterations < 0) 2315bccfe41SJohn Stultz printf("This runs continuously. Press ctrl-c to stop\n"); 2325bccfe41SJohn Stultz else 2335bccfe41SJohn Stultz printf("Running for %i iterations. Press ctrl-c to stop\n", iterations); 2345bccfe41SJohn Stultz 2355bccfe41SJohn Stultz printf("\n"); 2365bccfe41SJohn Stultz while (1) { 2375bccfe41SJohn Stultz int ret; 2385bccfe41SJohn Stultz struct timespec ts; 2395bccfe41SJohn Stultz struct timex tx; 2400c4a5fc9SJohn Stultz time_t now; 2415bccfe41SJohn Stultz 2425bccfe41SJohn Stultz /* Get the current time */ 2435bccfe41SJohn Stultz clock_gettime(CLOCK_REALTIME, &ts); 2445bccfe41SJohn Stultz 2455bccfe41SJohn Stultz /* Calculate the next possible leap second 23:59:60 GMT */ 2465bccfe41SJohn Stultz next_leap = ts.tv_sec; 2475bccfe41SJohn Stultz next_leap += 86400 - (next_leap % 86400); 2485bccfe41SJohn Stultz 2495bccfe41SJohn Stultz if (settime) { 2505bccfe41SJohn Stultz struct timeval tv; 2515bccfe41SJohn Stultz 2525bccfe41SJohn Stultz tv.tv_sec = next_leap - 10; 2535bccfe41SJohn Stultz tv.tv_usec = 0; 2545bccfe41SJohn Stultz settimeofday(&tv, NULL); 2555bccfe41SJohn Stultz printf("Setting time to %s", ctime(&tv.tv_sec)); 2565bccfe41SJohn Stultz } 2575bccfe41SJohn Stultz 2585bccfe41SJohn Stultz /* Reset NTP time state */ 2595bccfe41SJohn Stultz clear_time_state(); 2605bccfe41SJohn Stultz 2615bccfe41SJohn Stultz /* Set the leap second insert flag */ 2625bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 2635bccfe41SJohn Stultz if (insert) 2645bccfe41SJohn Stultz tx.status = STA_INS; 2655bccfe41SJohn Stultz else 2665bccfe41SJohn Stultz tx.status = STA_DEL; 2675bccfe41SJohn Stultz ret = adjtimex(&tx); 2685bccfe41SJohn Stultz if (ret < 0) { 2695bccfe41SJohn Stultz printf("Error: Problem setting STA_INS/STA_DEL!: %s\n", 2705bccfe41SJohn Stultz time_state_str(ret)); 2715bccfe41SJohn Stultz return ksft_exit_fail(); 2725bccfe41SJohn Stultz } 2735bccfe41SJohn Stultz 2745bccfe41SJohn Stultz /* Validate STA_INS was set */ 2755bccfe41SJohn Stultz tx.modes = 0; 2765bccfe41SJohn Stultz ret = adjtimex(&tx); 2775bccfe41SJohn Stultz if (tx.status != STA_INS && tx.status != STA_DEL) { 2785bccfe41SJohn Stultz printf("Error: STA_INS/STA_DEL not set!: %s\n", 2795bccfe41SJohn Stultz time_state_str(ret)); 2805bccfe41SJohn Stultz return ksft_exit_fail(); 2815bccfe41SJohn Stultz } 2825bccfe41SJohn Stultz 2835bccfe41SJohn Stultz if (tai_time) { 2845bccfe41SJohn Stultz printf("Using TAI time," 2855bccfe41SJohn Stultz " no inconsistencies should be seen!\n"); 2865bccfe41SJohn Stultz } 2875bccfe41SJohn Stultz 2885bccfe41SJohn Stultz printf("Scheduling leap second for %s", ctime(&next_leap)); 2895bccfe41SJohn Stultz 2900c4a5fc9SJohn Stultz /* Set up timer */ 29151a16c1eSJohn Stultz printf("Setting timer for %ld - %s", next_leap, ctime(&next_leap)); 2920c4a5fc9SJohn Stultz memset(&se, 0, sizeof(se)); 2930c4a5fc9SJohn Stultz se.sigev_notify = SIGEV_SIGNAL; 2940c4a5fc9SJohn Stultz se.sigev_signo = signum; 2950c4a5fc9SJohn Stultz se.sigev_value.sival_int = 0; 2960c4a5fc9SJohn Stultz if (timer_create(CLOCK_REALTIME, &se, &tm1) == -1) { 2970c4a5fc9SJohn Stultz printf("Error: timer_create failed\n"); 2980c4a5fc9SJohn Stultz return ksft_exit_fail(); 2990c4a5fc9SJohn Stultz } 3000c4a5fc9SJohn Stultz its1.it_value.tv_sec = next_leap; 3010c4a5fc9SJohn Stultz its1.it_value.tv_nsec = 0; 3020c4a5fc9SJohn Stultz its1.it_interval.tv_sec = 0; 3030c4a5fc9SJohn Stultz its1.it_interval.tv_nsec = 0; 3040c4a5fc9SJohn Stultz timer_settime(tm1, TIMER_ABSTIME, &its1, NULL); 3050c4a5fc9SJohn Stultz 3065bccfe41SJohn Stultz /* Wake up 3 seconds before leap */ 3075bccfe41SJohn Stultz ts.tv_sec = next_leap - 3; 3085bccfe41SJohn Stultz ts.tv_nsec = 0; 3095bccfe41SJohn Stultz 3100c4a5fc9SJohn Stultz 3115bccfe41SJohn Stultz while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, NULL)) 3125bccfe41SJohn Stultz printf("Something woke us up, returning to sleep\n"); 3135bccfe41SJohn Stultz 3145bccfe41SJohn Stultz /* Validate STA_INS is still set */ 3155bccfe41SJohn Stultz tx.modes = 0; 3165bccfe41SJohn Stultz ret = adjtimex(&tx); 3175bccfe41SJohn Stultz if (tx.status != STA_INS && tx.status != STA_DEL) { 3185bccfe41SJohn Stultz printf("Something cleared STA_INS/STA_DEL, setting it again.\n"); 3195bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 3205bccfe41SJohn Stultz if (insert) 3215bccfe41SJohn Stultz tx.status = STA_INS; 3225bccfe41SJohn Stultz else 3235bccfe41SJohn Stultz tx.status = STA_DEL; 3245bccfe41SJohn Stultz ret = adjtimex(&tx); 3255bccfe41SJohn Stultz } 3265bccfe41SJohn Stultz 3275bccfe41SJohn Stultz /* Check adjtimex output every half second */ 3285bccfe41SJohn Stultz now = tx.time.tv_sec; 3295bccfe41SJohn Stultz while (now < next_leap + 2) { 3305bccfe41SJohn Stultz char buf[26]; 3315bccfe41SJohn Stultz struct timespec tai; 3320c4a5fc9SJohn Stultz int ret; 3335bccfe41SJohn Stultz 3345bccfe41SJohn Stultz tx.modes = 0; 3355bccfe41SJohn Stultz ret = adjtimex(&tx); 3365bccfe41SJohn Stultz 3375bccfe41SJohn Stultz if (tai_time) { 3385bccfe41SJohn Stultz clock_gettime(CLOCK_TAI, &tai); 3395bccfe41SJohn Stultz printf("%ld sec, %9ld ns\t%s\n", 3405bccfe41SJohn Stultz tai.tv_sec, 3415bccfe41SJohn Stultz tai.tv_nsec, 3425bccfe41SJohn Stultz time_state_str(ret)); 3435bccfe41SJohn Stultz } else { 3445bccfe41SJohn Stultz ctime_r(&tx.time.tv_sec, buf); 3455bccfe41SJohn Stultz buf[strlen(buf)-1] = 0; /*remove trailing\n */ 3465bccfe41SJohn Stultz 3475bccfe41SJohn Stultz printf("%s + %6ld us (%i)\t%s\n", 3485bccfe41SJohn Stultz buf, 3495bccfe41SJohn Stultz tx.time.tv_usec, 3505bccfe41SJohn Stultz tx.tai, 3515bccfe41SJohn Stultz time_state_str(ret)); 3525bccfe41SJohn Stultz } 3535bccfe41SJohn Stultz now = tx.time.tv_sec; 3545bccfe41SJohn Stultz /* Sleep for another half second */ 3555bccfe41SJohn Stultz ts.tv_sec = 0; 3565bccfe41SJohn Stultz ts.tv_nsec = NSEC_PER_SEC / 2; 3575bccfe41SJohn Stultz clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); 3585bccfe41SJohn Stultz } 3595bccfe41SJohn Stultz /* Switch to using other mode */ 3605bccfe41SJohn Stultz insert = !insert; 3615bccfe41SJohn Stultz 3625bccfe41SJohn Stultz /* Note if kernel has known hrtimer failure */ 3635bccfe41SJohn Stultz test_hrtimer_failure(); 3645bccfe41SJohn Stultz 3650c4a5fc9SJohn Stultz printf("Leap complete\n"); 3660c4a5fc9SJohn Stultz if (error_found) { 3670c4a5fc9SJohn Stultz printf("Errors observed\n"); 3680c4a5fc9SJohn Stultz clear_time_state(); 3690c4a5fc9SJohn Stultz return ksft_exit_fail(); 3700c4a5fc9SJohn Stultz } 3710c4a5fc9SJohn Stultz printf("\n"); 3725bccfe41SJohn Stultz if ((iterations != -1) && !(--iterations)) 3735bccfe41SJohn Stultz break; 3745bccfe41SJohn Stultz } 3755bccfe41SJohn Stultz 3765bccfe41SJohn Stultz clear_time_state(); 3775bccfe41SJohn Stultz return ksft_exit_pass(); 3785bccfe41SJohn Stultz } 379