Skip to content

Commit c686ba5

Browse files
committed
Merge remote-tracking branch 'forked/main'
2 parents 073322c + 646844f commit c686ba5

File tree

8 files changed

+117
-51
lines changed

8 files changed

+117
-51
lines changed

.github/workflows/generate-bindings.yml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ name: Generate bindings
22

33
on:
44
schedule:
5-
# Run the CI at 02:22 UTC every Tuesday
5+
# Run the CI at 00:11 UTC every night
66
# We pick an arbitrary time outside of most of the world's work hours
77
# to minimize the likelihood of running alongside a heavy workload.
8-
- cron: '22 2 * * 2'
8+
- cron: '11 0 * * *'
99
workflow_dispatch:
1010

1111
env:
@@ -44,7 +44,9 @@ jobs:
4444
container:
4545
image: ${{ matrix.docker_image }}
4646
steps:
47-
- uses: actions/checkout@v4
47+
- uses: actions/checkout@v5
48+
with:
49+
fetch-depth: 0
4850

4951
- name: Setup ROS environment
5052
uses: ros-tooling/[email protected]
@@ -61,10 +63,11 @@ jobs:
6163
run: curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
6264

6365
- name: Install bindgen
64-
run: cargo binstall -y bindgen
66+
run: cargo binstall -y bindgen-cli
6567

6668
- name: Generate bindings
6769
run: |
70+
. /opt/ros/${{ matrix.ros_distribution }}/setup.sh
6871
cd rclrs/src
6972
../generate_bindings.py rcl_wrapper.h ${{ matrix.ros_distribution }} .
7073
@@ -78,7 +81,7 @@ jobs:
7881
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
7982
git remote update origin
8083
CREATE_PR=0
81-
if !git checkout update-bindings-${{ matrix.ros_distribution }}; then
84+
if ! git checkout update-bindings-${{ matrix.ros_distribution }}; then
8285
CREATE_PR=1
8386
git checkout -b update-bindings-${{ matrix.ros_distribution }}
8487
fi

.github/workflows/release-plz.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ on:
55
branches:
66
- main
77

8+
env:
9+
RUSTFLAGS: "--cfg ros_distro=\"humble\""
10+
811
jobs:
912
release-plz-release:
1013
name: Release-plz release

rclrs/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.5.1](https://github.com/ros2-rust/ros2_rust/compare/v0.5.0...v0.5.1) - 2025-08-23
11+
12+
### Other
13+
14+
- Fix executor timeout ([#519](https://github.com/ros2-rust/ros2_rust/pull/519))
15+
1016
## [0.5.0](https://github.com/ros2-rust/ros2_rust/compare/v0.4.1...v0.5.0) - 2025-08-15
1117

1218
### Added

rclrs/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rclrs"
3-
version = "0.5.0"
3+
version = "0.5.1"
44
# This project is not military-sponsored, Jacob's employment contract just requires him to use this email address
55
authors = ["Esteve Fernandez <[email protected]>", "Nikolai Morin <[email protected]>", "Jacob Hassold <[email protected]>"]
66
edition = "2021"
@@ -45,10 +45,9 @@ tempfile = "3.3.0"
4545
tokio = { version = "1", features = ["rt", "time", "macros"] }
4646

4747
[build-dependencies]
48-
# Needed for FFI
49-
bindgen = "0.70"
5048
# Needed for uploading documentation to docs.rs
5149
cfg-if = "1.0.0"
50+
rustflags = "0.1"
5251

5352
[features]
5453
default = []
@@ -60,3 +59,4 @@ use_ros_shim = ["rosidl_runtime_rs/use_ros_shim"]
6059

6160
[package.metadata.docs.rs]
6261
features = ["use_ros_shim"]
62+
rustc-args = ["--cfg", "ros_distro=\"humble\""]

rclrs/build.rs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
1-
use std::{
2-
env,
3-
fs::read_dir,
4-
path::{Path, PathBuf},
5-
};
6-
1+
use std::{env, path::Path};
72
const AMENT_PREFIX_PATH: &str = "AMENT_PREFIX_PATH";
83
const ROS_DISTRO: &str = "ROS_DISTRO";
9-
const BINDGEN_WRAPPER: &str = "src/rcl_wrapper.h";
104

115
fn get_env_var_or_abort(env_var: &'static str) -> String {
126
if let Ok(value) = env::var(env_var) {
@@ -20,22 +14,37 @@ fn get_env_var_or_abort(env_var: &'static str) -> String {
2014
}
2115

2216
fn main() {
17+
println!(
18+
"cargo:rustc-check-cfg=cfg(ros_distro, values(\"{}\"))",
19+
vec!["humble", "jazzy", "kilted", "rolling"].join("\", \"")
20+
);
2321
let ros_distro = if let Ok(value) = env::var(ROS_DISTRO) {
2422
value
2523
} else {
26-
let error_msg =
27-
"ROS_DISTRO environment variable not set - please source ROS 2 installation first.";
24+
use rustflags;
2825
cfg_if::cfg_if! {
2926
if #[cfg(feature="use_ros_shim")] {
30-
println!("{}", error_msg);
31-
return;
27+
// // Look for --cfg ros_distro=<ros_distro>
28+
for flag in rustflags::from_env() {
29+
if matches!(flag, rustflags::Flag::Cfg { ref name, value : _ } if name == "ros_distro") {
30+
if let rustflags::Flag::Cfg {name:_, value: flag_value} = flag {
31+
println!("cargo:rustc-cfg=ros_distro=\"{}\"", flag_value.unwrap());
32+
return;
33+
} else {
34+
continue;
35+
}
36+
}
37+
}
38+
let error_msg =
39+
"When using the use_ros_shim feature, you must pass the ROS distribution you are targeting as a compiler flag with --cfg ros_distro=\"<ros_distro>\"";
40+
panic!("{}", error_msg);
3241
} else {
42+
let error_msg =
43+
"ROS_DISTRO environment variable not set - please source ROS 2 installation first.";
3344
panic!("{}", error_msg);
3445
}
3546
}
3647
};
37-
38-
println!("cargo:rustc-check-cfg=cfg(ros_distro, values(\"humble\", \"jazzy\", \"rolling\"))");
3948
println!("cargo:rustc-cfg=ros_distro=\"{ros_distro}\"");
4049

4150
let ament_prefix_paths = get_env_var_or_abort(AMENT_PREFIX_PATH);

rclrs/src/executor.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,3 +487,30 @@ impl CreateBasicExecutor for Context {
487487
self.create_executor(runtime)
488488
}
489489
}
490+
491+
#[cfg(test)]
492+
mod tests {
493+
use crate::*;
494+
use std::time::Duration;
495+
496+
#[test]
497+
fn test_timeout() {
498+
let context = Context::default();
499+
let mut executor = context.create_basic_executor();
500+
let _node = executor
501+
.create_node(&format!("test_timeout_{}", line!()))
502+
.unwrap();
503+
504+
for _ in 0..10 {
505+
let r = executor.spin(SpinOptions::default().timeout(Duration::from_millis(1)));
506+
assert_eq!(r.len(), 1);
507+
assert!(matches!(
508+
r[0],
509+
RclrsError::RclError {
510+
code: RclReturnCode::Timeout,
511+
..
512+
}
513+
));
514+
}
515+
}
516+
}

rclrs/src/rcl_bindings.rs

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,41 @@
1212
#![allow(missing_docs)]
1313

1414
cfg_if::cfg_if! {
15-
if #[cfg(feature="use_ros_shim")] {
15+
if #[cfg(ros_distro="humble")] {
1616
include!(
1717
concat!(
1818
env!("CARGO_MANIFEST_DIR"),
19-
"/src/rcl_bindings_generated_",
20-
"rolling", // rolling will always be a valid ROS distro
21-
".rs",
22-
)
23-
);
24-
25-
} else {
19+
"/src/rcl_bindings_generated_humble.rs",
20+
)
21+
);
22+
} else if #[cfg(ros_distro="jazzy")] {
2623
include!(
2724
concat!(
2825
env!("CARGO_MANIFEST_DIR"),
29-
"/src/rcl_bindings_generated_",
30-
env!("ROS_DISTRO"),
31-
".rs",
32-
)
33-
);
34-
35-
pub const RMW_GID_STORAGE_SIZE: usize = rmw_gid_storage_size_constant;
26+
"/src/rcl_bindings_generated_jazzy.rs",
27+
)
28+
);
29+
} else if #[cfg(ros_distro="kilted")] {
30+
include!(
31+
concat!(
32+
env!("CARGO_MANIFEST_DIR"),
33+
"/src/rcl_bindings_generated_kilted.rs",
34+
)
35+
);
36+
} else if #[cfg(ros_distro="rolling")] {
37+
include!(
38+
concat!(
39+
env!("CARGO_MANIFEST_DIR"),
40+
"/src/rcl_bindings_generated_rolling.rs",
41+
)
42+
);
43+
} else {
44+
panic!("Unsupported ROS distribution");
3645
}
3746
}
3847

48+
pub const RMW_GID_STORAGE_SIZE: usize = rmw_gid_storage_size_constant;
49+
3950
/// Wrapper around [`std::slice::from_raw_parts`] that accommodates the rcl
4051
/// convention of providing a null pointer to represent empty arrays. This
4152
/// violates the safety requirements of [`std::slice::from_raw_parts`].

rclrs/src/wait_set.rs

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -114,32 +114,39 @@ impl WaitSet {
114114
})
115115
}
116116
};
117+
117118
// SAFETY: The comments in rcl mention "This function cannot operate on the same wait set
118119
// in multiple threads, and the wait sets may not share content."
119-
// We cannot currently guarantee that the wait sets may not share content, but it is
120-
// mentioned in the doc comment for `add_subscription`.
121-
// Also, the rcl_wait_set is obviously valid.
122-
match unsafe { rcl_wait(&mut self.handle.rcl_wait_set, timeout_ns) }.ok() {
123-
Ok(_) => (),
120+
// * The we have exclusive access to rcl_wait_set because this is a
121+
// mutable borrow of WaitSet, which houses rcl_wait_set.
122+
// * We guarantee that the wait sets do not share content by funneling
123+
// the waitable of each primitive to one (and only one) WaitSet when
124+
// the primitive gets constructed. The waitables are never allowed to
125+
// move between wait sets.
126+
let r = match unsafe { rcl_wait(&mut self.handle.rcl_wait_set, timeout_ns) }.ok() {
127+
Ok(_) => Ok(()),
124128
Err(error) => match error {
125129
RclrsError::RclError { code, msg } => match code {
126-
RclReturnCode::WaitSetEmpty => (),
127-
_ => return Err(RclrsError::RclError { code, msg }),
130+
RclReturnCode::WaitSetEmpty => Ok(()),
131+
_ => Err(RclrsError::RclError { code, msg }),
128132
},
129-
_ => return Err(error),
133+
_ => Err(error),
130134
},
131-
}
135+
};
132136

133137
// Remove any waitables that are no longer being used
134138
for waitable in self.primitives.values_mut() {
135139
waitable.retain(|w| w.in_use());
136140
}
137141

138-
// For the remaining entities, check if they were activated and then run
139-
// the callback for those that were.
140-
for waiter in self.primitives.values_mut().flat_map(|v| v) {
141-
if waiter.is_ready(&self.handle.rcl_wait_set) {
142-
f(&mut *waiter.primitive)?;
142+
// Do not check the readiness if an error was reported.
143+
if !r.is_err() {
144+
// For the remaining entities, check if they were activated and then run
145+
// the callback for those that were.
146+
for waiter in self.primitives.values_mut().flat_map(|v| v) {
147+
if waiter.is_ready(&self.handle.rcl_wait_set) {
148+
f(&mut *waiter.primitive)?;
149+
}
143150
}
144151
}
145152

@@ -160,7 +167,7 @@ impl WaitSet {
160167
);
161168
}
162169

163-
Ok(())
170+
r
164171
}
165172

166173
/// Get a count of the different kinds of entities in the wait set.

0 commit comments

Comments
 (0)