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 struct timespec mono_end, elapsed, adjust;
46
47 if (!clock_saved)
48 return;
49
50 clock_saved = 0;
51
52 if (tst_clock_gettime(CLOCK_MONOTONIC_RAW, &mono_end))
53 tst_brk(TBROK | TERRNO, "tst_clock_gettime() monotonic failed");
54
55 elapsed = tst_timespec_diff(mono_end, mono_begin);
56
57 adjust = tst_timespec_add(real_begin, elapsed);
58
59 /* restore realtime clock based on monotonic delta */
60
61 if (tst_clock_settime(CLOCK_REALTIME, &adjust))
62 tst_brk(TBROK | TERRNO, "tst_clock_settime() realtime failed");
63 }
64
tst_rtc_clock_save(const char * rtc_dev)65 void tst_rtc_clock_save(const char *rtc_dev)
66 {
67 /* save initial monotonic time to restore it when needed */
68 if (tst_rtc_gettime(rtc_dev, &rtc_begin))
69 tst_brk(TBROK | TERRNO, "tst_rtc_gettime() realtime failed");
70
71 if (tst_clock_gettime(CLOCK_MONOTONIC_RAW, &mono_begin))
72 tst_brk(TBROK | TERRNO, "tst_clock_gettime() monotonic failed");
73
74 clock_saved = 1;
75 }
76
tst_rtc_clock_restore(const char * rtc_dev)77 void tst_rtc_clock_restore(const char *rtc_dev)
78 {
79 static struct timespec mono_end, elapsed;
80 static struct timespec rtc_begin_tm, rtc_adjust;
81 static struct rtc_time rtc_restore;
82
83 if (!clock_saved)
84 return;
85
86 clock_saved = 0;
87
88 if (tst_clock_gettime(CLOCK_MONOTONIC_RAW, &mono_end))
89 tst_brk(TBROK | TERRNO, "tst_clock_gettime() monotonic failed");
90
91 elapsed = tst_timespec_diff(mono_end, mono_begin);
92
93 rtc_begin_tm.tv_nsec = 0;
94 rtc_begin_tm.tv_sec = tst_rtc_tm_to_time(&rtc_begin);
95
96 rtc_adjust = tst_timespec_add(rtc_begin_tm, elapsed);
97
98 tst_rtc_time_to_tm(rtc_adjust.tv_sec, &rtc_restore);
99
100 /* restore realtime clock based on monotonic delta */
101 if (tst_rtc_settime(rtc_dev, &rtc_restore))
102 tst_brk(TBROK | TERRNO, "tst_rtc_settime() realtime failed");
103 }
104