leap-a-day.c 7.4 KB

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