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> 475bccfe41SJohn Stultz #include <string.h> 485bccfe41SJohn Stultz #include <signal.h> 495bccfe41SJohn Stultz #include <unistd.h> 505bccfe41SJohn Stultz #ifdef KTEST 515bccfe41SJohn Stultz #include "../kselftest.h" 525bccfe41SJohn Stultz #else 535bccfe41SJohn Stultz static inline int ksft_exit_pass(void) 545bccfe41SJohn Stultz { 555bccfe41SJohn Stultz exit(0); 565bccfe41SJohn Stultz } 575bccfe41SJohn Stultz static inline int ksft_exit_fail(void) 585bccfe41SJohn Stultz { 595bccfe41SJohn Stultz exit(1); 605bccfe41SJohn Stultz } 615bccfe41SJohn Stultz #endif 625bccfe41SJohn Stultz 635bccfe41SJohn Stultz #define NSEC_PER_SEC 1000000000ULL 645bccfe41SJohn Stultz #define CLOCK_TAI 11 655bccfe41SJohn Stultz 665bccfe41SJohn Stultz /* returns 1 if a <= b, 0 otherwise */ 675bccfe41SJohn Stultz static inline int in_order(struct timespec a, struct timespec b) 685bccfe41SJohn Stultz { 695bccfe41SJohn Stultz if (a.tv_sec < b.tv_sec) 705bccfe41SJohn Stultz return 1; 715bccfe41SJohn Stultz if (a.tv_sec > b.tv_sec) 725bccfe41SJohn Stultz return 0; 735bccfe41SJohn Stultz if (a.tv_nsec > b.tv_nsec) 745bccfe41SJohn Stultz return 0; 755bccfe41SJohn Stultz return 1; 765bccfe41SJohn Stultz } 775bccfe41SJohn Stultz 785bccfe41SJohn Stultz struct timespec timespec_add(struct timespec ts, unsigned long long ns) 795bccfe41SJohn Stultz { 805bccfe41SJohn Stultz ts.tv_nsec += ns; 815bccfe41SJohn Stultz while (ts.tv_nsec >= NSEC_PER_SEC) { 825bccfe41SJohn Stultz ts.tv_nsec -= NSEC_PER_SEC; 835bccfe41SJohn Stultz ts.tv_sec++; 845bccfe41SJohn Stultz } 855bccfe41SJohn Stultz return ts; 865bccfe41SJohn Stultz } 875bccfe41SJohn Stultz 885bccfe41SJohn Stultz char *time_state_str(int state) 895bccfe41SJohn Stultz { 905bccfe41SJohn Stultz switch (state) { 915bccfe41SJohn Stultz case TIME_OK: return "TIME_OK"; 925bccfe41SJohn Stultz case TIME_INS: return "TIME_INS"; 935bccfe41SJohn Stultz case TIME_DEL: return "TIME_DEL"; 945bccfe41SJohn Stultz case TIME_OOP: return "TIME_OOP"; 955bccfe41SJohn Stultz case TIME_WAIT: return "TIME_WAIT"; 965bccfe41SJohn Stultz case TIME_BAD: return "TIME_BAD"; 975bccfe41SJohn Stultz } 985bccfe41SJohn Stultz return "ERROR"; 995bccfe41SJohn Stultz } 1005bccfe41SJohn Stultz 1015bccfe41SJohn Stultz /* clear NTP time_status & time_state */ 1025bccfe41SJohn Stultz int clear_time_state(void) 1035bccfe41SJohn Stultz { 1045bccfe41SJohn Stultz struct timex tx; 1055bccfe41SJohn Stultz int ret; 1065bccfe41SJohn Stultz 1075bccfe41SJohn Stultz /* 1085bccfe41SJohn Stultz * We have to call adjtime twice here, as kernels 1095bccfe41SJohn Stultz * prior to 6b1859dba01c7 (included in 3.5 and 1105bccfe41SJohn Stultz * -stable), had an issue with the state machine 1115bccfe41SJohn Stultz * and wouldn't clear the STA_INS/DEL flag directly. 1125bccfe41SJohn Stultz */ 1135bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 1145bccfe41SJohn Stultz tx.status = STA_PLL; 1155bccfe41SJohn Stultz ret = adjtimex(&tx); 1165bccfe41SJohn Stultz 1175bccfe41SJohn Stultz /* Clear maxerror, as it can cause UNSYNC to be set */ 1185bccfe41SJohn Stultz tx.modes = ADJ_MAXERROR; 1195bccfe41SJohn Stultz tx.maxerror = 0; 1205bccfe41SJohn Stultz ret = adjtimex(&tx); 1215bccfe41SJohn Stultz 1225bccfe41SJohn Stultz /* Clear the status */ 1235bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 1245bccfe41SJohn Stultz tx.status = 0; 1255bccfe41SJohn Stultz ret = adjtimex(&tx); 1265bccfe41SJohn Stultz 1275bccfe41SJohn Stultz return ret; 1285bccfe41SJohn Stultz } 1295bccfe41SJohn Stultz 1305bccfe41SJohn Stultz /* Make sure we cleanup on ctrl-c */ 1315bccfe41SJohn Stultz void handler(int unused) 1325bccfe41SJohn Stultz { 1335bccfe41SJohn Stultz clear_time_state(); 1345bccfe41SJohn Stultz exit(0); 1355bccfe41SJohn Stultz } 1365bccfe41SJohn Stultz 1375bccfe41SJohn Stultz /* Test for known hrtimer failure */ 1385bccfe41SJohn Stultz void test_hrtimer_failure(void) 1395bccfe41SJohn Stultz { 1405bccfe41SJohn Stultz struct timespec now, target; 1415bccfe41SJohn Stultz 1425bccfe41SJohn Stultz clock_gettime(CLOCK_REALTIME, &now); 1435bccfe41SJohn Stultz target = timespec_add(now, NSEC_PER_SEC/2); 1445bccfe41SJohn Stultz clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &target, NULL); 1455bccfe41SJohn Stultz clock_gettime(CLOCK_REALTIME, &now); 1465bccfe41SJohn Stultz 1475bccfe41SJohn Stultz if (!in_order(target, now)) 1485bccfe41SJohn Stultz printf("ERROR: hrtimer early expiration failure observed.\n"); 1495bccfe41SJohn Stultz } 1505bccfe41SJohn Stultz 1515bccfe41SJohn Stultz int main(int argc, char **argv) 1525bccfe41SJohn Stultz { 1535bccfe41SJohn Stultz int settime = 0; 1545bccfe41SJohn Stultz int tai_time = 0; 1555bccfe41SJohn Stultz int insert = 1; 1565bccfe41SJohn Stultz int iterations = -1; 1575bccfe41SJohn Stultz int opt; 1585bccfe41SJohn Stultz 1595bccfe41SJohn Stultz /* Process arguments */ 1605bccfe41SJohn Stultz while ((opt = getopt(argc, argv, "sti:")) != -1) { 1615bccfe41SJohn Stultz switch (opt) { 1625bccfe41SJohn Stultz case 's': 1635bccfe41SJohn Stultz printf("Setting time to speed up testing\n"); 1645bccfe41SJohn Stultz settime = 1; 1655bccfe41SJohn Stultz break; 1665bccfe41SJohn Stultz case 'i': 1675bccfe41SJohn Stultz iterations = atoi(optarg); 1685bccfe41SJohn Stultz break; 1695bccfe41SJohn Stultz case 't': 1705bccfe41SJohn Stultz tai_time = 1; 1715bccfe41SJohn Stultz break; 1725bccfe41SJohn Stultz default: 1735bccfe41SJohn Stultz printf("Usage: %s [-s] [-i <iterations>]\n", argv[0]); 1745bccfe41SJohn Stultz printf(" -s: Set time to right before leap second each iteration\n"); 1755bccfe41SJohn Stultz printf(" -i: Number of iterations\n"); 1765bccfe41SJohn Stultz printf(" -t: Print TAI time\n"); 1775bccfe41SJohn Stultz exit(-1); 1785bccfe41SJohn Stultz } 1795bccfe41SJohn Stultz } 1805bccfe41SJohn Stultz 1815bccfe41SJohn Stultz /* Make sure TAI support is present if -t was used */ 1825bccfe41SJohn Stultz if (tai_time) { 1835bccfe41SJohn Stultz struct timespec ts; 1845bccfe41SJohn Stultz 1855bccfe41SJohn Stultz if (clock_gettime(CLOCK_TAI, &ts)) { 1865bccfe41SJohn Stultz printf("System doesn't support CLOCK_TAI\n"); 1875bccfe41SJohn Stultz ksft_exit_fail(); 1885bccfe41SJohn Stultz } 1895bccfe41SJohn Stultz } 1905bccfe41SJohn Stultz 1915bccfe41SJohn Stultz signal(SIGINT, handler); 1925bccfe41SJohn Stultz signal(SIGKILL, handler); 1935bccfe41SJohn Stultz 1945bccfe41SJohn Stultz if (iterations < 0) 1955bccfe41SJohn Stultz printf("This runs continuously. Press ctrl-c to stop\n"); 1965bccfe41SJohn Stultz else 1975bccfe41SJohn Stultz printf("Running for %i iterations. Press ctrl-c to stop\n", iterations); 1985bccfe41SJohn Stultz 1995bccfe41SJohn Stultz printf("\n"); 2005bccfe41SJohn Stultz while (1) { 2015bccfe41SJohn Stultz int ret; 2025bccfe41SJohn Stultz struct timespec ts; 2035bccfe41SJohn Stultz struct timex tx; 2045bccfe41SJohn Stultz time_t now, next_leap; 2055bccfe41SJohn Stultz 2065bccfe41SJohn Stultz /* Get the current time */ 2075bccfe41SJohn Stultz clock_gettime(CLOCK_REALTIME, &ts); 2085bccfe41SJohn Stultz 2095bccfe41SJohn Stultz /* Calculate the next possible leap second 23:59:60 GMT */ 2105bccfe41SJohn Stultz next_leap = ts.tv_sec; 2115bccfe41SJohn Stultz next_leap += 86400 - (next_leap % 86400); 2125bccfe41SJohn Stultz 2135bccfe41SJohn Stultz if (settime) { 2145bccfe41SJohn Stultz struct timeval tv; 2155bccfe41SJohn Stultz 2165bccfe41SJohn Stultz tv.tv_sec = next_leap - 10; 2175bccfe41SJohn Stultz tv.tv_usec = 0; 2185bccfe41SJohn Stultz settimeofday(&tv, NULL); 2195bccfe41SJohn Stultz printf("Setting time to %s", ctime(&tv.tv_sec)); 2205bccfe41SJohn Stultz } 2215bccfe41SJohn Stultz 2225bccfe41SJohn Stultz /* Reset NTP time state */ 2235bccfe41SJohn Stultz clear_time_state(); 2245bccfe41SJohn Stultz 2255bccfe41SJohn Stultz /* Set the leap second insert flag */ 2265bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 2275bccfe41SJohn Stultz if (insert) 2285bccfe41SJohn Stultz tx.status = STA_INS; 2295bccfe41SJohn Stultz else 2305bccfe41SJohn Stultz tx.status = STA_DEL; 2315bccfe41SJohn Stultz ret = adjtimex(&tx); 2325bccfe41SJohn Stultz if (ret < 0) { 2335bccfe41SJohn Stultz printf("Error: Problem setting STA_INS/STA_DEL!: %s\n", 2345bccfe41SJohn Stultz time_state_str(ret)); 2355bccfe41SJohn Stultz return ksft_exit_fail(); 2365bccfe41SJohn Stultz } 2375bccfe41SJohn Stultz 2385bccfe41SJohn Stultz /* Validate STA_INS was set */ 2395bccfe41SJohn Stultz tx.modes = 0; 2405bccfe41SJohn Stultz ret = adjtimex(&tx); 2415bccfe41SJohn Stultz if (tx.status != STA_INS && tx.status != STA_DEL) { 2425bccfe41SJohn Stultz printf("Error: STA_INS/STA_DEL not set!: %s\n", 2435bccfe41SJohn Stultz time_state_str(ret)); 2445bccfe41SJohn Stultz return ksft_exit_fail(); 2455bccfe41SJohn Stultz } 2465bccfe41SJohn Stultz 2475bccfe41SJohn Stultz if (tai_time) { 2485bccfe41SJohn Stultz printf("Using TAI time," 2495bccfe41SJohn Stultz " no inconsistencies should be seen!\n"); 2505bccfe41SJohn Stultz } 2515bccfe41SJohn Stultz 2525bccfe41SJohn Stultz printf("Scheduling leap second for %s", ctime(&next_leap)); 2535bccfe41SJohn Stultz 2545bccfe41SJohn Stultz /* Wake up 3 seconds before leap */ 2555bccfe41SJohn Stultz ts.tv_sec = next_leap - 3; 2565bccfe41SJohn Stultz ts.tv_nsec = 0; 2575bccfe41SJohn Stultz 2585bccfe41SJohn Stultz while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, NULL)) 2595bccfe41SJohn Stultz printf("Something woke us up, returning to sleep\n"); 2605bccfe41SJohn Stultz 2615bccfe41SJohn Stultz /* Validate STA_INS is still set */ 2625bccfe41SJohn Stultz tx.modes = 0; 2635bccfe41SJohn Stultz ret = adjtimex(&tx); 2645bccfe41SJohn Stultz if (tx.status != STA_INS && tx.status != STA_DEL) { 2655bccfe41SJohn Stultz printf("Something cleared STA_INS/STA_DEL, setting it again.\n"); 2665bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 2675bccfe41SJohn Stultz if (insert) 2685bccfe41SJohn Stultz tx.status = STA_INS; 2695bccfe41SJohn Stultz else 2705bccfe41SJohn Stultz tx.status = STA_DEL; 2715bccfe41SJohn Stultz ret = adjtimex(&tx); 2725bccfe41SJohn Stultz } 2735bccfe41SJohn Stultz 2745bccfe41SJohn Stultz /* Check adjtimex output every half second */ 2755bccfe41SJohn Stultz now = tx.time.tv_sec; 2765bccfe41SJohn Stultz while (now < next_leap + 2) { 2775bccfe41SJohn Stultz char buf[26]; 2785bccfe41SJohn Stultz struct timespec tai; 2795bccfe41SJohn Stultz 2805bccfe41SJohn Stultz tx.modes = 0; 2815bccfe41SJohn Stultz ret = adjtimex(&tx); 2825bccfe41SJohn Stultz 2835bccfe41SJohn Stultz if (tai_time) { 2845bccfe41SJohn Stultz clock_gettime(CLOCK_TAI, &tai); 2855bccfe41SJohn Stultz printf("%ld sec, %9ld ns\t%s\n", 2865bccfe41SJohn Stultz tai.tv_sec, 2875bccfe41SJohn Stultz tai.tv_nsec, 2885bccfe41SJohn Stultz time_state_str(ret)); 2895bccfe41SJohn Stultz } else { 2905bccfe41SJohn Stultz ctime_r(&tx.time.tv_sec, buf); 2915bccfe41SJohn Stultz buf[strlen(buf)-1] = 0; /*remove trailing\n */ 2925bccfe41SJohn Stultz 2935bccfe41SJohn Stultz printf("%s + %6ld us (%i)\t%s\n", 2945bccfe41SJohn Stultz buf, 2955bccfe41SJohn Stultz tx.time.tv_usec, 2965bccfe41SJohn Stultz tx.tai, 2975bccfe41SJohn Stultz time_state_str(ret)); 2985bccfe41SJohn Stultz } 2995bccfe41SJohn Stultz now = tx.time.tv_sec; 3005bccfe41SJohn Stultz /* Sleep for another half second */ 3015bccfe41SJohn Stultz ts.tv_sec = 0; 3025bccfe41SJohn Stultz ts.tv_nsec = NSEC_PER_SEC / 2; 3035bccfe41SJohn Stultz clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); 3045bccfe41SJohn Stultz } 3055bccfe41SJohn Stultz /* Switch to using other mode */ 3065bccfe41SJohn Stultz insert = !insert; 3075bccfe41SJohn Stultz 3085bccfe41SJohn Stultz /* Note if kernel has known hrtimer failure */ 3095bccfe41SJohn Stultz test_hrtimer_failure(); 3105bccfe41SJohn Stultz 3115bccfe41SJohn Stultz printf("Leap complete\n\n"); 3125bccfe41SJohn Stultz 3135bccfe41SJohn Stultz if ((iterations != -1) && !(--iterations)) 3145bccfe41SJohn Stultz break; 3155bccfe41SJohn Stultz } 3165bccfe41SJohn Stultz 3175bccfe41SJohn Stultz clear_time_state(); 3185bccfe41SJohn Stultz return ksft_exit_pass(); 3195bccfe41SJohn Stultz } 320