nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
Loading...
Searching...
No Matches
executor.hpp
Go to the documentation of this file.
1// nros-cpp: Executor class
2// Freestanding C++ — no exceptions, no STL required
3
10#ifndef NROS_RCLCPP_EXECUTOR_HPP
11#define NROS_RCLCPP_EXECUTOR_HPP
12
13#include <cstdint>
14#include <cstddef>
15
16#include "rclcpp/result.hpp"
17// phase-417 stage 3 — the refusal vocabulary (`NROS_RCLCPP_REFUSE_*`,
18// `rclcpp::detail::refuse`, `rclcpp::detail::log_handle`) and the routed
19// `NROS_LOG_*` family both live here. `log.hpp` includes nothing of ours but
20// `std_detect.hpp`, so this cannot cycle.
21#include "rclcpp/logging.hpp"
22#include "rclcpp/detail/nros_cpp_config_generated.h"
23
24#include "rclcpp/detail/nros_cpp_ffi.h"
25
26// phase-427 W7 — `Node` is DEFINED in `rclcpp::` (RFC-0089: that namespace is
27// the home), so the forward declaration has to be there too.
28namespace rclcpp {
29class Node;
30}
31
32namespace rclcpp {
33
34// Forward declarations
35class NodeBuilder;
36
44using ShutdownCallback = void (*)(void* context);
45
72
85
92
116class Executor {
117 public:
119 Executor() : storage_(), initialized_(false) {}
120
130 static Result create(Executor& out, const char* locator = nullptr, uint8_t domain_id = 0) {
131 return create(out, locator, domain_id, "nros_cpp");
132 }
133
140 static Result create(Executor& out, const char* locator, uint8_t domain_id,
141 const char* session_name) {
142 // -3 = NROS_CPP_RET_INVALID_ARGUMENT (generated header).
143 if (session_name == nullptr) {
144 return Result(-3);
145 }
146 // Issue 1050 defect (3) — the same baked RMW selector `rclcpp::init()`
147 // reads. Both spellings of "open the one session" must apply it, or the
148 // bake means one thing on one path and nothing on the other — which is
149 // how `BACKENDS` came to read as a declaration that decided nothing.
150#ifdef NROS_ENTRY_RMW
151 const char* rmw = NROS_ENTRY_RMW;
152#else
153 const char* rmw = nullptr;
154#endif
156 nros_cpp_init_rmw(rmw, locator, domain_id, session_name, nullptr, out.storage_);
157 if (ret == 0) {
158 out.initialized_ = true;
159 }
160 return Result(ret);
161 }
162
171 static Result create_with_rmw(Executor& out, const char* rmw, const char* locator = nullptr,
172 uint8_t domain_id = 0, const char* session_name = "nros_cpp") {
173 if (session_name == nullptr) {
174 return Result(-3);
175 }
177 nros_cpp_init_rmw(rmw, locator, domain_id, session_name, nullptr, out.storage_);
178 if (ret == 0) {
179 out.initialized_ = true;
180 }
181 return Result(ret);
182 }
183
192 Result create_node(::rclcpp::Node& out, const char* name, const char* ns = nullptr);
193
201 NodeBuilder node_builder(const char* name);
202
229 // FIRST, before the `initialized_` check: the defect is in the VALUE,
230 // so it is knowable without a session and a caller must not have to
231 // stand one up to be told (RFC-0089 §"Where the refusal fires"). It
232 // used to be `timeout_ms.max(0)` Rust-side, which turned upstream's
233 // "block forever" into a 0 ms poll with no diagnostic at all.
234 //
235 // `NROS_RCLCPP_SAY_REFUSED`, not the legacy `NROS_ERROR`: the legacy
236 // sink is a no-op on every freestanding target, and a refusal nobody
237 // can read on the targets nano-ros exists for is issue 1019 again. It
238 // is also not the `"%s"` printf path, whose 256-byte buffer would cut
239 // the message off before the alternative.
240 if (timeout_ms < 0) {
243 }
244 if (!initialized_) return Result(ErrorCode::NotInitialized);
245 return Result(nros_cpp_spin_once(storage_, timeout_ms));
246 }
247
255 template <typename T = void> Result spin_once() {
256 static_assert(::rclcpp::detail::refuse<T>::value, NROS_RCLCPP_REFUSE_UNBOUNDED_SPIN);
258 }
259
272 if (!initialized_) return Result(ErrorCode::NotInitialized);
273 return Result(nros_cpp_executor_ping(storage_, timeout_ms));
274 }
275
297
308
315
322 if (!initialized_) return Result(ErrorCode::NotInitialized);
324 }
325
329 if (!initialized_) return Result(ErrorCode::NotInitialized);
331 }
332
341
358
366
374
387
395
425 if (!initialized_) return Result(ErrorCode::NotInitialized);
426 return Result(nros_cpp_spin(storage_, poll_ms));
427 }
428
449 if (!initialized_) return Result(ErrorCode::NotInitialized);
450 return Result(nros_cpp_executor_cancel(storage_));
451 }
452
470 bool is_spinning() const {
471 return nros_cpp_executor_is_spinning(const_cast<uint8_t*>(storage_));
472 }
473
483 if (!initialized_) return Result(ErrorCode::NotInitialized);
484 // Issue 0329 — the wall-clock budgeted loop (Phase 118.C: iteration-count
485 // budgeting collapses when `spin_once` returns early on a signaled
486 // condvar) now lives once, Rust-side, in `nros_cpp_spin_for`; forward to
487 // it so this and `rclcpp::spin()` share one implementation.
488 return Result(nros_cpp_spin_for(storage_, duration_ms, poll_ms));
489 }
490
492 bool ok() const { return initialized_; }
493
500 void* handle() { return storage_; }
501
533
551
560 if (!initialized_) return false;
561 return nros_cpp_remove_pre_shutdown_callback(storage_, handle.value()) == 0;
562 }
563
568 if (!initialized_) return false;
569 return nros_cpp_remove_on_shutdown_callback(storage_, handle.value()) == 0;
570 }
571
574 if (!initialized_) return Result::success();
575 nros_cpp_ret_t ret = nros_cpp_fini(storage_);
576 initialized_ = false;
577 return Result(ret);
578 }
579
582 if (initialized_) {
583 nros_cpp_fini(storage_);
584 initialized_ = false;
585 }
586 }
587
588 // Move semantics (non-copyable)
589 Executor(Executor&& other) : initialized_(other.initialized_) {
590 for (unsigned i = 0; i < sizeof(storage_); ++i) {
591 storage_[i] = other.storage_[i];
592 other.storage_[i] = 0;
593 }
594 other.initialized_ = false;
595 }
596
598 if (this != &other) {
599 if (initialized_) {
600 nros_cpp_fini(storage_);
601 }
602 for (unsigned i = 0; i < sizeof(storage_); ++i) {
603 storage_[i] = other.storage_[i];
604 other.storage_[i] = 0;
605 }
606 initialized_ = other.initialized_;
607 other.initialized_ = false;
608 }
609 return *this;
610 }
611
612 private:
613 Executor(const Executor&) = delete;
614 Executor& operator=(const Executor&) = delete;
615
616 alignas(8) uint8_t storage_[NROS_CPP_EXECUTOR_STORAGE_SIZE];
617 bool initialized_;
618};
619
620} // namespace rclcpp
621
622#endif // NROS_RCLCPP_EXECUTOR_HPP
Definition client.hpp:129
Definition executor.hpp:116
Result get_service_names_and_types(nros_cpp_names_and_types_visit_fn visit, void *ctx)
Definition executor.hpp:311
Result create_node(::rclcpp::Node &out, const char *name, const char *ns=nullptr)
Definition node.hpp:3084
bool ok() const
Check if the executor is initialized.
Definition executor.hpp:492
Result spin_once()
Definition executor.hpp:255
static Result create(Executor &out, const char *locator=nullptr, uint8_t domain_id=0)
Definition executor.hpp:130
Executor(Executor &&other)
Definition executor.hpp:589
Result spin(int32_t poll_ms=10)
Definition executor.hpp:424
Executor & operator=(Executor &&other)
Definition executor.hpp:597
Result spin_for(uint32_t duration_ms, int32_t poll_ms=10)
Definition executor.hpp:482
bool remove_pre_shutdown_callback(PreShutdownCallbackHandle handle)
Definition executor.hpp:559
Result get_publisher_names_and_types_by_node(const char *node_name, const char *node_namespace, nros_cpp_names_and_types_visit_fn visit, void *ctx)
phase-381 W4 — what one named node PUBLISHES, with the types.
Definition executor.hpp:334
Result count_publishers(const char *topic_name, size_t *out_count)
Definition executor.hpp:321
NodeBuilder node_builder(const char *name)
Definition node.hpp:3186
Result get_topic_names_and_types(nros_cpp_names_and_types_visit_fn visit, void *ctx)
Definition executor.hpp:304
Result add_on_shutdown_callback(ShutdownCallback callback, void *context=nullptr, OnShutdownCallbackHandle *out=nullptr)
Definition executor.hpp:543
Result get_node_names(nros_cpp_node_visit_fn visit, void *ctx)
Definition executor.hpp:293
void * handle()
Definition executor.hpp:500
Result get_subscription_names_and_types_by_node(const char *node_name, const char *node_namespace, nros_cpp_names_and_types_visit_fn visit, void *ctx)
Definition executor.hpp:350
bool remove_on_shutdown_callback(OnShutdownCallbackHandle handle)
Definition executor.hpp:567
Executor()
Default constructor — creates an uninitialized executor.
Definition executor.hpp:119
Result get_subscriptions_info_by_topic(const char *topic_name, nros_cpp_endpoint_info_visit_fn visit, void *ctx)
phase-381 W4 — the subscriptions on topic_name, one visit each.
Definition executor.hpp:389
Result ping(int32_t timeout_ms)
Definition executor.hpp:271
Result cancel()
Definition executor.hpp:448
Result add_pre_shutdown_callback(ShutdownCallback callback, void *context=nullptr, PreShutdownCallbackHandle *out=nullptr)
Definition executor.hpp:525
Result get_publishers_info_by_topic(const char *topic_name, nros_cpp_endpoint_info_visit_fn visit, void *ctx)
Definition executor.hpp:381
Result shutdown()
Shut down the executor and close the middleware connection.
Definition executor.hpp:573
Result spin_once(int32_t timeout_ms)
Definition executor.hpp:228
Result count_subscribers(const char *topic_name, size_t *out_count)
Definition executor.hpp:328
bool is_spinning() const
Definition executor.hpp:470
Result get_client_names_and_types_by_node(const char *node_name, const char *node_namespace, nros_cpp_names_and_types_visit_fn visit, void *ctx)
phase-381 W4 — what services one named node CALLS, with the types.
Definition executor.hpp:368
~Executor()
Destructor — shuts down if still active.
Definition executor.hpp:581
static Result create_with_rmw(Executor &out, const char *rmw, const char *locator=nullptr, uint8_t domain_id=0, const char *session_name="nros_cpp")
Definition executor.hpp:171
static Result create(Executor &out, const char *locator, uint8_t domain_id, const char *session_name)
Definition executor.hpp:140
Result get_service_names_and_types_by_node(const char *node_name, const char *node_namespace, nros_cpp_names_and_types_visit_fn visit, void *ctx)
phase-381 W4 — what services one named node SERVES, with the types.
Definition executor.hpp:360
Definition node.hpp:3107
Definition node.hpp:703
Definition executor.hpp:88
Definition executor.hpp:81
Definition result.hpp:216
static constexpr ResultOf success()
Named constructors.
Definition result.hpp:238
Definition executor.hpp:53
ShutdownCallbackHandle(nros_cpp_shutdown_callback_handle_t value)
Definition executor.hpp:61
bool valid() const
True when this handle came from a successful registration.
Definition executor.hpp:64
ShutdownCallbackHandle()
Definition executor.hpp:57
nros_cpp_shutdown_callback_handle_t value() const
The raw FFI value, for passing to the C entry points directly.
Definition executor.hpp:67
int nros_cpp_ret_t
Definition future.hpp:21
nros_cpp_ret_t nros_cpp_spin_once(void *handle, int32_t timeout_ms)
Definition rclcpp.hpp:75
ResultOf< void > Result
Definition result.hpp:246
@ Unsupported
Operation not implemented by the active backend.
rclcpp::Result, rclcpp::ErrorCode, and the RCLCPP_TRY macro.