33#include < abi-bits/clockid_t.h>
44#include < bits/ansi/timespec.h>
55#include < bits/ensure.h>
6+ #include < frg/safe_int.hpp>
67#include < mlibc/all-sysdeps.hpp>
78#include < mlibc/debug.hpp>
89#include < time.h>
@@ -16,7 +17,7 @@ inline bool time_absolute_to_relative(const clockid_t clock, const struct timesp
1617 constexpr long nanos_per_second = 1'000'000'000 ;
1718
1819 if (clock != CLOCK_REALTIME && clock != CLOCK_MONOTONIC ) {
19- mlibc::infoLogger () << " mlibc: time_relative_to_absolute () only supports CLOCK_REALTIME and CLOCK_MONOTONIC"
20+ mlibc::infoLogger () << " mlibc: time_absolute_to_relative () only supports CLOCK_REALTIME and CLOCK_MONOTONIC"
2021 << frg::endlog;
2122 return false ;
2223 }
@@ -25,8 +26,10 @@ inline bool time_absolute_to_relative(const clockid_t clock, const struct timesp
2526 if (mlibc::sysdep<ClockGet>(clock, &now.tv_sec , &now.tv_nsec ))
2627 __ensure (!" sys_clock_get() failed" );
2728
28- reltime->tv_sec = abstime->tv_sec - now.tv_sec ;
29- reltime->tv_nsec = abstime->tv_nsec - now.tv_nsec ;
29+ if (!frg::checked_sub (abstime->tv_sec , now.tv_sec , reltime->tv_sec ))
30+ return false ;
31+ if (!frg::checked_sub (abstime->tv_nsec , now.tv_nsec , reltime->tv_nsec ))
32+ return false ;
3033
3134 // Check if abstime has already passed.
3235 if (reltime->tv_sec < 0 || (reltime->tv_sec == 0 && reltime->tv_nsec < 0 )) {
@@ -35,17 +38,64 @@ inline bool time_absolute_to_relative(const clockid_t clock, const struct timesp
3538 return true ;
3639 } else if (reltime->tv_nsec >= nanos_per_second) {
3740 reltime->tv_nsec -= nanos_per_second;
38- reltime->tv_sec ++;
41+ if (!frg::checked_add (reltime->tv_sec , time_t {1 }, reltime->tv_sec ))
42+ return false ;
3943 if (reltime->tv_nsec >= nanos_per_second)
4044 return false ;
4145 } else if (reltime->tv_nsec < 0 ) {
4246 reltime->tv_nsec += nanos_per_second;
43- reltime->tv_sec --;
47+ if (!frg::checked_sub (reltime->tv_sec , time_t {1 }, reltime->tv_sec ))
48+ return false ;
4449 if (reltime->tv_nsec < 0 )
4550 return false ;
4651 }
4752
4853 return true ;
4954}
5055
56+ // Converts the relative time `reltime` to an absolute time `abstime`.
57+ // Returns false if the conversion failed (e.g. due to over-/underflow).
58+ inline bool time_relative_to_absolute (
59+ const clockid_t clock, const struct timespec *__restrict reltime, struct timespec *abstime
60+ ) {
61+ constexpr long nanos_per_second = 1'000'000'000 ;
62+
63+ if (clock != CLOCK_REALTIME && clock != CLOCK_MONOTONIC ) {
64+ mlibc::infoLogger ()
65+ << " mlibc: time_relative_to_absolute() only supports CLOCK_REALTIME and CLOCK_MONOTONIC"
66+ << frg::endlog;
67+ return false ;
68+ }
69+
70+ struct timespec now;
71+ if (mlibc::sysdep<ClockGet>(clock, &now.tv_sec , &now.tv_nsec ))
72+ __ensure (!" sys_clock_get() failed" );
73+
74+ // Add relative time to current time
75+ if (!frg::checked_add (now.tv_sec , reltime->tv_sec , abstime->tv_sec ))
76+ return false ;
77+ if (!frg::checked_add (now.tv_nsec , reltime->tv_nsec , abstime->tv_nsec ))
78+ return false ;
79+
80+ // Normalize nanoseconds
81+ if (abstime->tv_nsec >= nanos_per_second) {
82+ abstime->tv_nsec -= nanos_per_second;
83+ if (!frg::checked_add (abstime->tv_sec , time_t {1 }, abstime->tv_sec ))
84+ return false ;
85+ if (abstime->tv_nsec >= nanos_per_second)
86+ return false ;
87+ } else if (abstime->tv_nsec < 0 ) {
88+ abstime->tv_nsec += nanos_per_second;
89+ if (!frg::checked_sub (abstime->tv_sec , time_t {1 }, abstime->tv_sec ))
90+ return false ;
91+ if (abstime->tv_nsec < 0 )
92+ return false ;
93+ }
94+
95+ if (now.tv_sec > 0 && reltime->tv_sec > 0 && abstime->tv_sec < 0 )
96+ return false ;
97+
98+ return true ;
99+ }
100+
51101} // namespace mlibc
0 commit comments