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