Skip to content

Commit 5e06b81

Browse files
author
Emerson Knapp
committed
Address review feedback:
* Add new time.h/c * Update documentation to distinguish between unspecified/infinite * Add overflow/bounds checking for time utils Signed-off-by: Emerson Knapp <[email protected]>
1 parent 94f4f33 commit 5e06b81

File tree

8 files changed

+313
-172
lines changed

8 files changed

+313
-172
lines changed

rmw/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ set(rmw_sources
3636
"src/sanity_checks.c"
3737
"src/security_options.c"
3838
"src/subscription_options.c"
39+
"src/time.c"
3940
"src/topic_endpoint_info_array.c"
4041
"src/topic_endpoint_info.c"
4142
"src/types.c"

rmw/include/rmw/time.h

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef RMW__TIME_H_
16+
#define RMW__TIME_H_
17+
18+
#ifdef __cplusplus
19+
extern "C"
20+
{
21+
#endif // __cplusplus
22+
23+
#include <stdint.h>
24+
25+
#include "rcutils/time.h"
26+
27+
#include "rmw/macros.h"
28+
#include "rmw/visibility_control.h"
29+
30+
/// A struct representing a duration in RMW.
31+
typedef struct RMW_PUBLIC_TYPE rmw_time_t
32+
{
33+
/// Seconds since the epoch
34+
uint64_t sec;
35+
36+
/// Nanoseconds component of this time point
37+
uint64_t nsec;
38+
} rmw_time_t;
39+
40+
typedef rcutils_time_point_value_t rmw_time_point_value_t;
41+
typedef rcutils_duration_value_t rmw_duration_t;
42+
43+
/// Constant representing an infinite duration. Use rmw_time_equal for comparisons.
44+
/**
45+
* Different RMW implementations have different representations for infinite durations.
46+
* This value is reported for QoS policy durations that are left unspecified.
47+
* Do not directly compare `sec == sec && nsec == nsec`, because we don't want to be sensitive
48+
* to non-normalized values (nsec > 1 second) - use rmw_time_equal instead.
49+
* This value is INT64_MAX nanoseconds = 0x7FFF FFFF FFFF FFFF = d 9 223 372 036 854 775 807
50+
*/
51+
static const struct rmw_time_t RMW_DURATION_INFINITE = {9223372036LL, 854775807LL};
52+
static const struct rmw_time_t RMW_DURATION_UNSPECIFIED = {0LL, 0LL};
53+
54+
/// Check whether two rmw_time_t represent the same time.
55+
RMW_PUBLIC
56+
RMW_WARN_UNUSED
57+
bool
58+
rmw_time_equal(const rmw_time_t left, const rmw_time_t right);
59+
60+
/// Return the total nanosecond representation of a time.
61+
/**
62+
* \return INT64_MAX if input is too large to store in 64 bits
63+
*/
64+
RMW_PUBLIC
65+
RMW_WARN_UNUSED
66+
rmw_duration_t
67+
rmw_time_total_nsec(const rmw_time_t time);
68+
69+
/// Construct rmw_time_t from a total nanoseconds representation.
70+
/**
71+
* rmw_time_t only specifies relative time, so the origin is not relevant for this calculation.
72+
* \return RMW_DURATION_INFINITE if input is negative, which is not representable in rmw_time_t
73+
*/
74+
RMW_PUBLIC
75+
RMW_WARN_UNUSED
76+
rmw_time_t
77+
rmw_time_from_nsec(const rmw_duration_t nanoseconds);
78+
79+
/// Ensure that an rmw_time_t does not have nanoseconds > 1 second.
80+
RMW_PUBLIC
81+
RMW_WARN_UNUSED
82+
rmw_time_t
83+
rmw_time_normalize(const rmw_time_t time);
84+
85+
#ifdef __cplusplus
86+
}
87+
#endif // __cplusplus
88+
89+
#endif // RMW__TIME_H_

rmw/include/rmw/types.h

Lines changed: 25 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ extern "C"
3333
#include "rmw/ret_types.h"
3434
#include "rmw/security_options.h"
3535
#include "rmw/serialized_message.h"
36+
#include "rmw/time.h"
3637
#include "rmw/visibility_control.h"
3738

3839
// 24 bytes is the most memory needed to represent the GID by any current
@@ -318,53 +319,6 @@ typedef struct RMW_PUBLIC_TYPE rmw_request_id_t
318319
int64_t sequence_number;
319320
} rmw_request_id_t;
320321

321-
/// Struct representing a time point for rmw
322-
typedef struct RMW_PUBLIC_TYPE rmw_time_t
323-
{
324-
/// Seconds since the epoch
325-
uint64_t sec;
326-
327-
/// Nanoseconds component of this time point
328-
uint64_t nsec;
329-
} rmw_time_t;
330-
331-
typedef rcutils_time_point_value_t rmw_time_point_value_t;
332-
typedef rcutils_duration_value_t rmw_duration_t;
333-
334-
/// Constant representing an infinite duration. Use rmw_time_equal for comparisons.
335-
/**
336-
* Different RMW implementations have different representations for infinite durations.
337-
* This value is reported for QoS policy durations that are left unspecified.
338-
* Do not directly comparee `sec == sec && nsec == nsec`, because we don't want to be sensitive
339-
* to non-normalized values (nsec > 1 second) - use rmw_time_equal instead.
340-
* This value is INT64_MAX nanoseconds = 0x7FFF FFFF FFFF FFFF = d 9 223 372 036 854 775 807
341-
*/
342-
#define RMW_DURATION_INFINITE {9223372036LL, 854775807LL}
343-
344-
/// Check whether two rmw_time_t represent the same time.
345-
RMW_PUBLIC
346-
RMW_WARN_UNUSED
347-
bool
348-
rmw_time_equal(const rmw_time_t left, const rmw_time_t right);
349-
350-
/// Return the total nanosecond representation of a time.
351-
RMW_PUBLIC
352-
RMW_WARN_UNUSED
353-
rmw_duration_t
354-
rmw_time_total_nsec(const rmw_time_t time);
355-
356-
/// Construct rmw_time_t from a total nanoseconds representation.
357-
RMW_PUBLIC
358-
RMW_WARN_UNUSED
359-
rmw_time_t
360-
rmw_time_from_nsec(const rmw_duration_t nanoseconds);
361-
362-
/// Ensure that an rmw_time_t does not have nanoseconds > 1 second.
363-
RMW_PUBLIC
364-
RMW_WARN_UNUSED
365-
rmw_time_t
366-
rmw_time_normalize(const rmw_time_t time);
367-
368322
/// Meta-data for a service-related take.
369323
typedef struct RMW_PUBLIC_TYPE rmw_service_info_t
370324
{
@@ -459,16 +413,17 @@ enum RMW_PUBLIC_TYPE rmw_qos_liveliness_policy_t
459413
RMW_QOS_POLICY_LIVELINESS_UNKNOWN = 4
460414
};
461415

462-
#define RMW_QOS_DURATION_UNSPECIFIED {0, 0}
463-
464-
/// QoS Deadline default, 0s indicates deadline policies are not tracked or enforced
465-
#define RMW_QOS_DEADLINE_DEFAULT RMW_QOS_DURATION_UNSPECIFIED
416+
/// QoS Deadline default - when unspecified the RMW implementation default is used
417+
/// In most implementations, this is "infinity" meaning that the deadline is not enforced
418+
#define RMW_QOS_DEADLINE_DEFAULT RMW_DURATION_UNSPECIFIED
466419

467-
/// QoS Lifespan default, 0s indicate lifespan policies are not tracked or enforced
468-
#define RMW_QOS_LIFESPAN_DEFAULT RMW_QOS_DURATION_UNSPECIFIED
420+
/// QoS Lifespan default - when unspecified the RMW implementation default is used
421+
/// In most implementations, this is "infinity" meaning that the deadline is not enforced
422+
#define RMW_QOS_LIFESPAN_DEFAULT RMW_DURATION_UNSPECIFIED
469423

470-
/// QoS Liveliness lease duration default, 0s indicate lease durations are not tracked or enforced
471-
#define RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT RMW_QOS_DURATION_UNSPECIFIED
424+
/// QoS liveliness lease duration default - when unspecified the RMW implementation default is used
425+
/// In most implementations, this is "infinity" meaning that the deadline is not enforced
426+
#define RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT RMW_DURATION_UNSPECIFIED
472427

473428
/// ROS MiddleWare quality of service profile.
474429
typedef struct RMW_PUBLIC_TYPE rmw_qos_profile_t
@@ -481,12 +436,27 @@ typedef struct RMW_PUBLIC_TYPE rmw_qos_profile_t
481436
/// Durability QoS policy setting
482437
enum rmw_qos_durability_policy_t durability;
483438
/// The period at which messages are expected to be sent/received
439+
/**
440+
* RMW_DURATION_UNSPEFICIED will use the RMW implementation's default value,
441+
* which may or may not be infinite.
442+
* RMW_DURATION_INFINITE explicitly states that messages never miss a deadline expectation.
443+
*/
484444
struct rmw_time_t deadline;
485445
/// The age at which messages are considered expired and no longer valid
446+
/**
447+
* RMW_DURATION_UNSPEFICIED will use the RMW implementation's default value,
448+
* which may or may not be infinite.
449+
* RMW_DURATION_INFINITE explicitly states that messages do not expire.
450+
*/
486451
struct rmw_time_t lifespan;
487452
/// Liveliness QoS policy setting
488453
enum rmw_qos_liveliness_policy_t liveliness;
489454
/// The time within which the RMW node or publisher must show that it is alive
455+
/**
456+
* RMW_DURATION_UNSPEFICIED will use the RMW implementation's default value,
457+
* which may or may not be infinite.
458+
* RMW_DURATION_INFINITE explicitly states that liveliness is not enforced.
459+
*/
490460
struct rmw_time_t liveliness_lease_duration;
491461

492462
/// If true, any ROS specific namespacing conventions will be circumvented.

rmw/src/time.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "rmw/time.h"
16+
17+
#include "rcutils/time.h"
18+
19+
RMW_PUBLIC
20+
RMW_WARN_UNUSED
21+
bool
22+
rmw_time_equal(const rmw_time_t left, const rmw_time_t right)
23+
{
24+
return rmw_time_total_nsec(left) == rmw_time_total_nsec(right);
25+
}
26+
27+
RMW_PUBLIC
28+
RMW_WARN_UNUSED
29+
rmw_duration_t
30+
rmw_time_total_nsec(const rmw_time_t time)
31+
{
32+
static const int64_t max_sec = INT64_MAX / RCUTILS_S_TO_NS(1);
33+
if ((int64_t)time.sec > max_sec) {
34+
// Seconds not representable in nanoseconds
35+
return INT64_MAX;
36+
}
37+
38+
const int64_t sec_as_nsec = RCUTILS_S_TO_NS(time.sec);
39+
if ((int64_t)time.nsec > (INT64_MAX - sec_as_nsec)) {
40+
// overflow
41+
return INT64_MAX;
42+
}
43+
return sec_as_nsec + time.nsec;
44+
}
45+
46+
RMW_PUBLIC
47+
RMW_WARN_UNUSED
48+
rmw_time_t
49+
rmw_time_from_nsec(const rmw_duration_t nanoseconds)
50+
{
51+
if (nanoseconds < 0) {
52+
return RMW_DURATION_INFINITE;
53+
}
54+
55+
// Avoid typing the 1 billion constant
56+
rmw_time_t time;
57+
time.sec = RCUTILS_NS_TO_S(nanoseconds);
58+
time.nsec = nanoseconds % RCUTILS_S_TO_NS(1);
59+
return time;
60+
}
61+
62+
RMW_PUBLIC
63+
RMW_WARN_UNUSED
64+
rmw_time_t
65+
rmw_time_normalize(const rmw_time_t time)
66+
{
67+
return rmw_time_from_nsec(rmw_time_total_nsec(time));
68+
}

rmw/src/types.c

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
#include "rmw/types.h"
1616

17-
#include "rcutils/time.h"
18-
1917
RMW_PUBLIC
2018
RMW_WARN_UNUSED
2119
rmw_message_info_t
@@ -24,39 +22,3 @@ rmw_get_zero_initialized_message_info(void)
2422
rmw_message_info_t zero_initialized_message_info = {0, 0, {NULL, {0}}, false};
2523
return zero_initialized_message_info;
2624
}
27-
28-
RMW_PUBLIC
29-
RMW_WARN_UNUSED
30-
bool
31-
rmw_time_equal(const rmw_time_t left, const rmw_time_t right)
32-
{
33-
return rmw_time_total_nsec(left) == rmw_time_total_nsec(right);
34-
}
35-
36-
RMW_PUBLIC
37-
RMW_WARN_UNUSED
38-
rmw_duration_t
39-
rmw_time_total_nsec(const rmw_time_t time)
40-
{
41-
return RCUTILS_S_TO_NS(time.sec) + time.nsec;
42-
}
43-
44-
RMW_PUBLIC
45-
RMW_WARN_UNUSED
46-
rmw_time_t
47-
rmw_time_from_nsec(const rmw_duration_t nanoseconds)
48-
{
49-
// Avoid typing the 1 billion constant
50-
rmw_time_t time;
51-
time.sec = RCUTILS_NS_TO_S(nanoseconds);
52-
time.nsec = nanoseconds % RCUTILS_S_TO_NS(1);
53-
return time;
54-
}
55-
56-
RMW_PUBLIC
57-
RMW_WARN_UNUSED
58-
rmw_time_t
59-
rmw_time_normalize(const rmw_time_t time)
60-
{
61-
return rmw_time_from_nsec(rmw_time_total_nsec(time));
62-
}

rmw/test/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,15 @@ if(TARGET test_subscription_options)
121121
target_link_libraries(test_subscription_options ${PROJECT_NAME})
122122
endif()
123123

124+
ament_add_gmock(test_time
125+
test_time.cpp
126+
# Append the directory of librmw so it is found at test time.
127+
APPEND_LIBRARY_DIRS "$<TARGET_FILE_DIR:${PROJECT_NAME}>"
128+
)
129+
if(TARGET test_time)
130+
target_link_libraries(test_time ${PROJECT_NAME})
131+
endif()
132+
124133
ament_add_gmock(test_types
125134
test_types.cpp
126135
# Append the directory of librmw so it is found at test time.

0 commit comments

Comments
 (0)