ROS 2 rclcpp + rcl - humble  humble
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  static rcl_wait_set_t null_wait_set = {
67  .subscriptions = NULL,
68  .size_of_subscriptions = 0,
69  .guard_conditions = NULL,
70  .size_of_guard_conditions = 0,
71  .clients = NULL,
72  .size_of_clients = 0,
73  .services = NULL,
74  .size_of_services = 0,
75  .timers = NULL,
76  .size_of_timers = 0,
77  .events = NULL,
78  .size_of_events = 0,
79  .impl = NULL,
80  };
81  return null_wait_set;
82 }
83 
84 bool
86 {
87  return wait_set && wait_set->impl;
88 }
89 
90 static void
91 __wait_set_clean_up(rcl_wait_set_t * wait_set)
92 {
93  rcl_ret_t ret = rcl_wait_set_resize(wait_set, 0, 0, 0, 0, 0, 0);
94  (void)ret; // NO LINT
95  assert(RCL_RET_OK == ret); // Defensive, shouldn't fail with size 0.
96  if (wait_set->impl) {
97  wait_set->impl->allocator.deallocate(wait_set->impl, wait_set->impl->allocator.state);
98  wait_set->impl = NULL;
99  }
100 }
101 
102 rcl_ret_t
104  rcl_wait_set_t * wait_set,
105  size_t number_of_subscriptions,
106  size_t number_of_guard_conditions,
107  size_t number_of_timers,
108  size_t number_of_clients,
109  size_t number_of_services,
110  size_t number_of_events,
111  rcl_context_t * context,
112  rcl_allocator_t allocator)
113 {
114  RCUTILS_LOG_DEBUG_NAMED(
115  ROS_PACKAGE_NAME, "Initializing wait set with "
116  "'%zu' subscriptions, '%zu' guard conditions, '%zu' timers, '%zu' clients, '%zu' services",
117  number_of_subscriptions, number_of_guard_conditions, number_of_timers, number_of_clients,
118  number_of_services);
119  rcl_ret_t fail_ret = RCL_RET_ERROR;
120 
121  RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
122  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT);
123  if (rcl_wait_set_is_valid(wait_set)) {
124  RCL_SET_ERROR_MSG("wait_set already initialized, or memory was uninitialized.");
125  return RCL_RET_ALREADY_INIT;
126  }
127  // Make sure rcl has been initialized.
128  RCL_CHECK_ARGUMENT_FOR_NULL(context, RCL_RET_INVALID_ARGUMENT);
129  if (!rcl_context_is_valid(context)) {
130  RCL_SET_ERROR_MSG(
131  "the given context is not valid, "
132  "either rcl_init() was not called or rcl_shutdown() was called.");
133  return RCL_RET_NOT_INIT;
134  }
135  // Allocate space for the implementation struct.
136  wait_set->impl = (rcl_wait_set_impl_t *)allocator.allocate(
137  sizeof(rcl_wait_set_impl_t), allocator.state);
138  RCL_CHECK_FOR_NULL_WITH_MSG(
139  wait_set->impl, "allocating memory failed", return RCL_RET_BAD_ALLOC);
140  memset(wait_set->impl, 0, sizeof(rcl_wait_set_impl_t));
141  wait_set->impl->rmw_subscriptions.subscribers = NULL;
142  wait_set->impl->rmw_subscriptions.subscriber_count = 0;
143  wait_set->impl->rmw_guard_conditions.guard_conditions = NULL;
144  wait_set->impl->rmw_guard_conditions.guard_condition_count = 0;
145  wait_set->impl->rmw_clients.clients = NULL;
146  wait_set->impl->rmw_clients.client_count = 0;
147  wait_set->impl->rmw_services.services = NULL;
148  wait_set->impl->rmw_services.service_count = 0;
149  wait_set->impl->rmw_events.events = NULL;
150  wait_set->impl->rmw_events.event_count = 0;
151  // Set context.
152  wait_set->impl->context = context;
153  // Set allocator.
154  wait_set->impl->allocator = allocator;
155 
156  size_t num_conditions =
157  (2 * number_of_subscriptions) +
158  number_of_guard_conditions +
159  number_of_clients +
160  number_of_services +
161  number_of_events;
162 
163  wait_set->impl->rmw_wait_set = rmw_create_wait_set(&(context->impl->rmw_context), num_conditions);
164  if (!wait_set->impl->rmw_wait_set) {
165  goto fail;
166  }
167 
168  // Initialize subscription space.
170  wait_set, number_of_subscriptions, number_of_guard_conditions, number_of_timers,
171  number_of_clients, number_of_services, number_of_events);
172  if (RCL_RET_OK != ret) {
173  fail_ret = ret;
174  goto fail;
175  }
176  return RCL_RET_OK;
177 fail:
178  if (rcl_wait_set_is_valid(wait_set)) {
179  rmw_ret_t ret = rmw_destroy_wait_set(wait_set->impl->rmw_wait_set);
180  if (ret != RMW_RET_OK) {
181  fail_ret = RCL_RET_WAIT_SET_INVALID;
182  }
183  }
184  __wait_set_clean_up(wait_set);
185  return fail_ret;
186 }
187 
188 rcl_ret_t
190 {
191  rcl_ret_t result = RCL_RET_OK;
192  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT);
193 
194  if (rcl_wait_set_is_valid(wait_set)) {
195  rmw_ret_t ret = rmw_destroy_wait_set(wait_set->impl->rmw_wait_set);
196  if (ret != RMW_RET_OK) {
197  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
198  result = RCL_RET_WAIT_SET_INVALID;
199  }
200  __wait_set_clean_up(wait_set);
201  }
202  return result;
203 }
204 
205 rcl_ret_t
207 {
208  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT);
209  if (!rcl_wait_set_is_valid(wait_set)) {
210  RCL_SET_ERROR_MSG("wait set is invalid");
212  }
213  RCL_CHECK_ARGUMENT_FOR_NULL(allocator, RCL_RET_INVALID_ARGUMENT);
214  *allocator = wait_set->impl->allocator;
215  return RCL_RET_OK;
216 }
217 
218 #define SET_ADD(Type) \
219  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT); \
220  if (!wait_set->impl) { \
221  RCL_SET_ERROR_MSG("wait set is invalid"); \
222  return RCL_RET_WAIT_SET_INVALID; \
223  } \
224  RCL_CHECK_ARGUMENT_FOR_NULL(Type, RCL_RET_INVALID_ARGUMENT); \
225  if (!(wait_set->impl->Type ## _index < wait_set->size_of_ ## Type ## s)) { \
226  RCL_SET_ERROR_MSG(#Type "s set is full"); \
227  return RCL_RET_WAIT_SET_FULL; \
228  } \
229  size_t current_index = wait_set->impl->Type ## _index++; \
230  wait_set->Type ## s[current_index] = Type; \
231  /* Set optional output argument */ \
232  if (NULL != index) { \
233  *index = current_index; \
234  }
235 
236 #define SET_ADD_RMW(Type, RMWStorage, RMWCount) \
237  /* Also place into rmw storage. */ \
238  rmw_ ## Type ## _t * rmw_handle = rcl_ ## Type ## _get_rmw_handle(Type); \
239  RCL_CHECK_FOR_NULL_WITH_MSG( \
240  rmw_handle, rcl_get_error_string().str, return RCL_RET_ERROR); \
241  wait_set->impl->RMWStorage[current_index] = rmw_handle->data; \
242  wait_set->impl->RMWCount++;
243 
244 #define SET_CLEAR(Type) \
245  do { \
246  if (NULL != wait_set->Type ## s) { \
247  memset( \
248  (void *)wait_set->Type ## s, \
249  0, \
250  sizeof(rcl_ ## Type ## _t *) * wait_set->size_of_ ## Type ## s); \
251  wait_set->impl->Type ## _index = 0; \
252  } \
253  } while (false)
254 
255 #define SET_CLEAR_RMW(Type, RMWStorage, RMWCount) \
256  do { \
257  if (NULL != wait_set->impl->RMWStorage) { \
258  /* Also clear the rmw storage. */ \
259  memset( \
260  wait_set->impl->RMWStorage, \
261  0, \
262  sizeof(void *) * wait_set->impl->RMWCount); \
263  wait_set->impl->RMWCount = 0; \
264  } \
265  } while (false)
266 
267 #define SET_RESIZE(Type, ExtraDealloc, ExtraRealloc) \
268  do { \
269  rcl_allocator_t allocator = wait_set->impl->allocator; \
270  wait_set->size_of_ ## Type ## s = 0; \
271  wait_set->impl->Type ## _index = 0; \
272  if (0 == Type ## s_size) { \
273  if (wait_set->Type ## s) { \
274  allocator.deallocate((void *)wait_set->Type ## s, allocator.state); \
275  wait_set->Type ## s = NULL; \
276  } \
277  ExtraDealloc \
278  } else { \
279  wait_set->Type ## s = (const rcl_ ## Type ## _t **)allocator.reallocate( \
280  (void *)wait_set->Type ## s, sizeof(rcl_ ## Type ## _t *) * Type ## s_size, \
281  allocator.state); \
282  RCL_CHECK_FOR_NULL_WITH_MSG( \
283  wait_set->Type ## s, "allocating memory failed", return RCL_RET_BAD_ALLOC); \
284  memset((void *)wait_set->Type ## s, 0, sizeof(rcl_ ## Type ## _t *) * Type ## s_size); \
285  wait_set->size_of_ ## Type ## s = Type ## s_size; \
286  ExtraRealloc \
287  } \
288  } while (false)
289 
290 #define SET_RESIZE_RMW_DEALLOC(RMWStorage, RMWCount) \
291  /* Also deallocate the rmw storage. */ \
292  if (wait_set->impl->RMWStorage) { \
293  allocator.deallocate((void *)wait_set->impl->RMWStorage, allocator.state); \
294  wait_set->impl->RMWStorage = NULL; \
295  wait_set->impl->RMWCount = 0; \
296  }
297 
298 #define SET_RESIZE_RMW_REALLOC(Type, RMWStorage, RMWCount) \
299  /* Also resize the rmw storage. */ \
300  wait_set->impl->RMWCount = 0; \
301  wait_set->impl->RMWStorage = (void **)allocator.reallocate( \
302  wait_set->impl->RMWStorage, sizeof(void *) * Type ## s_size, allocator.state); \
303  if (!wait_set->impl->RMWStorage) { \
304  allocator.deallocate((void *)wait_set->Type ## s, allocator.state); \
305  wait_set->Type ## s = NULL; \
306  wait_set->size_of_ ## Type ## s = 0; \
307  RCL_SET_ERROR_MSG("allocating memory failed"); \
308  return RCL_RET_BAD_ALLOC; \
309  } \
310  memset(wait_set->impl->RMWStorage, 0, sizeof(void *) * Type ## s_size);
311 
312 /* Implementation-specific notes:
313  *
314  * Add the rmw representation to the underlying rmw array and increment
315  * the rmw array count.
316  */
317 rcl_ret_t
319  rcl_wait_set_t * wait_set,
320  const rcl_subscription_t * subscription,
321  size_t * index)
322 {
323  SET_ADD(subscription)
324  SET_ADD_RMW(subscription, rmw_subscriptions.subscribers, rmw_subscriptions.subscriber_count)
325  return RCL_RET_OK;
326 }
327 
328 /* Implementation-specific notes:
329  *
330  * Sets all of the entries in the underlying rmw array to null, and sets the
331  * count in the rmw array to 0.
332  */
333 rcl_ret_t
335 {
336  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT);
337  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set->impl, RCL_RET_WAIT_SET_INVALID);
338 
339  SET_CLEAR(subscription);
340  SET_CLEAR(guard_condition);
341  SET_CLEAR(client);
342  SET_CLEAR(service);
343  SET_CLEAR(event);
344  SET_CLEAR(timer);
345 
346  SET_CLEAR_RMW(
347  subscription,
348  rmw_subscriptions.subscribers,
349  rmw_subscriptions.subscriber_count);
350  SET_CLEAR_RMW(
351  guard_condition,
352  rmw_guard_conditions.guard_conditions,
353  rmw_guard_conditions.guard_condition_count);
354  SET_CLEAR_RMW(
355  clients,
356  rmw_clients.clients,
357  rmw_clients.client_count);
358  SET_CLEAR_RMW(
359  services,
360  rmw_services.services,
361  rmw_services.service_count);
362  SET_CLEAR_RMW(
363  events,
364  rmw_events.events,
365  rmw_events.event_count);
366 
367  return RCL_RET_OK;
368 }
369 
370 /* Implementation-specific notes:
371  *
372  * Similarly, the underlying rmw representation is reallocated and reset:
373  * all entries are set to null and the count is set to zero.
374  */
375 rcl_ret_t
377  rcl_wait_set_t * wait_set,
378  size_t subscriptions_size,
379  size_t guard_conditions_size,
380  size_t timers_size,
381  size_t clients_size,
382  size_t services_size,
383  size_t events_size)
384 {
385  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT);
386  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set->impl, RCL_RET_WAIT_SET_INVALID);
387  SET_RESIZE(
388  subscription,
389  SET_RESIZE_RMW_DEALLOC(
390  rmw_subscriptions.subscribers, rmw_subscriptions.subscriber_count),
391  SET_RESIZE_RMW_REALLOC(
392  subscription, rmw_subscriptions.subscribers, rmw_subscriptions.subscriber_count)
393  );
394  // Guard condition RCL size is the resize amount given
395  SET_RESIZE(guard_condition,;,;); // NOLINT
396 
397  // Guard condition RMW size needs to be guard conditions + timers
398  rmw_guard_conditions_t * rmw_gcs = &(wait_set->impl->rmw_guard_conditions);
399  const size_t num_rmw_gc = guard_conditions_size + timers_size;
400  // Clear added guard conditions
401  rmw_gcs->guard_condition_count = 0u;
402  if (0u == num_rmw_gc) {
403  if (rmw_gcs->guard_conditions) {
404  wait_set->impl->allocator.deallocate(
405  (void *)rmw_gcs->guard_conditions, wait_set->impl->allocator.state);
406  rmw_gcs->guard_conditions = NULL;
407  }
408  } else {
409  rmw_gcs->guard_conditions = (void **)wait_set->impl->allocator.reallocate(
410  rmw_gcs->guard_conditions, sizeof(void *) * num_rmw_gc, wait_set->impl->allocator.state);
411  if (!rmw_gcs->guard_conditions) {
412  // Deallocate rcl arrays to match unallocated rmw guard conditions
413  wait_set->impl->allocator.deallocate(
414  (void *)wait_set->guard_conditions, wait_set->impl->allocator.state);
415  wait_set->size_of_guard_conditions = 0u;
416  wait_set->guard_conditions = NULL;
417  wait_set->impl->allocator.deallocate(
418  (void *)wait_set->timers, wait_set->impl->allocator.state);
419  wait_set->size_of_timers = 0u;
420  wait_set->timers = NULL;
421  RCL_SET_ERROR_MSG("allocating memory failed");
422  return RCL_RET_BAD_ALLOC;
423  }
424  memset(rmw_gcs->guard_conditions, 0, sizeof(void *) * num_rmw_gc);
425  }
426 
427  SET_RESIZE(timer,;,;); // NOLINT
428  SET_RESIZE(
429  client,
430  SET_RESIZE_RMW_DEALLOC(
431  rmw_clients.clients, rmw_clients.client_count),
432  SET_RESIZE_RMW_REALLOC(
433  client, rmw_clients.clients, rmw_clients.client_count)
434  );
435  SET_RESIZE(
436  service,
437  SET_RESIZE_RMW_DEALLOC(
438  rmw_services.services, rmw_services.service_count),
439  SET_RESIZE_RMW_REALLOC(
440  service, rmw_services.services, rmw_services.service_count)
441  );
442  SET_RESIZE(
443  event,
444  SET_RESIZE_RMW_DEALLOC(
445  rmw_events.events, rmw_events.event_count),
446  SET_RESIZE_RMW_REALLOC(
447  event, rmw_events.events, rmw_events.event_count)
448  );
449 
450  return RCL_RET_OK;
451 }
452 
453 rcl_ret_t
455  rcl_wait_set_t * wait_set,
456  const rcl_guard_condition_t * guard_condition,
457  size_t * index)
458 {
459  SET_ADD(guard_condition)
460  SET_ADD_RMW(
461  guard_condition, rmw_guard_conditions.guard_conditions,
462  rmw_guard_conditions.guard_condition_count)
463 
464  return RCL_RET_OK;
465 }
466 
467 rcl_ret_t
469  rcl_wait_set_t * wait_set,
470  const rcl_timer_t * timer,
471  size_t * index)
472 {
473  SET_ADD(timer)
474  // Add timer guard conditions to end of rmw guard condtion set.
475  rcl_guard_condition_t * guard_condition = rcl_timer_get_guard_condition(timer);
476  if (NULL != guard_condition) {
477  // rcl_wait() will take care of moving these backwards and setting guard_condition_count.
478  const size_t index = wait_set->size_of_guard_conditions + (wait_set->impl->timer_index - 1);
479  rmw_guard_condition_t * rmw_handle = rcl_guard_condition_get_rmw_handle(guard_condition);
480  RCL_CHECK_FOR_NULL_WITH_MSG(
481  rmw_handle, rcl_get_error_string().str, return RCL_RET_ERROR);
482  wait_set->impl->rmw_guard_conditions.guard_conditions[index] = rmw_handle->data;
483  }
484  return RCL_RET_OK;
485 }
486 
487 rcl_ret_t
489  rcl_wait_set_t * wait_set,
490  const rcl_client_t * client,
491  size_t * index)
492 {
493  SET_ADD(client)
494  SET_ADD_RMW(client, rmw_clients.clients, rmw_clients.client_count)
495  return RCL_RET_OK;
496 }
497 
498 rcl_ret_t
500  rcl_wait_set_t * wait_set,
501  const rcl_service_t * service,
502  size_t * index)
503 {
504  SET_ADD(service)
505  SET_ADD_RMW(service, rmw_services.services, rmw_services.service_count)
506  return RCL_RET_OK;
507 }
508 
509 rcl_ret_t
511  rcl_wait_set_t * wait_set,
512  const rcl_event_t * event,
513  size_t * index)
514 {
515  SET_ADD(event)
516  SET_ADD_RMW(event, rmw_events.events, rmw_events.event_count)
517  wait_set->impl->rmw_events.events[current_index] = rmw_handle;
518  return RCL_RET_OK;
519 }
520 
521 rcl_ret_t
522 rcl_wait(rcl_wait_set_t * wait_set, int64_t timeout)
523 {
524  RCL_CHECK_ARGUMENT_FOR_NULL(wait_set, RCL_RET_INVALID_ARGUMENT);
525  if (!rcl_wait_set_is_valid(wait_set)) {
526  RCL_SET_ERROR_MSG("wait set is invalid");
528  }
529  if (
530  wait_set->size_of_subscriptions == 0 &&
531  wait_set->size_of_guard_conditions == 0 &&
532  wait_set->size_of_timers == 0 &&
533  wait_set->size_of_clients == 0 &&
534  wait_set->size_of_services == 0 &&
535  wait_set->size_of_events == 0)
536  {
537  RCL_SET_ERROR_MSG("wait set is empty");
538  return RCL_RET_WAIT_SET_EMPTY;
539  }
540  // Calculate the timeout argument.
541  // By default, set the timer to block indefinitely if none of the below conditions are met.
542  rmw_time_t * timeout_argument = NULL;
543  rmw_time_t temporary_timeout_storage;
544 
545  bool is_timer_timeout = false;
546  int64_t min_timeout = timeout > 0 ? timeout : INT64_MAX;
547  { // scope to prevent i from colliding below
548  uint64_t i = 0;
549  for (i = 0; i < wait_set->impl->timer_index; ++i) {
550  if (!wait_set->timers[i]) {
551  continue; // Skip NULL timers.
552  }
553  rmw_guard_conditions_t * rmw_gcs = &(wait_set->impl->rmw_guard_conditions);
554  size_t gc_idx = wait_set->size_of_guard_conditions + i;
555  if (NULL != rmw_gcs->guard_conditions[gc_idx]) {
556  // This timer has a guard condition, so move it to make a legal wait set.
557  rmw_gcs->guard_conditions[rmw_gcs->guard_condition_count] =
558  rmw_gcs->guard_conditions[gc_idx];
559  ++(rmw_gcs->guard_condition_count);
560  }
561  // use timer time to to set the rmw_wait timeout
562  // TODO(sloretz) fix spurious wake-ups on ROS_TIME timers with ROS_TIME enabled
563  int64_t timer_timeout = INT64_MAX;
564  rcl_ret_t ret = rcl_timer_get_time_until_next_call(wait_set->timers[i], &timer_timeout);
565  if (ret == RCL_RET_TIMER_CANCELED) {
566  wait_set->timers[i] = NULL;
567  continue;
568  }
569  if (ret != RCL_RET_OK) {
570  return ret; // The rcl error state should already be set.
571  }
572  if (timer_timeout < min_timeout) {
573  is_timer_timeout = true;
574  min_timeout = timer_timeout;
575  }
576  }
577  }
578 
579  if (timeout == 0) {
580  // Then it is non-blocking, so set the temporary storage to 0, 0 and pass it.
581  temporary_timeout_storage.sec = 0;
582  temporary_timeout_storage.nsec = 0;
583  timeout_argument = &temporary_timeout_storage;
584  } else if (timeout > 0 || is_timer_timeout) {
585  // If min_timeout was negative, we need to wake up immediately.
586  if (min_timeout < 0) {
587  min_timeout = 0;
588  }
589  temporary_timeout_storage.sec = RCL_NS_TO_S(min_timeout);
590  temporary_timeout_storage.nsec = min_timeout % 1000000000;
591  timeout_argument = &temporary_timeout_storage;
592  }
593 
594  // Wait.
595  rmw_ret_t ret = rmw_wait(
596  &wait_set->impl->rmw_subscriptions,
597  &wait_set->impl->rmw_guard_conditions,
598  &wait_set->impl->rmw_services,
599  &wait_set->impl->rmw_clients,
600  &wait_set->impl->rmw_events,
601  wait_set->impl->rmw_wait_set,
602  timeout_argument);
603 
604  // Items that are not ready will have been set to NULL by rmw_wait.
605  // We now update our handles accordingly.
606 
607  // Check for ready timers
608  // and set not ready timers (which includes canceled timers) to NULL.
609  size_t i;
610  for (i = 0; i < wait_set->impl->timer_index; ++i) {
611  if (!wait_set->timers[i]) {
612  continue;
613  }
614  bool is_ready = false;
615  rcl_ret_t ret = rcl_timer_is_ready(wait_set->timers[i], &is_ready);
616  if (ret != RCL_RET_OK) {
617  return ret; // The rcl error state should already be set.
618  }
619  if (!is_ready) {
620  wait_set->timers[i] = NULL;
621  }
622  }
623  // Check for timeout, return RCL_RET_TIMEOUT only if it wasn't a timer.
624  if (ret != RMW_RET_OK && ret != RMW_RET_TIMEOUT) {
625  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
626  return RCL_RET_ERROR;
627  }
628  // Set corresponding rcl subscription handles NULL.
629  for (i = 0; i < wait_set->size_of_subscriptions; ++i) {
630  bool is_ready = wait_set->impl->rmw_subscriptions.subscribers[i] != NULL;
631  if (!is_ready) {
632  wait_set->subscriptions[i] = NULL;
633  }
634  }
635  // Set corresponding rcl guard_condition handles NULL.
636  for (i = 0; i < wait_set->size_of_guard_conditions; ++i) {
637  bool is_ready = wait_set->impl->rmw_guard_conditions.guard_conditions[i] != NULL;
638  if (!is_ready) {
639  wait_set->guard_conditions[i] = NULL;
640  }
641  }
642  // Set corresponding rcl client handles NULL.
643  for (i = 0; i < wait_set->size_of_clients; ++i) {
644  bool is_ready = wait_set->impl->rmw_clients.clients[i] != NULL;
645  if (!is_ready) {
646  wait_set->clients[i] = NULL;
647  }
648  }
649  // Set corresponding rcl service handles NULL.
650  for (i = 0; i < wait_set->size_of_services; ++i) {
651  bool is_ready = wait_set->impl->rmw_services.services[i] != NULL;
652  if (!is_ready) {
653  wait_set->services[i] = NULL;
654  }
655  }
656  // Set corresponding rcl event handles NULL.
657  for (i = 0; i < wait_set->size_of_events; ++i) {
658  bool is_ready = wait_set->impl->rmw_events.events[i] != NULL;
659  if (!is_ready) {
660  wait_set->events[i] = NULL;
661  }
662  }
663 
664  if (RMW_RET_TIMEOUT == ret && !is_timer_timeout) {
665  return RCL_RET_TIMEOUT;
666  }
667  return RCL_RET_OK;
668 }
669 
670 #ifdef __cplusplus
671 }
672 #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:37
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:57
Handle for a rcl guard condition.
Structure which encapsulates a ROS Service.
Definition: service.h:37
Structure which encapsulates a ROS Subscription.
Definition: subscription.h:39
rcl_subscription_impl_t * impl
Pointer to the subscription implementation.
Definition: subscription.h:41
Structure which encapsulates a ROS Timer.
Definition: timer.h:39
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
#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_timer_get_time_until_next_call(const rcl_timer_t *timer, int64_t *time_until_next_call)
Calculate and retrieve the time until the next call in nanoseconds.
Definition: timer.c:313
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:447
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:295
#define RCL_RET_WAIT_SET_EMPTY
Given rcl_wait_set_t is empty return code.
Definition: types.h:98
#define RCL_RET_WAIT_SET_INVALID
Invalid rcl_wait_set_t given return code.
Definition: types.h:96
#define RCL_RET_NOT_INIT
rcl_init() not yet called return code.
Definition: types.h:42
#define RCL_RET_ALREADY_INIT
rcl_init() already called return code.
Definition: types.h:40
#define RCL_RET_OK
Success return code.
Definition: types.h:26
#define RCL_RET_BAD_ALLOC
Failed to allocate memory return code.
Definition: types.h:32
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
Definition: types.h:34
#define RCL_RET_ERROR
Unspecified error return code.
Definition: types.h:28
#define RCL_RET_TIMER_CANCELED
Given timer was canceled return code.
Definition: types.h:92
#define RCL_RET_TIMEOUT
Timeout occurred return code.
Definition: types.h:30
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:23
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:318
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:85
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:499
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:103
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:334
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:468
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:488
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:189
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:522
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:376
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:206
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:510
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:454