Skip to content

Commit bba04cf

Browse files
Add rcutils_raw_steady_time_now method for slew-free clock (ros2#507) (ros2#513)
(cherry picked from commit 89264ce) Signed-off-by: Sai Kishor Kothakota <sai.kishor@pal-robotics.com> Co-authored-by: Sai Kishor Kothakota <saisastra3@gmail.com>
1 parent 0bd3cd7 commit bba04cf

5 files changed

Lines changed: 114 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ The API is a combination of parts:
5454
- Portable implementations of "get system time" and "get steady time":
5555
- rcutils_system_time_now()
5656
- rcutils_steady_time_now()
57+
- rcutils_raw_steady_time_now()
5758
- rcutils/time.h
5859
- Some useful data structures:
5960
- A "string array" data structure (analogous to `std::vector<std::string>`):

include/rcutils/time.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,33 @@ RCUTILS_WARN_UNUSED
104104
rcutils_ret_t
105105
rcutils_steady_time_now(rcutils_time_point_value_t * now);
106106

107+
/// Retrieve the current time as a rcutils_time_point_value_t object.
108+
/**
109+
* This function returns the time from a monotonically increasing slew-free clock.
110+
*
111+
* The resolution (e.g. nanoseconds vs microseconds) is not guaranteed.
112+
*
113+
* The now argument must point to an allocated rcutils_time_point_value_t object,
114+
* as the result is copied into this variable.
115+
*
116+
* <hr>
117+
* Attribute | Adherence
118+
* ------------------ | -------------
119+
* Allocates Memory | No
120+
* Thread-Safe | Yes
121+
* Uses Atomics | No
122+
* Lock-Free | Yes
123+
*
124+
* \param[out] now a struct in which the current time is stored
125+
* \return #RCUTILS_RET_OK if the current time was successfully obtained, or
126+
* \return #RCUTILS_RET_INVALID_ARGUMENT if any arguments are invalid, or
127+
* \return #RCUTILS_RET_ERROR if an unspecified error occur.
128+
*/
129+
RCUTILS_PUBLIC
130+
RCUTILS_WARN_UNUSED
131+
rcutils_ret_t
132+
rcutils_raw_steady_time_now(rcutils_time_point_value_t * now);
133+
107134
/// Return a time point as nanoseconds in a string.
108135
/**
109136
* The number is always fixed width, with left padding zeros up to the maximum

src/time_unix.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# error time_unix.c is not intended to be used with win32 based systems
1717
#endif // defined(_WIN32)
1818

19+
#include "rcutils/logging_macros.h"
1920
#include "rcutils/time.h"
2021

2122
#if defined(__MACH__) && defined(__APPLE__)
@@ -98,3 +99,30 @@ rcutils_steady_time_now(rcutils_time_point_value_t * now)
9899
*now = RCUTILS_S_TO_NS((int64_t)timespec_now.tv_sec) + timespec_now.tv_nsec;
99100
return RCUTILS_RET_OK;
100101
}
102+
103+
rcutils_ret_t
104+
rcutils_raw_steady_time_now(rcutils_time_point_value_t * now)
105+
{
106+
RCUTILS_CHECK_ARGUMENT_FOR_NULL(now, RCUTILS_RET_INVALID_ARGUMENT);
107+
struct timespec timespec_now;
108+
109+
#if defined(CLOCK_MONOTONIC_RAW)
110+
clockid_t monotonic_raw_clock = CLOCK_MONOTONIC_RAW;
111+
#else
112+
clockid_t monotonic_raw_clock = CLOCK_MONOTONIC;
113+
RCUTILS_LOG_WARN_ONCE(
114+
"CLOCK_MONOTONIC_RAW is not supported by the platform, using CLOCK_MONOTONIC "
115+
"instead. This may not provide the desired raw steady time behavior.");
116+
#endif
117+
118+
if (clock_gettime(monotonic_raw_clock, &timespec_now) < 0) {
119+
RCUTILS_SET_ERROR_MSG_WITH_FORMAT_STRING("Failed to get raw steady time: %d", errno);
120+
return RCUTILS_RET_ERROR;
121+
}
122+
if (would_be_negative(&timespec_now)) {
123+
RCUTILS_SET_ERROR_MSG("unexpected negative time");
124+
return RCUTILS_RET_ERROR;
125+
}
126+
*now = RCUTILS_S_TO_NS((int64_t)timespec_now.tv_sec) + timespec_now.tv_nsec;
127+
return RCUTILS_RET_OK;
128+
}

src/time_win32.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ rcutils_steady_time_now(rcutils_time_point_value_t * now)
8484
return RCUTILS_RET_OK;
8585
}
8686

87+
rcutils_ret_t
88+
rcutils_raw_steady_time_now(rcutils_time_point_value_t * now)
89+
{
90+
// On Windows, there is no difference between steady and raw steady time.
91+
// The QueryPerformanceCounter function provides a high-resolution timer
92+
// that is not affected by system clock changes.
93+
return rcutils_steady_time_now(now);
94+
}
95+
8796
#ifdef __cplusplus
8897
}
8998
#endif

test/test_time.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,47 @@ TEST_F(TestTimeFixture, test_rcutils_steady_time_now) {
191191
llabs(steady_diff - sc_diff), RCUTILS_MS_TO_NS(k_tolerance_ms)) << "steady_clock differs";
192192
}
193193

194+
// Tests the rcutils_raw_steady_time_now() function.
195+
TEST_F(TestTimeFixture, test_rcutils_raw_steady_time_now) {
196+
rcutils_ret_t ret;
197+
// Check for invalid argument error condition (allowed to alloc).
198+
ret = rcutils_raw_steady_time_now(nullptr);
199+
EXPECT_EQ(ret, RCUTILS_RET_INVALID_ARGUMENT) << rcutils_get_error_string().str;
200+
rcutils_reset_error();
201+
// Check for normal operation (not allowed to alloc).
202+
rcutils_time_point_value_t now = 0;
203+
EXPECT_NO_MEMORY_OPERATIONS(
204+
{
205+
ret = rcutils_raw_steady_time_now(&now);
206+
});
207+
EXPECT_EQ(ret, RCUTILS_RET_OK) << rcutils_get_error_string().str;
208+
EXPECT_NE(0u, now);
209+
// Compare to std::chrono::steady_clock difference of two times (within a second).
210+
now = 0;
211+
EXPECT_NO_MEMORY_OPERATIONS(
212+
{
213+
ret = rcutils_raw_steady_time_now(&now);
214+
});
215+
std::chrono::steady_clock::time_point now_sc = std::chrono::steady_clock::now();
216+
EXPECT_EQ(ret, RCUTILS_RET_OK) << rcutils_get_error_string().str;
217+
// Wait for a little while.
218+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
219+
// Then take a new timestamp with each and compare.
220+
rcutils_time_point_value_t later;
221+
EXPECT_NO_MEMORY_OPERATIONS(
222+
{
223+
ret = rcutils_raw_steady_time_now(&later);
224+
});
225+
std::chrono::steady_clock::time_point later_sc = std::chrono::steady_clock::now();
226+
EXPECT_EQ(ret, RCUTILS_RET_OK) << rcutils_get_error_string().str;
227+
int64_t steady_diff = later - now;
228+
int64_t sc_diff =
229+
std::chrono::duration_cast<std::chrono::nanoseconds>(later_sc - now_sc).count();
230+
const int k_tolerance_ms = 1;
231+
EXPECT_LE(
232+
llabs(steady_diff - sc_diff), RCUTILS_MS_TO_NS(k_tolerance_ms)) << "steady_clock differs";
233+
}
234+
194235
#if !defined(_WIN32)
195236

196237
TEST_F(TestTimeFixture, test_rcutils_with_bad_system_clocks) {
@@ -211,6 +252,10 @@ TEST_F(TestTimeFixture, test_rcutils_with_bad_system_clocks) {
211252
ret = rcutils_steady_time_now(&now);
212253
EXPECT_EQ(RCUTILS_RET_ERROR, ret);
213254
rcutils_reset_error();
255+
256+
ret = rcutils_raw_steady_time_now(&now);
257+
EXPECT_EQ(RCUTILS_RET_ERROR, ret);
258+
rcutils_reset_error();
214259
}
215260
{
216261
auto mock = mocking_utils::patch(
@@ -229,6 +274,10 @@ TEST_F(TestTimeFixture, test_rcutils_with_bad_system_clocks) {
229274
ret = rcutils_steady_time_now(&now);
230275
EXPECT_EQ(RCUTILS_RET_ERROR, ret);
231276
rcutils_reset_error();
277+
278+
ret = rcutils_raw_steady_time_now(&now);
279+
EXPECT_EQ(RCUTILS_RET_ERROR, ret);
280+
rcutils_reset_error();
232281
}
233282
}
234283

0 commit comments

Comments
 (0)