• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2019 Linaro Limited. All rights reserved.
4  * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
5  */
6 
7 #include <errno.h>
8 
9 #define TST_NO_DEFAULT_MAIN
10 
11 #include "tst_test.h"
12 #include "tst_timer.h"
13 #include "tst_clocks.h"
14 #include "tst_rtctime.h"
15 #include "tst_wallclock.h"
16 #include "lapi/posix_clocks.h"
17 
18 static struct timespec real_begin, mono_begin;
19 
20 static struct rtc_time rtc_begin;
21 
22 static int clock_saved;
23 
tst_wallclock_save(void)24 void tst_wallclock_save(void)
25 {
26 	/* save initial monotonic time to restore it when needed */
27 
28 	if (tst_clock_gettime(CLOCK_REALTIME, &real_begin))
29 		tst_brk(TBROK | TERRNO, "tst_clock_gettime() realtime failed");
30 
31 	if (tst_clock_gettime(CLOCK_MONOTONIC_RAW, &mono_begin)) {
32 		if (errno == EINVAL) {
33 			tst_brk(TCONF | TERRNO,
34 				"tst_clock_gettime() didn't support CLOCK_MONOTONIC_RAW");
35 		}
36 
37 		tst_brk(TBROK | TERRNO, "tst_clock_gettime() monotonic failed");
38 	}
39 
40 	clock_saved = 1;
41 }
42 
tst_wallclock_restore(void)43 void tst_wallclock_restore(void)
44 {
45 	static const char *localtime = "/etc/localtime";
46 	static struct timespec mono_end, elapsed, adjust;
47 	int ret;
48 
49 	if (!clock_saved)
50 		return;
51 
52 	clock_saved = 0;
53 
54 	if (tst_clock_gettime(CLOCK_MONOTONIC_RAW, &mono_end))
55 		tst_brk(TBROK | TERRNO, "tst_clock_gettime() monotonic failed");
56 
57 	elapsed = tst_timespec_diff(mono_end, mono_begin);
58 
59 	adjust = tst_timespec_add(real_begin, elapsed);
60 
61 	/* restore realtime clock based on monotonic delta */
62 
63 	if (tst_clock_settime(CLOCK_REALTIME, &adjust))
64 		tst_brk(TBROK | TERRNO, "tst_clock_settime() realtime failed");
65 
66 	/*
67 	 * Fix access time of /etc/localtime because adjusting the wallclock
68 	 * might have changed it to a time value which lies far ahead
69 	 * in the future.
70 	 * The access time of a file only changes if the new one is past
71 	 * the current one, therefore, just opening a file and reading it
72 	 * might not be enough because the current access time might be far
73 	 * in the future.
74 	 */
75 	ret = access(localtime, F_OK | W_OK);
76 	if (!ret)
77 		SAFE_TOUCH(localtime, 0, NULL);
78 }
79 
tst_rtc_clock_save(const char * rtc_dev)80 void tst_rtc_clock_save(const char *rtc_dev)
81 {
82 	/* save initial monotonic time to restore it when needed */
83 	if (tst_rtc_gettime(rtc_dev, &rtc_begin))
84 		tst_brk(TBROK | TERRNO, "tst_rtc_gettime() realtime failed");
85 
86 	if (tst_clock_gettime(CLOCK_MONOTONIC_RAW, &mono_begin))
87 		tst_brk(TBROK | TERRNO, "tst_clock_gettime() monotonic failed");
88 
89 	clock_saved = 1;
90 }
91 
tst_rtc_clock_restore(const char * rtc_dev)92 void tst_rtc_clock_restore(const char *rtc_dev)
93 {
94 	static struct timespec mono_end, elapsed;
95 	static struct timespec rtc_begin_tm, rtc_adjust;
96 	static struct rtc_time rtc_restore;
97 
98 	if (!clock_saved)
99 		return;
100 
101 	clock_saved = 0;
102 
103 	if (tst_clock_gettime(CLOCK_MONOTONIC_RAW, &mono_end))
104 		tst_brk(TBROK | TERRNO, "tst_clock_gettime() monotonic failed");
105 
106 	elapsed = tst_timespec_diff(mono_end, mono_begin);
107 
108 	rtc_begin_tm.tv_nsec = 0;
109 	rtc_begin_tm.tv_sec = tst_rtc_tm_to_time(&rtc_begin);
110 
111 	rtc_adjust = tst_timespec_add(rtc_begin_tm, elapsed);
112 
113 	tst_rtc_time_to_tm(rtc_adjust.tv_sec, &rtc_restore);
114 
115 	/* restore realtime clock based on monotonic delta */
116 	if (tst_rtc_settime(rtc_dev, &rtc_restore))
117 		tst_brk(TBROK | TERRNO, "tst_rtc_settime() realtime failed");
118 }
119