]>
Commit | Line | Data |
---|---|---|
d7b2902c JS |
1 | /* Demo leapsecond deadlock |
2 | * by: John Stultz (john.stultz@linaro.org) | |
3 | * (C) Copyright IBM 2012 | |
4 | * (C) Copyright 2013, 2015 Linaro Limited | |
5 | * Licensed under the GPL | |
6 | * | |
7 | * This test demonstrates leapsecond deadlock that is possibe | |
8 | * on kernels from 2.6.26 to 3.3. | |
9 | * | |
10 | * WARNING: THIS WILL LIKELY HARDHANG SYSTEMS AND MAY LOSE DATA | |
11 | * RUN AT YOUR OWN RISK! | |
12 | * To build: | |
13 | * $ gcc leapcrash.c -o leapcrash -lrt | |
14 | */ | |
15 | ||
16 | ||
17 | ||
18 | #include <stdio.h> | |
19 | #include <stdlib.h> | |
20 | #include <time.h> | |
21 | #include <sys/time.h> | |
22 | #include <sys/timex.h> | |
23 | #include <string.h> | |
24 | #include <signal.h> | |
25 | #ifdef KTEST | |
26 | #include "../kselftest.h" | |
27 | #else | |
28 | static inline int ksft_exit_pass(void) | |
29 | { | |
30 | exit(0); | |
31 | } | |
32 | static inline int ksft_exit_fail(void) | |
33 | { | |
34 | exit(1); | |
35 | } | |
36 | #endif | |
37 | ||
38 | ||
39 | ||
40 | /* clear NTP time_status & time_state */ | |
41 | int clear_time_state(void) | |
42 | { | |
43 | struct timex tx; | |
44 | int ret; | |
45 | ||
46 | /* | |
47 | * We have to call adjtime twice here, as kernels | |
48 | * prior to 6b1859dba01c7 (included in 3.5 and | |
49 | * -stable), had an issue with the state machine | |
50 | * and wouldn't clear the STA_INS/DEL flag directly. | |
51 | */ | |
52 | tx.modes = ADJ_STATUS; | |
53 | tx.status = STA_PLL; | |
54 | ret = adjtimex(&tx); | |
55 | ||
56 | tx.modes = ADJ_STATUS; | |
57 | tx.status = 0; | |
58 | ret = adjtimex(&tx); | |
59 | ||
60 | return ret; | |
61 | } | |
62 | ||
63 | /* Make sure we cleanup on ctrl-c */ | |
64 | void handler(int unused) | |
65 | { | |
66 | clear_time_state(); | |
67 | exit(0); | |
68 | } | |
69 | ||
70 | ||
71 | int main(void) | |
72 | { | |
73 | struct timex tx; | |
74 | struct timespec ts; | |
75 | time_t next_leap; | |
76 | int count = 0; | |
77 | ||
78 | setbuf(stdout, NULL); | |
79 | ||
80 | signal(SIGINT, handler); | |
81 | signal(SIGKILL, handler); | |
82 | printf("This runs for a few minutes. Press ctrl-c to stop\n"); | |
83 | ||
84 | clear_time_state(); | |
85 | ||
86 | ||
87 | /* Get the current time */ | |
88 | clock_gettime(CLOCK_REALTIME, &ts); | |
89 | ||
90 | /* Calculate the next possible leap second 23:59:60 GMT */ | |
91 | next_leap = ts.tv_sec; | |
92 | next_leap += 86400 - (next_leap % 86400); | |
93 | ||
94 | for (count = 0; count < 20; count++) { | |
95 | struct timeval tv; | |
96 | ||
97 | ||
98 | /* set the time to 2 seconds before the leap */ | |
99 | tv.tv_sec = next_leap - 2; | |
100 | tv.tv_usec = 0; | |
101 | if (settimeofday(&tv, NULL)) { | |
102 | printf("Error: You're likely not running with proper (ie: root) permissions\n"); | |
103 | return ksft_exit_fail(); | |
104 | } | |
105 | tx.modes = 0; | |
106 | adjtimex(&tx); | |
107 | ||
108 | /* hammer on adjtime w/ STA_INS */ | |
109 | while (tx.time.tv_sec < next_leap + 1) { | |
110 | /* Set the leap second insert flag */ | |
111 | tx.modes = ADJ_STATUS; | |
112 | tx.status = STA_INS; | |
113 | adjtimex(&tx); | |
114 | } | |
115 | clear_time_state(); | |
116 | printf("."); | |
117 | } | |
118 | printf("[OK]\n"); | |
119 | return ksft_exit_pass(); | |
120 | } |