27 #include "rcl/error_handling.h"
30 #include "rcutils/logging_macros.h"
31 #include "rmw/error_handling.h"
32 #include "rmw/ret_types.h"
35 #include "rmw/types.h"
37 #include "./context_impl.h"
38 #include "./client_impl.h"
39 #include "./guard_condition_impl.h"
40 #include "./service_impl.h"
41 #include "./subscription_impl.h"
42 #include "./timer_impl.h"
47 size_t subscription_index;
48 rmw_subscriptions_t rmw_subscriptions;
50 size_t guard_condition_index;
51 rmw_guard_conditions_t rmw_guard_conditions;
54 rmw_clients_t rmw_clients;
57 rmw_services_t rmw_services;
60 rmw_events_t rmw_events;
62 rmw_wait_set_t * rmw_wait_set;
82 return wait_set && wait_set->
impl;
88 size_t number_of_subscriptions,
89 size_t number_of_guard_conditions,
90 size_t number_of_timers,
91 size_t number_of_clients,
92 size_t number_of_services,
93 size_t number_of_events,
97 RCUTILS_LOG_DEBUG_NAMED(
98 ROS_PACKAGE_NAME,
"Initializing wait set with "
99 "'%zu' subscriptions, '%zu' guard conditions, '%zu' timers, '%zu' clients, '%zu' services",
100 number_of_subscriptions, number_of_guard_conditions, number_of_timers, number_of_clients,
107 RCL_SET_ERROR_MSG(
"wait_set already initialized, or memory was uninitialized.");
114 "the given context is not valid, "
115 "either rcl_init() was not called or rcl_shutdown() was called.");
121 RCL_CHECK_FOR_NULL_WITH_MSG(
124 wait_set->
impl->rmw_subscriptions.subscribers = NULL;
125 wait_set->
impl->rmw_subscriptions.subscriber_count = 0;
126 wait_set->
impl->rmw_guard_conditions.guard_conditions = NULL;
127 wait_set->
impl->rmw_guard_conditions.guard_condition_count = 0;
128 wait_set->
impl->rmw_clients.clients = NULL;
129 wait_set->
impl->rmw_clients.client_count = 0;
130 wait_set->
impl->rmw_services.services = NULL;
131 wait_set->
impl->rmw_services.service_count = 0;
132 wait_set->
impl->rmw_events.events = NULL;
133 wait_set->
impl->rmw_events.event_count = 0;
135 wait_set->
impl->context = context;
137 wait_set->
impl->allocator = allocator;
139 size_t num_conditions =
140 (2 * number_of_subscriptions) +
141 number_of_guard_conditions +
146 wait_set->
impl->rmw_wait_set = rmw_create_wait_set(&(context->
impl->
rmw_context), num_conditions);
147 if (!wait_set->
impl->rmw_wait_set) {
154 wait_set, number_of_subscriptions, number_of_guard_conditions, number_of_timers,
155 number_of_clients, number_of_services, number_of_events);
162 if (wait_set->
impl->rmw_wait_set != NULL) {
163 rmw_ret_t rmw_ret = rmw_destroy_wait_set(wait_set->
impl->rmw_wait_set);
164 if (rmw_ret != RMW_RET_OK) {
168 allocator.deallocate(wait_set->
impl, wait_set->
impl->allocator.state);
169 wait_set->
impl = NULL;
181 rmw_ret_t ret = rmw_destroy_wait_set(wait_set->
impl->rmw_wait_set);
182 if (ret != RMW_RET_OK) {
183 RCL_SET_ERROR_MSG(rmw_get_error_string().str);
190 result = resize_result;
192 if (wait_set->
impl) {
193 wait_set->
impl->allocator.deallocate(wait_set->
impl, wait_set->
impl->allocator.state);
194 wait_set->
impl = NULL;
205 RCL_SET_ERROR_MSG(
"wait set is invalid");
209 *allocator = wait_set->
impl->allocator;
213 #define SET_ADD(Type) \
214 RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT); \
215 if (!wait_set->impl) { \
216 RCL_SET_ERROR_MSG("wait set is invalid"); \
217 return RCL_RET_WAIT_SET_INVALID; \
219 RCL_CHECK_ARGUMENT_FOR_NULL(Type, RCL_RET_INVALID_ARGUMENT); \
220 if (!(wait_set->impl->Type ## _index < wait_set->size_of_ ## Type ## s)) { \
221 RCL_SET_ERROR_MSG(#Type "s set is full"); \
222 return RCL_RET_WAIT_SET_FULL; \
224 size_t current_index = wait_set->impl->Type ## _index++; \
225 wait_set->Type ## s[current_index] = Type; \
227 if (NULL != index) { \
228 *index = current_index; \
231 #define SET_ADD_RMW(Type, RMWStorage, RMWCount) \
233 rmw_ ## Type ## _t * rmw_handle = rcl_ ## Type ## _get_rmw_handle(Type); \
234 RCL_CHECK_FOR_NULL_WITH_MSG( \
235 rmw_handle, rcl_get_error_string().str, return RCL_RET_ERROR); \
236 wait_set->impl->RMWStorage[current_index] = rmw_handle->data; \
237 wait_set->impl->RMWCount++;
239 #define SET_CLEAR(Type) \
241 if (NULL != wait_set->Type ## s) { \
243 (void *)wait_set->Type ## s, \
245 sizeof(rcl_ ## Type ## _t *) * wait_set->size_of_ ## Type ## s); \
246 wait_set->impl->Type ## _index = 0; \
250 #define SET_CLEAR_RMW(Type, RMWStorage, RMWCount) \
252 if (NULL != wait_set->impl->RMWStorage) { \
255 wait_set->impl->RMWStorage, \
257 sizeof(void *) * wait_set->impl->RMWCount); \
258 wait_set->impl->RMWCount = 0; \
262 #define SET_RESIZE(Type, ExtraDealloc, ExtraRealloc) \
264 rcl_allocator_t allocator = wait_set->impl->allocator; \
265 wait_set->size_of_ ## Type ## s = 0; \
266 wait_set->impl->Type ## _index = 0; \
267 if (0 == Type ## s_size) { \
268 if (wait_set->Type ## s) { \
269 allocator.deallocate((void *)wait_set->Type ## s, allocator.state); \
270 wait_set->Type ## s = NULL; \
274 wait_set->Type ## s = (const rcl_ ## Type ## _t **)allocator.reallocate( \
275 (void *)wait_set->Type ## s, sizeof(rcl_ ## Type ## _t *) * Type ## s_size, \
277 RCL_CHECK_FOR_NULL_WITH_MSG( \
278 wait_set->Type ## s, "allocating memory failed", return RCL_RET_BAD_ALLOC); \
279 memset((void *)wait_set->Type ## s, 0, sizeof(rcl_ ## Type ## _t *) * Type ## s_size); \
280 wait_set->size_of_ ## Type ## s = Type ## s_size; \
285 #define SET_RESIZE_RMW_DEALLOC(RMWStorage, RMWCount) \
287 if (wait_set->impl->RMWStorage) { \
288 allocator.deallocate((void *)wait_set->impl->RMWStorage, allocator.state); \
289 wait_set->impl->RMWStorage = NULL; \
290 wait_set->impl->RMWCount = 0; \
293 #define SET_RESIZE_RMW_REALLOC(Type, RMWStorage, RMWCount) \
295 wait_set->impl->RMWCount = 0; \
296 wait_set->impl->RMWStorage = (void **)allocator.reallocate( \
297 wait_set->impl->RMWStorage, sizeof(void *) * Type ## s_size, allocator.state); \
298 if (!wait_set->impl->RMWStorage) { \
299 allocator.deallocate((void *)wait_set->Type ## s, allocator.state); \
300 wait_set->Type ## s = NULL; \
301 wait_set->size_of_ ## Type ## s = 0; \
302 RCL_SET_ERROR_MSG("allocating memory failed"); \
303 return RCL_RET_BAD_ALLOC; \
305 memset(wait_set->impl->RMWStorage, 0, sizeof(void *) * Type ## s_size);
315 #define CHECK_DOUBLE_USAGE(Type) \
316 for (size_t idx = 0; idx < wait_set->size_of_ ## Type ## s; idx++) { \
317 if (wait_set->Type ## s[idx]) { \
318 wait_set->Type ## s[idx]->impl->in_use_by_waitset = false; \
321 for (size_t idx = 0; idx < wait_set->size_of_ ## Type ## s; idx++) { \
322 if (wait_set->Type ## s[idx]) { \
323 if(wait_set->Type ## s[idx]->impl->in_use_by_waitset) { \
324 RCL_SET_ERROR_MSG("Entitiy of type " #Type " added multiple times to waitset."); \
325 return RCL_RET_WAIT_SET_INVALID; \
327 wait_set->Type ## s[idx]->impl->in_use_by_waitset = true; \
342 SET_ADD(subscription)
343 SET_ADD_RMW(subscription, rmw_subscriptions.subscribers, rmw_subscriptions.subscriber_count)
358 SET_CLEAR(subscription);
359 SET_CLEAR(guard_condition);
367 rmw_subscriptions.subscribers,
368 rmw_subscriptions.subscriber_count);
371 rmw_guard_conditions.guard_conditions,
372 rmw_guard_conditions.guard_condition_count);
376 rmw_clients.client_count);
379 rmw_services.services,
380 rmw_services.service_count);
384 rmw_events.event_count);
397 size_t subscriptions_size,
398 size_t guard_conditions_size,
401 size_t services_size,
408 SET_RESIZE_RMW_DEALLOC(
409 rmw_subscriptions.subscribers, rmw_subscriptions.subscriber_count),
410 SET_RESIZE_RMW_REALLOC(
411 subscription, rmw_subscriptions.subscribers, rmw_subscriptions.subscriber_count)
414 SET_RESIZE(guard_condition,;,;);
417 rmw_guard_conditions_t * rmw_gcs = &(wait_set->
impl->rmw_guard_conditions);
418 const size_t num_rmw_gc = guard_conditions_size + timers_size;
420 rmw_gcs->guard_condition_count = 0u;
421 if (0u == num_rmw_gc) {
422 if (rmw_gcs->guard_conditions) {
423 wait_set->
impl->allocator.deallocate(
424 (
void *)rmw_gcs->guard_conditions, wait_set->
impl->allocator.state);
425 rmw_gcs->guard_conditions = NULL;
428 rmw_gcs->guard_conditions = (
void **)wait_set->
impl->allocator.reallocate(
429 rmw_gcs->guard_conditions,
sizeof(
void *) * num_rmw_gc, wait_set->
impl->allocator.state);
430 if (!rmw_gcs->guard_conditions) {
432 wait_set->
impl->allocator.deallocate(
436 wait_set->
impl->allocator.deallocate(
437 (
void *)wait_set->
timers, wait_set->
impl->allocator.state);
440 RCL_SET_ERROR_MSG(
"allocating memory failed");
443 memset(rmw_gcs->guard_conditions, 0,
sizeof(
void *) * num_rmw_gc);
446 SET_RESIZE(timer,;,;);
449 SET_RESIZE_RMW_DEALLOC(
450 rmw_clients.clients, rmw_clients.client_count),
451 SET_RESIZE_RMW_REALLOC(
452 client, rmw_clients.clients, rmw_clients.client_count)
456 SET_RESIZE_RMW_DEALLOC(
457 rmw_services.services, rmw_services.service_count),
458 SET_RESIZE_RMW_REALLOC(
459 service, rmw_services.services, rmw_services.service_count)
463 SET_RESIZE_RMW_DEALLOC(
464 rmw_events.events, rmw_events.event_count),
465 SET_RESIZE_RMW_REALLOC(
466 event, rmw_events.events, rmw_events.event_count)
478 SET_ADD(guard_condition)
480 guard_condition, rmw_guard_conditions.guard_conditions,
481 rmw_guard_conditions.guard_condition_count)
495 if (NULL != guard_condition) {
499 RCL_CHECK_FOR_NULL_WITH_MSG(
500 rmw_handle, rcl_get_error_string().str,
return RCL_RET_ERROR);
501 wait_set->
impl->rmw_guard_conditions.guard_conditions[index] = rmw_handle->data;
513 SET_ADD_RMW(client, rmw_clients.clients, rmw_clients.client_count)
524 SET_ADD_RMW(service, rmw_services.services, rmw_services.service_count)
535 SET_ADD_RMW(event, rmw_events.events, rmw_events.event_count)
536 wait_set->
impl->rmw_events.events[current_index] = rmw_handle;
545 RCL_SET_ERROR_MSG(
"wait set is invalid");
556 RCL_SET_ERROR_MSG(
"wait set is empty");
560 CHECK_DOUBLE_USAGE(client);
561 CHECK_DOUBLE_USAGE(guard_condition);
562 CHECK_DOUBLE_USAGE(service);
563 CHECK_DOUBLE_USAGE(subscription);
564 CHECK_DOUBLE_USAGE(timer);
568 rmw_time_t * timeout_argument = NULL;
569 rmw_time_t temporary_timeout_storage;
570 bool is_non_blocking = timeout == 0;
572 for (uint64_t t_idx = 0; t_idx < wait_set->
impl->timer_index; ++t_idx) {
573 if (!wait_set->
timers[t_idx]) {
576 rmw_guard_conditions_t * rmw_gcs = &(wait_set->
impl->rmw_guard_conditions);
578 if (NULL != rmw_gcs->guard_conditions[gc_idx]) {
580 rmw_gcs->guard_conditions[rmw_gcs->guard_condition_count] =
581 rmw_gcs->guard_conditions[gc_idx];
582 ++(rmw_gcs->guard_condition_count);
599 if (!is_non_blocking) {
600 for (
size_t t_idx = 0; t_idx < wait_set->
impl->timer_index; ++t_idx) {
601 if (!wait_set->
timers[t_idx]) {
609 RCL_EXPECT_ERROR_IS_SET(ret);
614 bool timer_override_active =
false;
618 RCL_EXPECT_ERROR_IS_SET(ret);
622 if (timer_override_active) {
624 bool override_timer_is_ready =
false;
628 RCL_EXPECT_ERROR_IS_SET(ret);
632 if (override_timer_is_ready) {
634 is_non_blocking =
true;
646 int64_t next_call_time = INT64_MAX;
649 wait_set->
timers[t_idx] = NULL;
653 RCL_EXPECT_ERROR_IS_SET(ret);
656 if (next_call_time < min_next_call_time[clock->
type]) {
657 clocks[clock->
type] = clock;
658 min_next_call_time[clock->
type] = next_call_time;
663 if (is_non_blocking) {
664 temporary_timeout_storage.sec = 0;
665 temporary_timeout_storage.nsec = 0;
666 timeout_argument = &temporary_timeout_storage;
668 bool has_valid_timeout = timeout > 0;
669 int64_t min_timeout = has_valid_timeout ? timeout : INT64_MAX;
673 if (clocks[i] == NULL) {
680 RCL_EXPECT_ERROR_IS_SET(ret);
684 int64_t timer_timeout = min_next_call_time[i] - cur_time;
686 if (timer_timeout <= min_timeout) {
687 has_valid_timeout =
true;
688 min_timeout = timer_timeout;
693 if (min_timeout < 0) {
696 if (has_valid_timeout) {
697 temporary_timeout_storage.sec =
RCL_NS_TO_S(min_timeout);
698 temporary_timeout_storage.nsec = min_timeout % 1000000000;
699 timeout_argument = &temporary_timeout_storage;
704 rmw_ret_t ret = rmw_wait(
705 &wait_set->
impl->rmw_subscriptions,
706 &wait_set->
impl->rmw_guard_conditions,
707 &wait_set->
impl->rmw_services,
708 &wait_set->
impl->rmw_clients,
709 &wait_set->
impl->rmw_events,
710 wait_set->
impl->rmw_wait_set,
716 bool any_timer_is_ready =
false;
721 for (i = 0; i < wait_set->
impl->timer_index; ++i) {
722 if (!wait_set->
timers[i]) {
726 bool current_timer_is_ready =
false;
729 RCL_EXPECT_ERROR_IS_SET(ret);
732 if (!current_timer_is_ready) {
733 wait_set->
timers[i] = NULL;
735 any_timer_is_ready =
true;
739 if (ret != RMW_RET_OK && ret != RMW_RET_TIMEOUT) {
740 RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
741 "Error from rmw_wait(): %d %s", ret, rmw_get_error_string().str);
746 bool is_ready = wait_set->
impl->rmw_subscriptions.subscribers[i] != NULL;
753 bool is_ready = wait_set->
impl->rmw_guard_conditions.guard_conditions[i] != NULL;
760 bool is_ready = wait_set->
impl->rmw_clients.clients[i] != NULL;
767 bool is_ready = wait_set->
impl->rmw_services.services[i] != NULL;
774 bool is_ready = wait_set->
impl->rmw_events.events[i] != NULL;
776 wait_set->
events[i] = NULL;
780 if (RMW_RET_TIMEOUT == ret && !any_timer_is_ready) {
#define RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, msg, fail_statement)
Check that the given allocator is initialized, or fail with a message.
rcutils_allocator_t rcl_allocator_t
Encapsulation of an allocator.
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_context_is_valid(const rcl_context_t *context)
Return true if the given context is currently valid, otherwise false.
RCL_PUBLIC RCL_WARN_UNUSED rmw_guard_condition_t * rcl_guard_condition_get_rmw_handle(const rcl_guard_condition_t *guard_condition)
Return the rmw guard condition handle.
Structure which encapsulates a ROS Client.
Encapsulation of a time source.
rcl_clock_type_t type
Clock type.
rmw_context_t rmw_context
rmw context.
Encapsulates the non-global state of an init/shutdown cycle.
rcl_context_impl_t * impl
Implementation specific pointer.
Structure which encapsulates a ROS QoS event handle.
Handle for a rcl guard condition.
Structure which encapsulates a ROS Service.
Structure which encapsulates a ROS Subscription.
Structure which encapsulates a ROS Timer.
Container for subscription's, guard condition's, etc to be waited on.
const rcl_event_t ** events
Storage for event pointers.
const rcl_timer_t ** timers
Storage for timer pointers.
size_t size_of_timers
Number of timers.
size_t size_of_events
Number of events.
size_t size_of_subscriptions
Number of subscriptions.
const rcl_service_t ** services
Storage for service pointers.
const rcl_client_t ** clients
Storage for client pointers.
const rcl_subscription_t ** subscriptions
Storage for subscription pointers.
size_t size_of_guard_conditions
Number of guard_conditions.
rcl_wait_set_impl_t * impl
Implementation specific storage.
size_t size_of_clients
Number of clients.
const rcl_guard_condition_t ** guard_conditions
Storage for guard condition pointers.
size_t size_of_services
Number of services.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_clock_get_now(rcl_clock_t *clock, rcl_time_point_value_t *time_point_value)
Fill the time point value with the current value of the associated clock.
#define RCL_NS_TO_S
Convenience macro to convert nanoseconds to seconds.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_is_enabled_ros_time_override(rcl_clock_t *clock, bool *is_enabled)
Check if the RCL_ROS_TIME time source has the override enabled.
@ RCL_ROS_TIME
Use ROS time.
@ RCL_SYSTEM_TIME
Use system time.
@ RCL_STEADY_TIME
Use a steady clock time.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_get_next_call_time(const rcl_timer_t *timer, int64_t *next_call_time)
Retrieve the time when the next call to rcl_timer_call() shall occur.
RCL_PUBLIC RCL_WARN_UNUSED rcl_guard_condition_t * rcl_timer_get_guard_condition(const rcl_timer_t *timer)
Retrieve a guard condition used by the timer to wake the waitset when using ROSTime.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_clock(const rcl_timer_t *timer, rcl_clock_t **clock)
Retrieve the clock of the timer.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_is_ready(const rcl_timer_t *timer, bool *is_ready)
Calculates whether or not the timer should be called.
#define RCL_RET_WAIT_SET_EMPTY
Given rcl_wait_set_t is empty return code.
#define RCL_RET_WAIT_SET_INVALID
Invalid rcl_wait_set_t given return code.
#define RCL_RET_NOT_INIT
rcl_init() not yet called return code.
#define RCL_RET_ALREADY_INIT
rcl_init() already called return code.
#define RCL_RET_OK
Success return code.
#define RCL_RET_BAD_ALLOC
Failed to allocate memory return code.
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
#define RCL_RET_ERROR
Unspecified error return code.
#define RCL_RET_TIMER_CANCELED
Given timer was canceled return code.
#define RCL_RET_TIMEOUT
Timeout occurred return code.
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_add_subscription(rcl_wait_set_t *wait_set, const rcl_subscription_t *subscription, size_t *index)
Store a pointer to the given subscription in the next empty spot in the set.
RCL_PUBLIC bool rcl_wait_set_is_valid(const rcl_wait_set_t *wait_set)
Return true if the wait set is valid, else false.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_add_service(rcl_wait_set_t *wait_set, const rcl_service_t *service, size_t *index)
Store a pointer to the service in the next empty spot in the set.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_init(rcl_wait_set_t *wait_set, size_t number_of_subscriptions, size_t number_of_guard_conditions, size_t number_of_timers, size_t number_of_clients, size_t number_of_services, size_t number_of_events, rcl_context_t *context, rcl_allocator_t allocator)
Initialize a rcl wait set with space for items to be waited on.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_clear(rcl_wait_set_t *wait_set)
Remove (sets to NULL) all entities in the wait set.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_add_timer(rcl_wait_set_t *wait_set, const rcl_timer_t *timer, size_t *index)
Store a pointer to the timer in the next empty spot in the set.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_add_client(rcl_wait_set_t *wait_set, const rcl_client_t *client, size_t *index)
Store a pointer to the client in the next empty spot in the set.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_fini(rcl_wait_set_t *wait_set)
Finalize a rcl wait set.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait(rcl_wait_set_t *wait_set, int64_t timeout)
Block until the wait set is ready or until the timeout has been exceeded.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_resize(rcl_wait_set_t *wait_set, size_t subscriptions_size, size_t guard_conditions_size, size_t timers_size, size_t clients_size, size_t services_size, size_t events_size)
Reallocate space for entities in the wait set.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_get_allocator(const rcl_wait_set_t *wait_set, rcl_allocator_t *allocator)
Retrieve the wait set's allocator.
RCL_PUBLIC RCL_WARN_UNUSED rcl_wait_set_t rcl_get_zero_initialized_wait_set(void)
Return a rcl_wait_set_t struct with members set to NULL.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_add_event(rcl_wait_set_t *wait_set, const rcl_event_t *event, size_t *index)
Store a pointer to the event in the next empty spot in the set.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_add_guard_condition(rcl_wait_set_t *wait_set, const rcl_guard_condition_t *guard_condition, size_t *index)
Store a pointer to the guard condition in the next empty spot in the set.