nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | List of all members
nros::Executor Class Reference

#include <executor.hpp>

Public Member Functions

Result add_on_shutdown_callback (ShutdownCallback callback, void *context=nullptr, OnShutdownCallbackHandle *out=nullptr)
 
Result add_pre_shutdown_callback (ShutdownCallback callback, void *context=nullptr, PreShutdownCallbackHandle *out=nullptr)
 
Result count_publishers (const char *topic_name, size_t *out_count)
 
Result count_subscribers (const char *topic_name, size_t *out_count)
 
Result create_node (Node &out, const char *name, const char *ns=nullptr)
 
 Executor ()
 Default constructor — creates an uninitialized executor.
 
 Executor (Executor &&other)
 
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.
 
Result get_node_names (nros_cpp_node_visit_fn visit, void *ctx)
 
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.
 
Result get_publishers_info_by_topic (const char *topic_name, nros_cpp_endpoint_info_visit_fn visit, void *ctx)
 
Result get_service_names_and_types (nros_cpp_names_and_types_visit_fn visit, void *ctx)
 
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.
 
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)
 
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.
 
Result get_topic_names_and_types (nros_cpp_names_and_types_visit_fn visit, void *ctx)
 
void * handle ()
 
NodeBuilder node_builder (const char *name)
 
bool ok () const
 Check if the executor is initialized.
 
Executoroperator= (Executor &&other)
 
Result ping (int32_t timeout_ms)
 
bool remove_on_shutdown_callback (OnShutdownCallbackHandle handle)
 
bool remove_pre_shutdown_callback (PreShutdownCallbackHandle handle)
 
Result shutdown ()
 Shut down the executor and close the middleware connection.
 
Result spin (int32_t poll_ms=10)
 
Result spin (uint32_t duration_ms, int32_t poll_ms)
 
Result spin_for (uint32_t duration_ms, int32_t poll_ms=10)
 
Result spin_once (int32_t timeout_ms=10)
 
 ~Executor ()
 Destructor — shuts down if still active.
 

Static Public Member Functions

static Result create (Executor &out, const char *locator, uint8_t domain_id, const char *session_name)
 
static Result create (Executor &out, const char *locator=nullptr, uint8_t domain_id=0)
 
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")
 

Detailed Description

Explicit executor for managing ROS 2 entities and spinning.

Mirrors rclcpp::executors::SingleThreadedExecutor. Provides an explicit alternative to the global nros::init()/nros::spin_once() free functions.

The executor uses inline opaque storage — no heap allocation required.

Usage:

nros::Executor executor;
NROS_TRY(executor.create_node(node, "my_node"));
// Create publishers, subscriptions, etc. on node...
while (executor.ok()) {
executor.spin_once(10);
}
executor.shutdown();
Definition executor.hpp:106
static Result create(Executor &out, const char *locator=nullptr, uint8_t domain_id=0)
Definition executor.hpp:120
bool ok() const
Check if the executor is initialized.
Definition executor.hpp:393
Result shutdown()
Shut down the executor and close the middleware connection.
Definition executor.hpp:474
Result spin_once(int32_t timeout_ms=10)
Definition executor.hpp:198
Result create_node(Node &out, const char *name, const char *ns=nullptr)
Definition node.hpp:1048
Definition node.hpp:211
#define NROS_TRY(expr)
Definition result.hpp:128

Constructor & Destructor Documentation

◆ Executor() [1/2]

nros::Executor::Executor ( )
inline

Default constructor — creates an uninitialized executor.

◆ ~Executor()

nros::Executor::~Executor ( )
inline

Destructor — shuts down if still active.

◆ Executor() [2/2]

nros::Executor::Executor ( Executor &&  other)
inline

Member Function Documentation

◆ add_on_shutdown_callback()

Result nros::Executor::add_on_shutdown_callback ( ShutdownCallback  callback,
void *  context = nullptr,
OnShutdownCallbackHandle out = nullptr 
)
inline

Register a callback to run AFTER this executor's entities are torn down — rclcpp's Context::add_on_shutdown_callback / rclcpp::on_shutdown.

The entities are gone by the time it runs, so anything that needs the wire belongs in [add_pre_shutdown_callback] instead. Use this for what survives the middleware: releasing a GPIO, stopping a peripheral clock, writing a log line.

See also
add_pre_shutdown_callback for the parameter and error contract.

◆ add_pre_shutdown_callback()

Result nros::Executor::add_pre_shutdown_callback ( ShutdownCallback  callback,
void *  context = nullptr,
PreShutdownCallbackHandle out = nullptr 
)
inline

Register a callback to run BEFORE this executor's entities are torn down — rclcpp's Context::add_pre_shutdown_callback. Issue 0790.

This is the load-bearing half and the one with no workaround. The callback runs while every publisher, subscription, service and client still works, so a node can publish a final state, answer a last request, park an actuator or release a bus. After teardown it cannot: on a device there is no OS to reclaim a claimed SPI bus, an armed DMA channel or an actuator holding its last commanded position.

The callbacks run from [shutdown] (and from the destructor, which shuts down if still active). They are a CLEAN-STOP facility: a watchdog reset, a hard fault or an abort does not come through here, and nothing backed by a static table could promise otherwise.

Parameters
callbackFunction to invoke. Must not be null.
contextOpaque pointer handed back to callback. Must stay valid until the callback runs or is removed.
outReceives the handle remove_pre_shutdown_callback takes. Optional.
Returns
Success, ErrorCode::Full when the fixed table is exhausted (NROS_EXECUTOR_MAX_SHUTDOWN_CBS, default 2), or ErrorCode::NotInitialized.

◆ count_publishers()

Result nros::Executor::count_publishers ( const char *  topic_name,
size_t *  out_count 
)
inline

phase-381 W4 — how many publishers are visible on topic_name.

topic_name is a ROS name ("/chatter"). The count reflects what has been DISCOVERED, so it can be low right after startup and is never a proof of absence.

◆ count_subscribers()

Result nros::Executor::count_subscribers ( const char *  topic_name,
size_t *  out_count 
)
inline

phase-381 W4 — how many subscribers are visible on topic_name. See [count_publishers] for the caveats.

◆ create() [1/2]

static Result nros::Executor::create ( Executor out,
const char *  locator,
uint8_t  domain_id,
const char *  session_name 
)
inlinestatic

Create and initialize an executor with an explicit session name.

session_name flows through to the XRCE-DDS RMW backend as the per-process key derivation seed. Two processes sharing one XRCE Agent MUST use distinct names; see nros::init's named overload for the full discussion.

◆ create() [2/2]

static Result nros::Executor::create ( Executor out,
const char *  locator = nullptr,
uint8_t  domain_id = 0 
)
inlinestatic

Create and initialize an executor.

Opens a middleware connection. This is the explicit alternative to nros::init().

Parameters
outReceives the initialized executor.
locatorMiddleware locator (e.g., "tcp/127.0.0.1:7447"), or nullptr.
domain_idROS domain ID (0-232).
Returns
Result indicating success or failure.

◆ create_node()

Result nros::Executor::create_node ( Node out,
const char *  name,
const char *  ns = nullptr 
)
inline

Create a node on this executor.

Parameters
outReceives the initialized node.
nameNode name (null-terminated).
nsNode namespace (null-terminated), or nullptr for "/".
Returns
Result indicating success or failure.

◆ create_with_rmw()

static Result nros::Executor::create_with_rmw ( Executor out,
const char *  rmw,
const char *  locator = nullptr,
uint8_t  domain_id = 0,
const char *  session_name = "nros_cpp" 
)
inlinestatic

Issue 1050 defect (3) — [create](Executor::create) against a named RMW backend.

rmw is the baked rung of RFC-0045's precedence model A: a hosted $NROS_RMW still wins, and nullptr / "" means "name none", which resolves only when exactly one backend is registered. See nros::init_with_rmw for why naming one is sometimes the only way to get the backend the image declared.

◆ get_client_names_and_types_by_node()

Result nros::Executor::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 
)
inline

phase-381 W4 — what services one named node CALLS, with the types.

◆ get_node_names()

Result nros::Executor::get_node_names ( nros_cpp_node_visit_fn  visit,
void *  ctx 
)
inline

phase-381 W4 — every node on the graph, with its namespace.

visit(name, ns, enclave) is called once per node; enclave is nullptr where the backend tracks none, which is what lets one call answer both rmw_get_node_names forms. Return false to stop early.

Takes a plain function pointer plus ctx rather than a std::function: this header is compiled -nostdinc++ against Zephyr's minimal libcpp in embedded builds, where <functional> does not exist (issue 0112). Every string is BORROWED for the duration of the call.

Reports what has been DISCOVERED and never blocks. The first call after startup legitimately sees a partial graph — the backend keeps a standing query fed by the spin loop — so poll rather than calling once and concluding. An empty enumeration means "nobody seen yet", never "nobody exists", and ErrorCode::Unsupported (a backend with no graph) stays distinct from it.

◆ get_publisher_names_and_types_by_node()

Result nros::Executor::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 
)
inline

phase-381 W4 — what one named node PUBLISHES, with the types.

◆ get_publishers_info_by_topic()

Result nros::Executor::get_publishers_info_by_topic ( const char *  topic_name,
nros_cpp_endpoint_info_visit_fn  visit,
void *  ctx 
)
inline

phase-381 W4 — the publishers on topic_name, one visit each.

The endpoint carries no QoS: the GRANTED profile is what would answer "why is nothing arriving", no backend can read one back yet, and reporting the remote's DECLARED profile would be a confident wrong answer.

◆ get_service_names_and_types()

Result nros::Executor::get_service_names_and_types ( nros_cpp_names_and_types_visit_fn  visit,
void *  ctx 
)
inline

phase-381 W4 — every service on the graph, with its types. As [get_topic_names_and_types], over servers and clients.

◆ get_service_names_and_types_by_node()

Result nros::Executor::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 
)
inline

phase-381 W4 — what services one named node SERVES, with the types.

◆ get_subscription_names_and_types_by_node()

Result nros::Executor::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 
)
inline

phase-381 W4 — what one named node SUBSCRIBES to, with the types.

subscription, not subscriber: the C++ surface takes rclcpp's vocabulary (create_subscription, Subscription<T>, get_subscriptions_info_by_topic). rclcpp has no *_by_node form for subscriptions at all, so the WORD comes from its vocabulary rather than from a method it lacks. The C surface says subscriber because rcl does, and the vtable slot because upstream rmw does.

◆ get_subscriptions_info_by_topic()

Result nros::Executor::get_subscriptions_info_by_topic ( const char *  topic_name,
nros_cpp_endpoint_info_visit_fn  visit,
void *  ctx 
)
inline

phase-381 W4 — the subscriptions on topic_name, one visit each.

◆ get_topic_names_and_types()

Result nros::Executor::get_topic_names_and_types ( nros_cpp_names_and_types_visit_fn  visit,
void *  ctx 
)
inline

phase-381 W4 — every topic on the graph, with the types on it.

visit(name, types, types_count) is called once per distinct TOPIC: a topic carrying two types is one call with two entries, not two calls. types_count may legitimately be 0 on a partially discovered graph. Same discovery caveat as [get_node_names].

◆ handle()

void * nros::Executor::handle ( )
inline

Get the raw executor storage (for advanced use).

Non-const: downstream FFI mutates executor state through this pointer (e.g. spin_once), so exposing it as const would be a lie. Callers that only need to observe the handle should do so through methods on Executor directly.

◆ node_builder()

NodeBuilder nros::Executor::node_builder ( const char *  name)
inline

Phase 104.C.9 — chainable Node-creation builder.

Mirrors Rust's Executor::node_builder(name).rmw(...).locator(...) .domain_id(...).namespace(...).sched(...).build(). Use this when binding a Node to a specific RMW backend, locator, domain, or SchedContext. Definition follows the full NodeBuilder class in node.hpp.

◆ ok()

bool nros::Executor::ok ( ) const
inline

Check if the executor is initialized.

◆ operator=()

Executor & nros::Executor::operator= ( Executor &&  other)
inline

◆ ping()

Result nros::Executor::ping ( int32_t  timeout_ms)
inline

Phase 124.F.3 — session-level connectivity probe.

Wire-level round-trip ("is the peer / agent / router reachable?") with timeout_ms budget. Returns Result::success() on reply, ErrorCode::Timeout on no reply, ErrorCode::Unsupported when the active backend can't probe. Mirrors micro-ROS's rmw_uros_ping_agent.

Useful for reconnect-on-link-loss patterns — call periodically and tear down / re-open the executor on timeout.

◆ remove_on_shutdown_callback()

bool nros::Executor::remove_on_shutdown_callback ( OnShutdownCallbackHandle  handle)
inline

Remove a registered on-shutdown callback — rclcpp's Context::remove_on_shutdown_callback.

See also
remove_pre_shutdown_callback

◆ remove_pre_shutdown_callback()

bool nros::Executor::remove_pre_shutdown_callback ( PreShutdownCallbackHandle  handle)
inline

Remove a registered pre-shutdown callback — rclcpp's Context::remove_pre_shutdown_callback.

bool for rclcpp's reason: "it was not there" is an ordinary answer (the callback may already have run), not an error.

Returns
true when handle named a live callback.

◆ shutdown()

Result nros::Executor::shutdown ( )
inline

Shut down the executor and close the middleware connection.

◆ spin() [1/2]

Result nros::Executor::spin ( int32_t  poll_ms = 10)
inline

Spin until this executor is shut down (blocking) — rclcpp::Executor::spin.

Issue 0338 — this verb used to mean the OPPOSITE here: spin was the BOUNDED form and there was no way to say "spin forever" on an executor, while spin blocks until shutdown in rclcpp, in the C API (nros_executor_spin) and in Rust. A user porting rclcpp code wrote exec.spin() and it did not compile; reaching for spin(ms) instead silently returned early. The bounded form is now [spin_for].

Exit condition: [shutdown] on THIS executor (the executor-scoped analogue of rclcpp exiting when its context is shut down) — typically from a signal handler or another thread. Returns the first non-success spin_once result, or success after a clean shutdown.

Parameters
poll_msIndividual spin_once timeout (default: 10ms).

◆ spin() [2/2]

Result nros::Executor::spin ( uint32_t  duration_ms,
int32_t  poll_ms 
)
inline

Deprecated alias for [spin_for] — issue 0338.

Kept for one release so existing code compiles. The two-argument form is unambiguous (the new spin() takes at most one argument), so this overload only ever matches a call that meant the BOUNDED verb.

◆ spin_for()

Result nros::Executor::spin_for ( uint32_t  duration_ms,
int32_t  poll_ms = 10 
)
inline

Spin for a bounded duration (blocking) — rclcpp's spin_some(max_duration).

Repeatedly calls spin_once() until duration_ms has elapsed.

Parameters
duration_msTotal time to spin, in milliseconds.
poll_msIndividual spin_once timeout (default: 10ms).
Returns
Result from the last spin_once call.

◆ spin_once()

Result nros::Executor::spin_once ( int32_t  timeout_ms = 10)
inline

Drive transport I/O and dispatch callbacks.

Processes pending subscriptions, timers, services, and guard conditions. Call this periodically in your main loop.

Parameters
timeout_msMaximum time to block waiting for I/O.
Returns
Result indicating success or failure.

The documentation for this class was generated from the following files: