ROS 2 rclcpp + rcl - rolling  rolling-a919a6e5
ROS 2 C++ Client Library with ROS Client Library
wait.c
1 // Copyright 2015 Open Source Robotics Foundation, Inc.
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 #ifdef __cplusplus
16 extern "C"
17 {
18 #endif
19 
20 #include "rcl/wait.h"
21 
22 #include <assert.h>
23 #include <inttypes.h>
24 #include <stdbool.h>
25 #include <string.h>
26 
27 #include "rcl/error_handling.h"
28 #include "rcl/time.h"
29 #include "rcutils/logging_macros.h"
30 #include "rmw/error_handling.h"
31 #include "rmw/rmw.h"
32 #include "rmw/event.h"
33 
34 #include "./context_impl.h"
35 
37 {
38  // number of subscriptions that have been added to the wait set
39  size_t subscription_index;
40  rmw_subscriptions_t rmw_subscriptions;
41  // number of guard_conditions that have been added to the wait set
42  size_t guard_condition_index;
43  rmw_guard_conditions_t rmw_guard_conditions;
44  // number of clients that have been added to the wait set
45  size_t client_index;
46  rmw_clients_t rmw_clients;
47  // number of services that have been added to the wait set
48  size_t service_index;
49  rmw_services_t rmw_services;
50  // number of events that have been added to the wait set
51  size_t event_index;
52  rmw_events_t rmw_events;
53 
54  rmw_wait_set_t * rmw_wait_set;
55  // number of timers that have been added to the wait set
56  size_t timer_index;
57  // context with which the wait set is associated
58  rcl_context_t * context;
59  // allocator used in the wait set
60  rcl_allocator_t allocator;
61 };
62 
65 {
66  // All members are initialized to 0 or NULL by C99 6.7.8/10.
67  static rcl_wait_set_t null_wait_set;
68  return null_wait_set;
69 }
70 
71 bool
73 {
74  return wait_set && wait_set->impl;
75 }
76 
79  rcl_wait_set_t * wait_set,
80  size_t number_of_subscriptions,
81  size_t number_of_guard_conditions,
82  size_t number_of_timers,
83  size_t number_of_clients,
84  size_t number_of_services,
85  size_t number_of_events,
86  rcl_context_t * context,
87  rcl_allocator_t allocator)
88 {
89  RCUTILS_LOG_DEBUG_NAMED(
90  ROS_PACKAGE_NAME, "Initializing wait set with "
91  "'%zu' subscriptions, '%zu' guard conditions, '%zu' timers, '%zu' clients, '%zu' services",
92  number_of_subscriptions, number_of_guard_conditions, number_of_timers, number_of_clients,
93  number_of_services);
94  rcl_ret_t rcl_ret = RCL_RET_ERROR;
95 
96  RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
97  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT);
98  if (rcl_wait_set_is_valid(wait_set)) {
99  RCL_SET_ERROR_MSG("wait_set already initialized, or memory was uninitialized.");
100  return RCL_RET_ALREADY_INIT;
101  }
102  // Make sure rcl has been initialized.
103  RCL_CHECK_ARGUMENT_FOR_NULL(context, RCL_RET_INVALID_ARGUMENT);
104  if (!rcl_context_is_valid(context)) {
105  RCL_SET_ERROR_MSG(
106  "the given context is not valid, "
107  "either rcl_init() was not called or rcl_shutdown() was called.");
108  return RCL_RET_NOT_INIT;
109  }
110  // Allocate space for the implementation struct.
111  wait_set->impl = (rcl_wait_set_impl_t *)allocator.allocate(
112  sizeof(rcl_wait_set_impl_t), allocator.state);
113  RCL_CHECK_FOR_NULL_WITH_MSG(
114  wait_set->impl, "allocating memory failed", return RCL_RET_BAD_ALLOC);
115  memset(wait_set->impl, 0, sizeof(rcl_wait_set_impl_t));
116  wait_set->impl->rmw_subscriptions.subscribers = NULL;
117  wait_set->impl->rmw_subscriptions.subscriber_count = 0;
118  wait_set->impl->rmw_guard_conditions.guard_conditions = NULL;
119  wait_set->impl->rmw_guard_conditions.guard_condition_count = 0;
120  wait_set->impl->rmw_clients.clients = NULL;
121  wait_set->impl->rmw_clients.client_count = 0;
122  wait_set->impl->rmw_services.services = NULL;
123  wait_set->impl->rmw_services.service_count = 0;
124  wait_set->impl->rmw_events.events = NULL;
125  wait_set->impl->rmw_events.event_count = 0;
126  // Set context.
127  wait_set->impl->context = context;
128  // Set allocator.
129  wait_set->impl->allocator = allocator;
130 
131  size_t num_conditions =
132  (2 * number_of_subscriptions) +
133  number_of_guard_conditions +
134  number_of_clients +
135  number_of_services +
136  number_of_events;
137 
138  wait_set->impl->rmw_wait_set = rmw_create_wait_set(&(context->impl->rmw_context), num_conditions);
139  if (!wait_set->impl->rmw_wait_set) {
140  rcl_ret = RCL_RET_BAD_ALLOC;
141  goto fail;
142  }
143 
144  // Initialize subscription space.
145  rcl_ret = rcl_wait_set_resize(
146  wait_set, number_of_subscriptions, number_of_guard_conditions, number_of_timers,
147  number_of_clients, number_of_services, number_of_events);
148  if (RCL_RET_OK != rcl_ret) {
149  goto fail;
150  }
151  return RCL_RET_OK;
152 
153 fail:
154  if (wait_set->impl->rmw_wait_set != NULL) {
155  rmw_ret_t rmw_ret = rmw_destroy_wait_set(wait_set->impl->rmw_wait_set);
156  if (rmw_ret != RMW_RET_OK) {
157  rcl_ret = RCL_RET_WAIT_SET_INVALID;
158  }
159  }
160  allocator.deallocate(wait_set->impl, wait_set->impl->allocator.state);
161  wait_set->impl = NULL;
162 
163  return rcl_ret;
164 }
165 
166 rcl_ret_t
168 {
169  rcl_ret_t result = RCL_RET_OK;
170  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT);
171 
172  if (rcl_wait_set_is_valid(wait_set)) {
173  rmw_ret_t ret = rmw_destroy_wait_set(wait_set->impl->rmw_wait_set);
174  if (ret != RMW_RET_OK) {
175  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
176  result = RCL_RET_WAIT_SET_INVALID;
177  }
178 
179  rcl_ret_t resize_result = rcl_wait_set_resize(wait_set, 0, 0, 0, 0, 0, 0);
180  if (result == RCL_RET_OK) {
181  // Only return the error here if we had no earlier errors.
182  result = resize_result;
183  }
184  if (wait_set->impl) {
185  wait_set->impl->allocator.deallocate(wait_set->impl, wait_set->impl->allocator.state);
186  wait_set->impl = NULL;
187  }
188  }
189  return result;
190 }
191 
192 rcl_ret_t
194 {
195  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT);
196  if (!rcl_wait_set_is_valid(wait_set)) {
197  RCL_SET_ERROR_MSG("wait set is invalid");
199  }
200  RCL_CHECK_ARGUMENT_FOR_NULL(allocator, RCL_RET_INVALID_ARGUMENT);
201  *allocator = wait_set->impl->allocator;
202  return RCL_RET_OK;
203 }
204 
205 #define SET_ADD(Type) \
206  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT); \
207  if (!wait_set->impl) { \
208  RCL_SET_ERROR_MSG("wait set is invalid"); \
209  return RCL_RET_WAIT_SET_INVALID; \
210  } \
211  RCL_CHECK_ARGUMENT_FOR_NULL(Type, RCL_RET_INVALID_ARGUMENT); \
212  if (!(wait_set->impl->Type ## _index < wait_set->size_of_ ## Type ## s)) { \
213  RCL_SET_ERROR_MSG(#Type "s set is full"); \
214  return RCL_RET_WAIT_SET_FULL; \
215  } \
216  size_t current_index = wait_set->impl->Type ## _index++; \
217  wait_set->Type ## s[current_index] = Type; \
218  /* Set optional output argument */ \
219  if (NULL != index) { \
220  *index = current_index; \
221  }
222 
223 #define SET_ADD_RMW(Type, RMWStorage, RMWCount) \
224  /* Also place into rmw storage. */ \
225  rmw_ ## Type ## _t * rmw_handle = rcl_ ## Type ## _get_rmw_handle(Type); \
226  RCL_CHECK_FOR_NULL_WITH_MSG( \
227  rmw_handle, rcl_get_error_string().str, return RCL_RET_ERROR); \
228  wait_set->impl->RMWStorage[current_index] = rmw_handle->data; \
229  wait_set->impl->RMWCount++;
230 
231 #define SET_CLEAR(Type) \
232  do { \
233  if (NULL != wait_set->Type ## s) { \
234  memset( \
235  (void *)wait_set->Type ## s, \
236  0, \
237  sizeof(rcl_ ## Type ## _t *) * wait_set->size_of_ ## Type ## s); \
238  wait_set->impl->Type ## _index = 0; \
239  } \
240  } while (false)
241 
242 #define SET_CLEAR_RMW(Type, RMWStorage, RMWCount) \
243  do { \
244  if (NULL != wait_set->impl->RMWStorage) { \
245  /* Also clear the rmw storage. */ \
246  memset( \
247  wait_set->impl->RMWStorage, \
248  0, \
249  sizeof(void *) * wait_set->impl->RMWCount); \
250  wait_set->impl->RMWCount = 0; \
251  } \
252  } while (false)
253 
254 #define SET_RESIZE(Type, ExtraDealloc, ExtraRealloc) \
255  do { \
256  rcl_allocator_t allocator = wait_set->impl->allocator; \
257  wait_set->size_of_ ## Type ## s = 0; \
258  wait_set->impl->Type ## _index = 0; \
259  if (0 == Type ## s_size) { \
260  if (wait_set->Type ## s) { \
261  allocator.deallocate((void *)wait_set->Type ## s, allocator.state); \
262  wait_set->Type ## s = NULL; \
263  } \
264  ExtraDealloc \
265  } else { \
266  wait_set->Type ## s = (const rcl_ ## Type ## _t **)allocator.reallocate( \
267  (void *)wait_set->Type ## s, sizeof(rcl_ ## Type ## _t *) * Type ## s_size, \
268  allocator.state); \
269  RCL_CHECK_FOR_NULL_WITH_MSG( \
270  wait_set->Type ## s, "allocating memory failed", return RCL_RET_BAD_ALLOC); \
271  memset((void *)wait_set->Type ## s, 0, sizeof(rcl_ ## Type ## _t *) * Type ## s_size); \
272  wait_set->size_of_ ## Type ## s = Type ## s_size; \
273  ExtraRealloc \
274  } \
275  } while (false)
276 
277 #define SET_RESIZE_RMW_DEALLOC(RMWStorage, RMWCount) \
278  /* Also deallocate the rmw storage. */ \
279  if (wait_set->impl->RMWStorage) { \
280  allocator.deallocate((void *)wait_set->impl->RMWStorage, allocator.state); \
281  wait_set->impl->RMWStorage = NULL; \
282  wait_set->impl->RMWCount = 0; \
283  }
284 
285 #define SET_RESIZE_RMW_REALLOC(Type, RMWStorage, RMWCount) \
286  /* Also resize the rmw storage. */ \
287  wait_set->impl->RMWCount = 0; \
288  wait_set->impl->RMWStorage = (void **)allocator.reallocate( \
289  wait_set->impl->RMWStorage, sizeof(void *) * Type ## s_size, allocator.state); \
290  if (!wait_set->impl->RMWStorage) { \
291  allocator.deallocate((void *)wait_set->Type ## s, allocator.state); \
292  wait_set->Type ## s = NULL; \
293  wait_set->size_of_ ## Type ## s = 0; \
294  RCL_SET_ERROR_MSG("allocating memory failed"); \
295  return RCL_RET_BAD_ALLOC; \
296  } \
297  memset(wait_set->impl->RMWStorage, 0, sizeof(void *) * Type ## s_size);
298 
299 /* Implementation-specific notes:
300  *
301  * Add the rmw representation to the underlying rmw array and increment
302  * the rmw array count.
303  */
304 rcl_ret_t
306  rcl_wait_set_t * wait_set,
307  const rcl_subscription_t * subscription,
308  size_t * index)
309 {
310  SET_ADD(subscription)
311  SET_ADD_RMW(subscription, rmw_subscriptions.subscribers, rmw_subscriptions.subscriber_count)
312  return RCL_RET_OK;
313 }
314 
315 /* Implementation-specific notes:
316  *
317  * Sets all of the entries in the underlying rmw array to null, and sets the
318  * count in the rmw array to 0.
319  */
320 rcl_ret_t
322 {
323  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT);
324  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set->impl, RCL_RET_WAIT_SET_INVALID);
325 
326  SET_CLEAR(subscription);
327  SET_CLEAR(guard_condition);
328  SET_CLEAR(client);
329  SET_CLEAR(service);
330  SET_CLEAR(event);
331  SET_CLEAR(timer);
332 
333  SET_CLEAR_RMW(
334  subscription,
335  rmw_subscriptions.subscribers,
336  rmw_subscriptions.subscriber_count);
337  SET_CLEAR_RMW(
338  guard_condition,
339  rmw_guard_conditions.guard_conditions,
340  rmw_guard_conditions.guard_condition_count);
341  SET_CLEAR_RMW(
342  clients,
343  rmw_clients.clients,
344  rmw_clients.client_count);
345  SET_CLEAR_RMW(
346  services,
347  rmw_services.services,
348  rmw_services.service_count);
349  SET_CLEAR_RMW(
350  events,
351  rmw_events.events,
352  rmw_events.event_count);
353 
354  return RCL_RET_OK;
355 }
356 
357 /* Implementation-specific notes:
358  *
359  * Similarly, the underlying rmw representation is reallocated and reset:
360  * all entries are set to null and the count is set to zero.
361  */
362 rcl_ret_t
364  rcl_wait_set_t * wait_set,
365  size_t subscriptions_size,
366  size_t guard_conditions_size,
367  size_t timers_size,
368  size_t clients_size,
369  size_t services_size,
370  size_t events_size)
371 {
372  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT);
373  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set->impl, RCL_RET_WAIT_SET_INVALID);
374  SET_RESIZE(
375  subscription,
376  SET_RESIZE_RMW_DEALLOC(
377  rmw_subscriptions.subscribers, rmw_subscriptions.subscriber_count),
378  SET_RESIZE_RMW_REALLOC(
379  subscription, rmw_subscriptions.subscribers, rmw_subscriptions.subscriber_count)
380  );
381  // Guard condition RCL size is the resize amount given
382  SET_RESIZE(guard_condition,;,;); // NOLINT
383 
384  // Guard condition RMW size needs to be guard conditions + timers
385  rmw_guard_conditions_t * rmw_gcs = &(wait_set->impl->rmw_guard_conditions);
386  const size_t num_rmw_gc = guard_conditions_size + timers_size;
387  // Clear added guard conditions
388  rmw_gcs->guard_condition_count = 0u;
389  if (0u == num_rmw_gc) {
390  if (rmw_gcs->guard_conditions) {
391  wait_set->impl->allocator.deallocate(
392  (void *)rmw_gcs->guard_conditions, wait_set->impl->allocator.state);
393  rmw_gcs->guard_conditions = NULL;
394  }
395  } else {
396  rmw_gcs->guard_conditions = (void **)wait_set->impl->allocator.reallocate(
397  rmw_gcs->guard_conditions, sizeof(void *) * num_rmw_gc, wait_set->impl->allocator.state);
398  if (!rmw_gcs->guard_conditions) {
399  // Deallocate rcl arrays to match unallocated rmw guard conditions
400  wait_set->impl->allocator.deallocate(
401  (void *)wait_set->guard_conditions, wait_set->impl->allocator.state);
402  wait_set->size_of_guard_conditions = 0u;
403  wait_set->guard_conditions = NULL;
404  wait_set->impl->allocator.deallocate(
405  (void *)wait_set->timers, wait_set->impl->allocator.state);
406  wait_set->size_of_timers = 0u;
407  wait_set->timers = NULL;
408  RCL_SET_ERROR_MSG("allocating memory failed");
409  return RCL_RET_BAD_ALLOC;
410  }
411  memset(rmw_gcs->guard_conditions, 0, sizeof(void *) * num_rmw_gc);
412  }
413 
414  SET_RESIZE(timer,;,;); // NOLINT
415  SET_RESIZE(
416  client,
417  SET_RESIZE_RMW_DEALLOC(
418  rmw_clients.clients, rmw_clients.client_count),
419  SET_RESIZE_RMW_REALLOC(
420  client, rmw_clients.clients, rmw_clients.client_count)
421  );
422  SET_RESIZE(
423  service,
424  SET_RESIZE_RMW_DEALLOC(
425  rmw_services.services, rmw_services.service_count),
426  SET_RESIZE_RMW_REALLOC(
427  service, rmw_services.services, rmw_services.service_count)
428  );
429  SET_RESIZE(
430  event,
431  SET_RESIZE_RMW_DEALLOC(
432  rmw_events.events, rmw_events.event_count),
433  SET_RESIZE_RMW_REALLOC(
434  event, rmw_events.events, rmw_events.event_count)
435  );
436 
437  return RCL_RET_OK;
438 }
439 
440 rcl_ret_t
442  rcl_wait_set_t * wait_set,
443  const rcl_guard_condition_t * guard_condition,
444  size_t * index)
445 {
446  SET_ADD(guard_condition)
447  SET_ADD_RMW(
448  guard_condition, rmw_guard_conditions.guard_conditions,
449  rmw_guard_conditions.guard_condition_count)
450 
451  return RCL_RET_OK;
452 }
453 
454 rcl_ret_t
456  rcl_wait_set_t * wait_set,
457  const rcl_timer_t * timer,
458  size_t * index)
459 {
460  SET_ADD(timer)
461  // Add timer guard conditions to end of rmw guard condtion set.
462  rcl_guard_condition_t * guard_condition = rcl_timer_get_guard_condition(timer);
463  if (NULL != guard_condition) {
464  // rcl_wait() will take care of moving these backwards and setting guard_condition_count.
465  const size_t index = wait_set->size_of_guard_conditions + (wait_set->impl->timer_index - 1);
466  rmw_guard_condition_t * rmw_handle = rcl_guard_condition_get_rmw_handle(guard_condition);
467  RCL_CHECK_FOR_NULL_WITH_MSG(
468  rmw_handle, rcl_get_error_string().str, return RCL_RET_ERROR);
469  wait_set->impl->rmw_guard_conditions.guard_conditions[index] = rmw_handle->data;
470  }
471  return RCL_RET_OK;
472 }
473 
474 rcl_ret_t
476  rcl_wait_set_t * wait_set,
477  const rcl_client_t * client,
478  size_t * index)
479 {
480  SET_ADD(client)
481  SET_ADD_RMW(client, rmw_clients.clients, rmw_clients.client_count)
482  return RCL_RET_OK;
483 }
484 
485 rcl_ret_t
487  rcl_wait_set_t * wait_set,
488  const rcl_service_t * service,
489  size_t * index)
490 {
491  SET_ADD(service)
492  SET_ADD_RMW(service, rmw_services.services, rmw_services.service_count)
493  return RCL_RET_OK;
494 }
495 
496 rcl_ret_t
498  rcl_wait_set_t * wait_set,
499  const rcl_event_t * event,
500  size_t * index)
501 {
502  SET_ADD(event)
503  SET_ADD_RMW(event, rmw_events.events, rmw_events.event_count)
504  wait_set->impl->rmw_events.events[current_index] = rmw_handle;
505  return RCL_RET_OK;
506 }
507 
508 rcl_ret_t
509 rcl_wait(rcl_wait_set_t * wait_set, int64_t timeout)
510 {
511  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT);
512  if (!rcl_wait_set_is_valid(wait_set)) {
513  RCL_SET_ERROR_MSG("wait set is invalid");
515  }
516  if (
517  wait_set->size_of_subscriptions == 0 &&
518  wait_set->size_of_guard_conditions == 0 &&
519  wait_set->size_of_timers == 0 &&
520  wait_set->size_of_clients == 0 &&
521  wait_set->size_of_services == 0 &&
522  wait_set->size_of_events == 0)
523  {
524  RCL_SET_ERROR_MSG("wait set is empty");
525  return RCL_RET_WAIT_SET_EMPTY;
526  }
527  // Calculate the timeout argument.
528  // By default, set the timer to block indefinitely if none of the below conditions are met.
529  rmw_time_t * timeout_argument = NULL;
530  rmw_time_t temporary_timeout_storage;
531  bool is_non_blocking = timeout == 0;
532 
533  for (uint64_t t_idx = 0; t_idx < wait_set->impl->timer_index; ++t_idx) {
534  if (!wait_set->timers[t_idx]) {
535  continue; // Skip NULL timers.
536  }
537  rmw_guard_conditions_t * rmw_gcs = &(wait_set->impl->rmw_guard_conditions);
538  size_t gc_idx = wait_set->size_of_guard_conditions + t_idx;
539  if (NULL != rmw_gcs->guard_conditions[gc_idx]) {
540  // This timer has a guard condition, so move it to make a legal wait set.
541  rmw_gcs->guard_conditions[rmw_gcs->guard_condition_count] =
542  rmw_gcs->guard_conditions[gc_idx];
543  ++(rmw_gcs->guard_condition_count);
544  }
545  }
546 
547  int64_t min_next_call_time[RCL_STEADY_TIME + 1];
548  rcl_clock_t * clocks[RCL_STEADY_TIME + 1] = {NULL, NULL, NULL, NULL};
549 
550  // asserts to make sure nobody changes the ordering of RCL_ROS_TIME,
551  // RCL_SYSTEM_TIME and RCL_STEADY_TIME
552  static_assert(RCL_ROS_TIME < RCL_STEADY_TIME + 1, "RCL_ROS_TIME won't fit in the array");
553  static_assert(RCL_SYSTEM_TIME < RCL_STEADY_TIME + 1, "RCL_SYSTEM_TIME won't fit in the array");
554  static_assert(RCL_STEADY_TIME < RCL_STEADY_TIME + 1, "RCL_STEADY_TIME won't fit in the array");
555 
556  min_next_call_time[RCL_ROS_TIME] = INT64_MAX;
557  min_next_call_time[RCL_SYSTEM_TIME] = INT64_MAX;
558  min_next_call_time[RCL_STEADY_TIME] = INT64_MAX;
559 
560  if (!is_non_blocking) {
561  for (size_t t_idx = 0; t_idx < wait_set->impl->timer_index; ++t_idx) {
562  if (!wait_set->timers[t_idx]) {
563  continue; // Skip NULL timers.
564  }
565 
566  rcl_clock_t * clock;
567  if (rcl_timer_clock(wait_set->timers[t_idx], &clock) != RCL_RET_OK) {
568  // should never happen
569  return RCL_RET_ERROR;
570  }
571 
572  if (clock->type == RCL_ROS_TIME) {
573  bool timer_override_active = false;
574  if (rcl_is_enabled_ros_time_override(clock, &timer_override_active) != RCL_RET_OK) {
575  // should never happen
576  return RCL_RET_ERROR;
577  }
578 
579  if (timer_override_active) {
580  // we need to check, it the timer is already ready
581  bool override_timer_is_ready = false;
582  if (rcl_timer_is_ready(wait_set->timers[t_idx], &override_timer_is_ready) != RCL_RET_OK) {
583  // should never happen
584  return RCL_RET_ERROR;
585  }
586 
587  if (override_timer_is_ready) {
588  // no need to search further for the timeout, we need to wake up instantly
589  is_non_blocking = true;
590  break;
591  }
592 
593  // if the timer override is active, there is no point in computing a wait time,
594  // as it might be on a total wrong time basis. In case this timer becomes ready,
595  // the guard_condition above will wake us.
596  continue;
597  }
598  }
599 
600  // get the time of the next call to the timer
601  int64_t next_call_time = INT64_MAX;
602  rcl_ret_t ret = rcl_timer_get_next_call_time(wait_set->timers[t_idx], &next_call_time);
603  if (ret == RCL_RET_TIMER_CANCELED) {
604  wait_set->timers[t_idx] = NULL;
605  continue;
606  }
607  if (ret != RCL_RET_OK) {
608  return ret; // The rcl error state should already be set.
609  }
610  if (next_call_time < min_next_call_time[clock->type]) {
611  clocks[clock->type] = clock;
612  min_next_call_time[clock->type] = next_call_time;
613  }
614  }
615  }
616 
617  if (is_non_blocking) {
618  temporary_timeout_storage.sec = 0;
619  temporary_timeout_storage.nsec = 0;
620  timeout_argument = &temporary_timeout_storage;
621  } else {
622  bool has_valid_timeout = timeout > 0;
623  int64_t min_timeout = has_valid_timeout ? timeout : INT64_MAX;
624 
625  // determine the min timeout of all clocks
626  for (size_t i = RCL_ROS_TIME; i <= RCL_STEADY_TIME; i++) {
627  if (clocks[i] == NULL) {
628  continue;
629  }
630 
631  int64_t cur_time;
632  rmw_ret_t ret = rcl_clock_get_now(clocks[i], &cur_time);
633  if (ret != RCL_RET_OK) {
634  return ret; // The rcl error state should already be set.
635  }
636 
637  int64_t timer_timeout = min_next_call_time[i] - cur_time;
638 
639  if (timer_timeout <= min_timeout) {
640  has_valid_timeout = true;
641  min_timeout = timer_timeout;
642  }
643  }
644 
645  // If min_timeout was negative, we need to wake up immediately.
646  if (min_timeout < 0) {
647  min_timeout = 0;
648  }
649  if (has_valid_timeout) {
650  temporary_timeout_storage.sec = RCL_NS_TO_S(min_timeout);
651  temporary_timeout_storage.nsec = min_timeout % 1000000000;
652  timeout_argument = &temporary_timeout_storage;
653  }
654  }
655 
656  // Wait.
657  rmw_ret_t ret = rmw_wait(
658  &wait_set->impl->rmw_subscriptions,
659  &wait_set->impl->rmw_guard_conditions,
660  &wait_set->impl->rmw_services,
661  &wait_set->impl->rmw_clients,
662  &wait_set->impl->rmw_events,
663  wait_set->impl->rmw_wait_set,
664  timeout_argument);
665 
666  // Items that are not ready will have been set to NULL by rmw_wait.
667  // We now update our handles accordingly.
668 
669  bool any_timer_is_ready = false;
670 
671  // Check for ready timers
672  // and set not ready timers (which includes canceled timers) to NULL.
673  size_t i;
674  for (i = 0; i < wait_set->impl->timer_index; ++i) {
675  if (!wait_set->timers[i]) {
676  continue;
677  }
678 
679  bool current_timer_is_ready = false;
680  rcl_ret_t ret = rcl_timer_is_ready(wait_set->timers[i], &current_timer_is_ready);
681  if (ret != RCL_RET_OK) {
682  return ret; // The rcl error state should already be set.
683  }
684  if (!current_timer_is_ready) {
685  wait_set->timers[i] = NULL;
686  } else {
687  any_timer_is_ready = true;
688  }
689  }
690  // Check for timeout, return RCL_RET_TIMEOUT only if it wasn't a timer.
691  if (ret != RMW_RET_OK && ret != RMW_RET_TIMEOUT) {
692  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
693  return RCL_RET_ERROR;
694  }
695  // Set corresponding rcl subscription handles NULL.
696  for (i = 0; i < wait_set->size_of_subscriptions; ++i) {
697  bool is_ready = wait_set->impl->rmw_subscriptions.subscribers[i] != NULL;
698  if (!is_ready) {
699  wait_set->subscriptions[i] = NULL;
700  }
701  }
702  // Set corresponding rcl guard_condition handles NULL.
703  for (i = 0; i < wait_set->size_of_guard_conditions; ++i) {
704  bool is_ready = wait_set->impl->rmw_guard_conditions.guard_conditions[i] != NULL;
705  if (!is_ready) {
706  wait_set->guard_conditions[i] = NULL;
707  }
708  }
709  // Set corresponding rcl client handles NULL.
710  for (i = 0; i < wait_set->size_of_clients; ++i) {
711  bool is_ready = wait_set->impl->rmw_clients.clients[i] != NULL;
712  if (!is_ready) {
713  wait_set->clients[i] = NULL;
714  }
715  }
716  // Set corresponding rcl service handles NULL.
717  for (i = 0; i < wait_set->size_of_services; ++i) {
718  bool is_ready = wait_set->impl->rmw_services.services[i] != NULL;
719  if (!is_ready) {
720  wait_set->services[i] = NULL;
721  }
722  }
723  // Set corresponding rcl event handles NULL.
724  for (i = 0; i < wait_set->size_of_events; ++i) {
725  bool is_ready = wait_set->impl->rmw_events.events[i] != NULL;
726  if (!is_ready) {
727  wait_set->events[i] = NULL;
728  }
729  }
730 
731  if (RMW_RET_TIMEOUT == ret && !any_timer_is_ready) {
732  return RCL_RET_TIMEOUT;
733  }
734  return RCL_RET_OK;
735 }
736 
737 #ifdef __cplusplus
738 }
739 #endif
#define RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, msg, fail_statement)
Check that the given allocator is initialized, or fail with a message.
Definition: allocator.h:56
rcutils_allocator_t rcl_allocator_t
Encapsulation of an allocator.
Definition: allocator.h:31
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.
Definition: context.c:94
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.
Definition: client.h:43
Encapsulation of a time source.
Definition: time.h:138
rcl_clock_type_t type
Clock type.
Definition: time.h:140
rmw_context_t rmw_context
rmw context.
Definition: context_impl.h:40
Encapsulates the non-global state of an init/shutdown cycle.
Definition: context.h:114
rcl_context_impl_t * impl
Implementation specific pointer.
Definition: context.h:120
Structure which encapsulates a ROS QoS event handle.
Definition: event.h:61
Handle for a rcl guard condition.
Structure which encapsulates a ROS Service.
Definition: service.h:43
Structure which encapsulates a ROS Subscription.
Definition: subscription.h:40
Structure which encapsulates a ROS Timer.
Definition: timer.h:41
Container for subscription's, guard condition's, etc to be waited on.
Definition: wait.h:42
const rcl_event_t ** events
Storage for event pointers.
Definition: wait.h:64
const rcl_timer_t ** timers
Storage for timer pointers.
Definition: wait.h:52
size_t size_of_timers
Number of timers.
Definition: wait.h:54
size_t size_of_events
Number of events.
Definition: wait.h:66
size_t size_of_subscriptions
Number of subscriptions.
Definition: wait.h:46
const rcl_service_t ** services
Storage for service pointers.
Definition: wait.h:60
const rcl_client_t ** clients
Storage for client pointers.
Definition: wait.h:56
const rcl_subscription_t ** subscriptions
Storage for subscription pointers.
Definition: wait.h:44
size_t size_of_guard_conditions
Number of guard_conditions.
Definition: wait.h:50
rcl_wait_set_impl_t * impl
Implementation specific storage.
Definition: wait.h:68
size_t size_of_clients
Number of clients.
Definition: wait.h:58
const rcl_guard_condition_t ** guard_conditions
Storage for guard condition pointers.
Definition: wait.h:48
size_t size_of_services
Number of services.
Definition: wait.h:62
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.
Definition: time.c:263
#define RCL_NS_TO_S
Convenience macro to convert nanoseconds to seconds.
Definition: time.h:39
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.
Definition: time.c:343
@ RCL_ROS_TIME
Use ROS time.
Definition: time.h:66
@ RCL_SYSTEM_TIME
Use system time.
Definition: time.h:68
@ RCL_STEADY_TIME
Use a steady clock time.
Definition: time.h:70
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.
Definition: timer.c:342
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.
Definition: timer.c:501
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.
Definition: timer.c:252
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.
Definition: timer.c:324
#define RCL_RET_WAIT_SET_EMPTY
Given rcl_wait_set_t is empty return code.
Definition: types.h:101
#define RCL_RET_WAIT_SET_INVALID
Invalid rcl_wait_set_t given return code.
Definition: types.h:99
#define RCL_RET_NOT_INIT
rcl_init() not yet called return code.
Definition: types.h:43
#define RCL_RET_ALREADY_INIT
rcl_init() already called return code.
Definition: types.h:41
#define RCL_RET_OK
Success return code.
Definition: types.h:27
#define RCL_RET_BAD_ALLOC
Failed to allocate memory return code.
Definition: types.h:33
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
Definition: types.h:35
#define RCL_RET_ERROR
Unspecified error return code.
Definition: types.h:29
#define RCL_RET_TIMER_CANCELED
Given timer was canceled return code.
Definition: types.h:95
#define RCL_RET_TIMEOUT
Timeout occurred return code.
Definition: types.h:31
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24
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.
Definition: wait.c:305
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.
Definition: wait.c:72
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.
Definition: wait.c:486
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.
Definition: wait.c:78
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.
Definition: wait.c:321
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.
Definition: wait.c:455
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.
Definition: wait.c:475
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_wait_set_fini(rcl_wait_set_t *wait_set)
Finalize a rcl wait set.
Definition: wait.c:167
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.
Definition: wait.c:509
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.
Definition: wait.c:363
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.
Definition: wait.c:193
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.
Definition: wait.c:64
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.
Definition: wait.c:497
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.
Definition: wait.c:441