1*5bccfe41SJohn Stultz /* Leap second stress test 2*5bccfe41SJohn Stultz * by: John Stultz (john.stultz@linaro.org) 3*5bccfe41SJohn Stultz * (C) Copyright IBM 2012 4*5bccfe41SJohn Stultz * (C) Copyright 2013, 2015 Linaro Limited 5*5bccfe41SJohn Stultz * Licensed under the GPLv2 6*5bccfe41SJohn Stultz * 7*5bccfe41SJohn Stultz * This test signals the kernel to insert a leap second 8*5bccfe41SJohn Stultz * every day at midnight GMT. This allows for stessing the 9*5bccfe41SJohn Stultz * kernel's leap-second behavior, as well as how well applications 10*5bccfe41SJohn Stultz * handle the leap-second discontinuity. 11*5bccfe41SJohn Stultz * 12*5bccfe41SJohn Stultz * Usage: leap-a-day [-s] [-i <num>] 13*5bccfe41SJohn Stultz * 14*5bccfe41SJohn Stultz * Options: 15*5bccfe41SJohn Stultz * -s: Each iteration, set the date to 10 seconds before midnight GMT. 16*5bccfe41SJohn Stultz * This speeds up the number of leapsecond transitions tested, 17*5bccfe41SJohn Stultz * but because it calls settimeofday frequently, advancing the 18*5bccfe41SJohn Stultz * time by 24 hours every ~16 seconds, it may cause application 19*5bccfe41SJohn Stultz * disruption. 20*5bccfe41SJohn Stultz * 21*5bccfe41SJohn Stultz * -i: Number of iterations to run (default: infinite) 22*5bccfe41SJohn Stultz * 23*5bccfe41SJohn Stultz * Other notes: Disabling NTP prior to running this is advised, as the two 24*5bccfe41SJohn Stultz * may conflict in their commands to the kernel. 25*5bccfe41SJohn Stultz * 26*5bccfe41SJohn Stultz * To build: 27*5bccfe41SJohn Stultz * $ gcc leap-a-day.c -o leap-a-day -lrt 28*5bccfe41SJohn Stultz * 29*5bccfe41SJohn Stultz * This program is free software: you can redistribute it and/or modify 30*5bccfe41SJohn Stultz * it under the terms of the GNU General Public License as published by 31*5bccfe41SJohn Stultz * the Free Software Foundation, either version 2 of the License, or 32*5bccfe41SJohn Stultz * (at your option) any later version. 33*5bccfe41SJohn Stultz * 34*5bccfe41SJohn Stultz * This program is distributed in the hope that it will be useful, 35*5bccfe41SJohn Stultz * but WITHOUT ANY WARRANTY; without even the implied warranty of 36*5bccfe41SJohn Stultz * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37*5bccfe41SJohn Stultz * GNU General Public License for more details. 38*5bccfe41SJohn Stultz */ 39*5bccfe41SJohn Stultz 40*5bccfe41SJohn Stultz 41*5bccfe41SJohn Stultz 42*5bccfe41SJohn Stultz #include <stdio.h> 43*5bccfe41SJohn Stultz #include <stdlib.h> 44*5bccfe41SJohn Stultz #include <time.h> 45*5bccfe41SJohn Stultz #include <sys/time.h> 46*5bccfe41SJohn Stultz #include <sys/timex.h> 47*5bccfe41SJohn Stultz #include <string.h> 48*5bccfe41SJohn Stultz #include <signal.h> 49*5bccfe41SJohn Stultz #include <unistd.h> 50*5bccfe41SJohn Stultz #ifdef KTEST 51*5bccfe41SJohn Stultz #include "../kselftest.h" 52*5bccfe41SJohn Stultz #else 53*5bccfe41SJohn Stultz static inline int ksft_exit_pass(void) 54*5bccfe41SJohn Stultz { 55*5bccfe41SJohn Stultz exit(0); 56*5bccfe41SJohn Stultz } 57*5bccfe41SJohn Stultz static inline int ksft_exit_fail(void) 58*5bccfe41SJohn Stultz { 59*5bccfe41SJohn Stultz exit(1); 60*5bccfe41SJohn Stultz } 61*5bccfe41SJohn Stultz #endif 62*5bccfe41SJohn Stultz 63*5bccfe41SJohn Stultz #define NSEC_PER_SEC 1000000000ULL 64*5bccfe41SJohn Stultz #define CLOCK_TAI 11 65*5bccfe41SJohn Stultz 66*5bccfe41SJohn Stultz /* returns 1 if a <= b, 0 otherwise */ 67*5bccfe41SJohn Stultz static inline int in_order(struct timespec a, struct timespec b) 68*5bccfe41SJohn Stultz { 69*5bccfe41SJohn Stultz if (a.tv_sec < b.tv_sec) 70*5bccfe41SJohn Stultz return 1; 71*5bccfe41SJohn Stultz if (a.tv_sec > b.tv_sec) 72*5bccfe41SJohn Stultz return 0; 73*5bccfe41SJohn Stultz if (a.tv_nsec > b.tv_nsec) 74*5bccfe41SJohn Stultz return 0; 75*5bccfe41SJohn Stultz return 1; 76*5bccfe41SJohn Stultz } 77*5bccfe41SJohn Stultz 78*5bccfe41SJohn Stultz struct timespec timespec_add(struct timespec ts, unsigned long long ns) 79*5bccfe41SJohn Stultz { 80*5bccfe41SJohn Stultz ts.tv_nsec += ns; 81*5bccfe41SJohn Stultz while (ts.tv_nsec >= NSEC_PER_SEC) { 82*5bccfe41SJohn Stultz ts.tv_nsec -= NSEC_PER_SEC; 83*5bccfe41SJohn Stultz ts.tv_sec++; 84*5bccfe41SJohn Stultz } 85*5bccfe41SJohn Stultz return ts; 86*5bccfe41SJohn Stultz } 87*5bccfe41SJohn Stultz 88*5bccfe41SJohn Stultz char *time_state_str(int state) 89*5bccfe41SJohn Stultz { 90*5bccfe41SJohn Stultz switch (state) { 91*5bccfe41SJohn Stultz case TIME_OK: return "TIME_OK"; 92*5bccfe41SJohn Stultz case TIME_INS: return "TIME_INS"; 93*5bccfe41SJohn Stultz case TIME_DEL: return "TIME_DEL"; 94*5bccfe41SJohn Stultz case TIME_OOP: return "TIME_OOP"; 95*5bccfe41SJohn Stultz case TIME_WAIT: return "TIME_WAIT"; 96*5bccfe41SJohn Stultz case TIME_BAD: return "TIME_BAD"; 97*5bccfe41SJohn Stultz } 98*5bccfe41SJohn Stultz return "ERROR"; 99*5bccfe41SJohn Stultz } 100*5bccfe41SJohn Stultz 101*5bccfe41SJohn Stultz /* clear NTP time_status & time_state */ 102*5bccfe41SJohn Stultz int clear_time_state(void) 103*5bccfe41SJohn Stultz { 104*5bccfe41SJohn Stultz struct timex tx; 105*5bccfe41SJohn Stultz int ret; 106*5bccfe41SJohn Stultz 107*5bccfe41SJohn Stultz /* 108*5bccfe41SJohn Stultz * We have to call adjtime twice here, as kernels 109*5bccfe41SJohn Stultz * prior to 6b1859dba01c7 (included in 3.5 and 110*5bccfe41SJohn Stultz * -stable), had an issue with the state machine 111*5bccfe41SJohn Stultz * and wouldn't clear the STA_INS/DEL flag directly. 112*5bccfe41SJohn Stultz */ 113*5bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 114*5bccfe41SJohn Stultz tx.status = STA_PLL; 115*5bccfe41SJohn Stultz ret = adjtimex(&tx); 116*5bccfe41SJohn Stultz 117*5bccfe41SJohn Stultz /* Clear maxerror, as it can cause UNSYNC to be set */ 118*5bccfe41SJohn Stultz tx.modes = ADJ_MAXERROR; 119*5bccfe41SJohn Stultz tx.maxerror = 0; 120*5bccfe41SJohn Stultz ret = adjtimex(&tx); 121*5bccfe41SJohn Stultz 122*5bccfe41SJohn Stultz /* Clear the status */ 123*5bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 124*5bccfe41SJohn Stultz tx.status = 0; 125*5bccfe41SJohn Stultz ret = adjtimex(&tx); 126*5bccfe41SJohn Stultz 127*5bccfe41SJohn Stultz return ret; 128*5bccfe41SJohn Stultz } 129*5bccfe41SJohn Stultz 130*5bccfe41SJohn Stultz /* Make sure we cleanup on ctrl-c */ 131*5bccfe41SJohn Stultz void handler(int unused) 132*5bccfe41SJohn Stultz { 133*5bccfe41SJohn Stultz clear_time_state(); 134*5bccfe41SJohn Stultz exit(0); 135*5bccfe41SJohn Stultz } 136*5bccfe41SJohn Stultz 137*5bccfe41SJohn Stultz /* Test for known hrtimer failure */ 138*5bccfe41SJohn Stultz void test_hrtimer_failure(void) 139*5bccfe41SJohn Stultz { 140*5bccfe41SJohn Stultz struct timespec now, target; 141*5bccfe41SJohn Stultz 142*5bccfe41SJohn Stultz clock_gettime(CLOCK_REALTIME, &now); 143*5bccfe41SJohn Stultz target = timespec_add(now, NSEC_PER_SEC/2); 144*5bccfe41SJohn Stultz clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &target, NULL); 145*5bccfe41SJohn Stultz clock_gettime(CLOCK_REALTIME, &now); 146*5bccfe41SJohn Stultz 147*5bccfe41SJohn Stultz if (!in_order(target, now)) 148*5bccfe41SJohn Stultz printf("ERROR: hrtimer early expiration failure observed.\n"); 149*5bccfe41SJohn Stultz } 150*5bccfe41SJohn Stultz 151*5bccfe41SJohn Stultz int main(int argc, char **argv) 152*5bccfe41SJohn Stultz { 153*5bccfe41SJohn Stultz int settime = 0; 154*5bccfe41SJohn Stultz int tai_time = 0; 155*5bccfe41SJohn Stultz int insert = 1; 156*5bccfe41SJohn Stultz int iterations = -1; 157*5bccfe41SJohn Stultz int opt; 158*5bccfe41SJohn Stultz 159*5bccfe41SJohn Stultz /* Process arguments */ 160*5bccfe41SJohn Stultz while ((opt = getopt(argc, argv, "sti:")) != -1) { 161*5bccfe41SJohn Stultz switch (opt) { 162*5bccfe41SJohn Stultz case 's': 163*5bccfe41SJohn Stultz printf("Setting time to speed up testing\n"); 164*5bccfe41SJohn Stultz settime = 1; 165*5bccfe41SJohn Stultz break; 166*5bccfe41SJohn Stultz case 'i': 167*5bccfe41SJohn Stultz iterations = atoi(optarg); 168*5bccfe41SJohn Stultz break; 169*5bccfe41SJohn Stultz case 't': 170*5bccfe41SJohn Stultz tai_time = 1; 171*5bccfe41SJohn Stultz break; 172*5bccfe41SJohn Stultz default: 173*5bccfe41SJohn Stultz printf("Usage: %s [-s] [-i <iterations>]\n", argv[0]); 174*5bccfe41SJohn Stultz printf(" -s: Set time to right before leap second each iteration\n"); 175*5bccfe41SJohn Stultz printf(" -i: Number of iterations\n"); 176*5bccfe41SJohn Stultz printf(" -t: Print TAI time\n"); 177*5bccfe41SJohn Stultz exit(-1); 178*5bccfe41SJohn Stultz } 179*5bccfe41SJohn Stultz } 180*5bccfe41SJohn Stultz 181*5bccfe41SJohn Stultz /* Make sure TAI support is present if -t was used */ 182*5bccfe41SJohn Stultz if (tai_time) { 183*5bccfe41SJohn Stultz struct timespec ts; 184*5bccfe41SJohn Stultz 185*5bccfe41SJohn Stultz if (clock_gettime(CLOCK_TAI, &ts)) { 186*5bccfe41SJohn Stultz printf("System doesn't support CLOCK_TAI\n"); 187*5bccfe41SJohn Stultz ksft_exit_fail(); 188*5bccfe41SJohn Stultz } 189*5bccfe41SJohn Stultz } 190*5bccfe41SJohn Stultz 191*5bccfe41SJohn Stultz signal(SIGINT, handler); 192*5bccfe41SJohn Stultz signal(SIGKILL, handler); 193*5bccfe41SJohn Stultz 194*5bccfe41SJohn Stultz if (iterations < 0) 195*5bccfe41SJohn Stultz printf("This runs continuously. Press ctrl-c to stop\n"); 196*5bccfe41SJohn Stultz else 197*5bccfe41SJohn Stultz printf("Running for %i iterations. Press ctrl-c to stop\n", iterations); 198*5bccfe41SJohn Stultz 199*5bccfe41SJohn Stultz printf("\n"); 200*5bccfe41SJohn Stultz while (1) { 201*5bccfe41SJohn Stultz int ret; 202*5bccfe41SJohn Stultz struct timespec ts; 203*5bccfe41SJohn Stultz struct timex tx; 204*5bccfe41SJohn Stultz time_t now, next_leap; 205*5bccfe41SJohn Stultz 206*5bccfe41SJohn Stultz /* Get the current time */ 207*5bccfe41SJohn Stultz clock_gettime(CLOCK_REALTIME, &ts); 208*5bccfe41SJohn Stultz 209*5bccfe41SJohn Stultz /* Calculate the next possible leap second 23:59:60 GMT */ 210*5bccfe41SJohn Stultz next_leap = ts.tv_sec; 211*5bccfe41SJohn Stultz next_leap += 86400 - (next_leap % 86400); 212*5bccfe41SJohn Stultz 213*5bccfe41SJohn Stultz if (settime) { 214*5bccfe41SJohn Stultz struct timeval tv; 215*5bccfe41SJohn Stultz 216*5bccfe41SJohn Stultz tv.tv_sec = next_leap - 10; 217*5bccfe41SJohn Stultz tv.tv_usec = 0; 218*5bccfe41SJohn Stultz settimeofday(&tv, NULL); 219*5bccfe41SJohn Stultz printf("Setting time to %s", ctime(&tv.tv_sec)); 220*5bccfe41SJohn Stultz } 221*5bccfe41SJohn Stultz 222*5bccfe41SJohn Stultz /* Reset NTP time state */ 223*5bccfe41SJohn Stultz clear_time_state(); 224*5bccfe41SJohn Stultz 225*5bccfe41SJohn Stultz /* Set the leap second insert flag */ 226*5bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 227*5bccfe41SJohn Stultz if (insert) 228*5bccfe41SJohn Stultz tx.status = STA_INS; 229*5bccfe41SJohn Stultz else 230*5bccfe41SJohn Stultz tx.status = STA_DEL; 231*5bccfe41SJohn Stultz ret = adjtimex(&tx); 232*5bccfe41SJohn Stultz if (ret < 0) { 233*5bccfe41SJohn Stultz printf("Error: Problem setting STA_INS/STA_DEL!: %s\n", 234*5bccfe41SJohn Stultz time_state_str(ret)); 235*5bccfe41SJohn Stultz return ksft_exit_fail(); 236*5bccfe41SJohn Stultz } 237*5bccfe41SJohn Stultz 238*5bccfe41SJohn Stultz /* Validate STA_INS was set */ 239*5bccfe41SJohn Stultz tx.modes = 0; 240*5bccfe41SJohn Stultz ret = adjtimex(&tx); 241*5bccfe41SJohn Stultz if (tx.status != STA_INS && tx.status != STA_DEL) { 242*5bccfe41SJohn Stultz printf("Error: STA_INS/STA_DEL not set!: %s\n", 243*5bccfe41SJohn Stultz time_state_str(ret)); 244*5bccfe41SJohn Stultz return ksft_exit_fail(); 245*5bccfe41SJohn Stultz } 246*5bccfe41SJohn Stultz 247*5bccfe41SJohn Stultz if (tai_time) { 248*5bccfe41SJohn Stultz printf("Using TAI time," 249*5bccfe41SJohn Stultz " no inconsistencies should be seen!\n"); 250*5bccfe41SJohn Stultz } 251*5bccfe41SJohn Stultz 252*5bccfe41SJohn Stultz printf("Scheduling leap second for %s", ctime(&next_leap)); 253*5bccfe41SJohn Stultz 254*5bccfe41SJohn Stultz /* Wake up 3 seconds before leap */ 255*5bccfe41SJohn Stultz ts.tv_sec = next_leap - 3; 256*5bccfe41SJohn Stultz ts.tv_nsec = 0; 257*5bccfe41SJohn Stultz 258*5bccfe41SJohn Stultz while (clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &ts, NULL)) 259*5bccfe41SJohn Stultz printf("Something woke us up, returning to sleep\n"); 260*5bccfe41SJohn Stultz 261*5bccfe41SJohn Stultz /* Validate STA_INS is still set */ 262*5bccfe41SJohn Stultz tx.modes = 0; 263*5bccfe41SJohn Stultz ret = adjtimex(&tx); 264*5bccfe41SJohn Stultz if (tx.status != STA_INS && tx.status != STA_DEL) { 265*5bccfe41SJohn Stultz printf("Something cleared STA_INS/STA_DEL, setting it again.\n"); 266*5bccfe41SJohn Stultz tx.modes = ADJ_STATUS; 267*5bccfe41SJohn Stultz if (insert) 268*5bccfe41SJohn Stultz tx.status = STA_INS; 269*5bccfe41SJohn Stultz else 270*5bccfe41SJohn Stultz tx.status = STA_DEL; 271*5bccfe41SJohn Stultz ret = adjtimex(&tx); 272*5bccfe41SJohn Stultz } 273*5bccfe41SJohn Stultz 274*5bccfe41SJohn Stultz /* Check adjtimex output every half second */ 275*5bccfe41SJohn Stultz now = tx.time.tv_sec; 276*5bccfe41SJohn Stultz while (now < next_leap + 2) { 277*5bccfe41SJohn Stultz char buf[26]; 278*5bccfe41SJohn Stultz struct timespec tai; 279*5bccfe41SJohn Stultz 280*5bccfe41SJohn Stultz tx.modes = 0; 281*5bccfe41SJohn Stultz ret = adjtimex(&tx); 282*5bccfe41SJohn Stultz 283*5bccfe41SJohn Stultz if (tai_time) { 284*5bccfe41SJohn Stultz clock_gettime(CLOCK_TAI, &tai); 285*5bccfe41SJohn Stultz printf("%ld sec, %9ld ns\t%s\n", 286*5bccfe41SJohn Stultz tai.tv_sec, 287*5bccfe41SJohn Stultz tai.tv_nsec, 288*5bccfe41SJohn Stultz time_state_str(ret)); 289*5bccfe41SJohn Stultz } else { 290*5bccfe41SJohn Stultz ctime_r(&tx.time.tv_sec, buf); 291*5bccfe41SJohn Stultz buf[strlen(buf)-1] = 0; /*remove trailing\n */ 292*5bccfe41SJohn Stultz 293*5bccfe41SJohn Stultz printf("%s + %6ld us (%i)\t%s\n", 294*5bccfe41SJohn Stultz buf, 295*5bccfe41SJohn Stultz tx.time.tv_usec, 296*5bccfe41SJohn Stultz tx.tai, 297*5bccfe41SJohn Stultz time_state_str(ret)); 298*5bccfe41SJohn Stultz } 299*5bccfe41SJohn Stultz now = tx.time.tv_sec; 300*5bccfe41SJohn Stultz /* Sleep for another half second */ 301*5bccfe41SJohn Stultz ts.tv_sec = 0; 302*5bccfe41SJohn Stultz ts.tv_nsec = NSEC_PER_SEC / 2; 303*5bccfe41SJohn Stultz clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); 304*5bccfe41SJohn Stultz } 305*5bccfe41SJohn Stultz /* Switch to using other mode */ 306*5bccfe41SJohn Stultz insert = !insert; 307*5bccfe41SJohn Stultz 308*5bccfe41SJohn Stultz /* Note if kernel has known hrtimer failure */ 309*5bccfe41SJohn Stultz test_hrtimer_failure(); 310*5bccfe41SJohn Stultz 311*5bccfe41SJohn Stultz printf("Leap complete\n\n"); 312*5bccfe41SJohn Stultz 313*5bccfe41SJohn Stultz if ((iterations != -1) && !(--iterations)) 314*5bccfe41SJohn Stultz break; 315*5bccfe41SJohn Stultz } 316*5bccfe41SJohn Stultz 317*5bccfe41SJohn Stultz clear_time_state(); 318*5bccfe41SJohn Stultz return ksft_exit_pass(); 319*5bccfe41SJohn Stultz } 320