162306a36Sopenharmony_ci/* Demo leapsecond deadlock 262306a36Sopenharmony_ci * by: John Stultz (john.stultz@linaro.org) 362306a36Sopenharmony_ci * (C) Copyright IBM 2012 462306a36Sopenharmony_ci * (C) Copyright 2013, 2015 Linaro Limited 562306a36Sopenharmony_ci * Licensed under the GPL 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This test demonstrates leapsecond deadlock that is possible 862306a36Sopenharmony_ci * on kernels from 2.6.26 to 3.3. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * WARNING: THIS WILL LIKELY HARD HANG SYSTEMS AND MAY LOSE DATA 1162306a36Sopenharmony_ci * RUN AT YOUR OWN RISK! 1262306a36Sopenharmony_ci * To build: 1362306a36Sopenharmony_ci * $ gcc leapcrash.c -o leapcrash -lrt 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <stdio.h> 1962306a36Sopenharmony_ci#include <stdlib.h> 2062306a36Sopenharmony_ci#include <time.h> 2162306a36Sopenharmony_ci#include <sys/time.h> 2262306a36Sopenharmony_ci#include <sys/timex.h> 2362306a36Sopenharmony_ci#include <string.h> 2462306a36Sopenharmony_ci#include <signal.h> 2562306a36Sopenharmony_ci#include "../kselftest.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* clear NTP time_status & time_state */ 2862306a36Sopenharmony_ciint clear_time_state(void) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct timex tx; 3162306a36Sopenharmony_ci int ret; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci /* 3462306a36Sopenharmony_ci * We have to call adjtime twice here, as kernels 3562306a36Sopenharmony_ci * prior to 6b1859dba01c7 (included in 3.5 and 3662306a36Sopenharmony_ci * -stable), had an issue with the state machine 3762306a36Sopenharmony_ci * and wouldn't clear the STA_INS/DEL flag directly. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci tx.modes = ADJ_STATUS; 4062306a36Sopenharmony_ci tx.status = STA_PLL; 4162306a36Sopenharmony_ci ret = adjtimex(&tx); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci tx.modes = ADJ_STATUS; 4462306a36Sopenharmony_ci tx.status = 0; 4562306a36Sopenharmony_ci ret = adjtimex(&tx); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return ret; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* Make sure we cleanup on ctrl-c */ 5162306a36Sopenharmony_civoid handler(int unused) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci clear_time_state(); 5462306a36Sopenharmony_ci exit(0); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ciint main(void) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct timex tx; 6162306a36Sopenharmony_ci struct timespec ts; 6262306a36Sopenharmony_ci time_t next_leap; 6362306a36Sopenharmony_ci int count = 0; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci setbuf(stdout, NULL); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci signal(SIGINT, handler); 6862306a36Sopenharmony_ci signal(SIGKILL, handler); 6962306a36Sopenharmony_ci printf("This runs for a few minutes. Press ctrl-c to stop\n"); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci clear_time_state(); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* Get the current time */ 7562306a36Sopenharmony_ci clock_gettime(CLOCK_REALTIME, &ts); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Calculate the next possible leap second 23:59:60 GMT */ 7862306a36Sopenharmony_ci next_leap = ts.tv_sec; 7962306a36Sopenharmony_ci next_leap += 86400 - (next_leap % 86400); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci for (count = 0; count < 20; count++) { 8262306a36Sopenharmony_ci struct timeval tv; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* set the time to 2 seconds before the leap */ 8662306a36Sopenharmony_ci tv.tv_sec = next_leap - 2; 8762306a36Sopenharmony_ci tv.tv_usec = 0; 8862306a36Sopenharmony_ci if (settimeofday(&tv, NULL)) { 8962306a36Sopenharmony_ci printf("Error: You're likely not running with proper (ie: root) permissions\n"); 9062306a36Sopenharmony_ci return ksft_exit_fail(); 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci tx.modes = 0; 9362306a36Sopenharmony_ci adjtimex(&tx); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* hammer on adjtime w/ STA_INS */ 9662306a36Sopenharmony_ci while (tx.time.tv_sec < next_leap + 1) { 9762306a36Sopenharmony_ci /* Set the leap second insert flag */ 9862306a36Sopenharmony_ci tx.modes = ADJ_STATUS; 9962306a36Sopenharmony_ci tx.status = STA_INS; 10062306a36Sopenharmony_ci adjtimex(&tx); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci clear_time_state(); 10362306a36Sopenharmony_ci printf("."); 10462306a36Sopenharmony_ci fflush(stdout); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci printf("[OK]\n"); 10762306a36Sopenharmony_ci return ksft_exit_pass(); 10862306a36Sopenharmony_ci} 109