Skip to content

Commit 484fc38

Browse files
committed
Sketch out action server construction and destruction
This follows generally the same pattern as the service server. It required adding a typesupport function to the Action trait and pulling in some more rcl_action bindings.
1 parent 5afd784 commit 484fc38

File tree

5 files changed

+103
-6
lines changed

5 files changed

+103
-6
lines changed

rclrs/package.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616
<build_depend>libclang-dev</build_depend>
1717
<build_depend>rosidl_runtime_rs</build_depend>
1818
<depend>rcl</depend>
19+
<depend>rcl_action</depend>
1920
<depend>builtin_interfaces</depend>
2021
<depend>rcl_interfaces</depend>
2122
<depend>rosgraph_msgs</depend>
22-
23+
2324
<test_depend>test_msgs</test_depend>
2425

2526
<export>

rclrs/src/action.rs

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
use crate::{rcl_bindings::*, NodeHandle, RclrsError};
2-
use std::sync::{Arc, Mutex, MutexGuard};
1+
use crate::{error::ToResult, rcl_bindings::*, NodeHandle, RclrsError, ENTITY_LIFECYCLE_MUTEX};
2+
use std::{
3+
ffi::CString,
4+
sync::{atomic::AtomicBool, Arc, Mutex, MutexGuard},
5+
};
36

47
// SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread
58
// they are running in. Therefore, this type can be safely sent to another thread.
@@ -22,6 +25,46 @@ pub enum CancelResponse {
2225
Accept = 2,
2326
}
2427

28+
/// Manage the lifecycle of an `rcl_action_server_t`, including managing its dependencies
29+
/// on `rcl_node_t` and `rcl_context_t` by ensuring that these dependencies are
30+
/// [dropped after][1] the `rcl_action_server_t`.
31+
///
32+
/// [1]: <https://doc.rust-lang.org/reference/destructors.html>
33+
pub struct ActionServerHandle {
34+
rcl_action_server: Mutex<rcl_action_server_t>,
35+
node_handle: Arc<NodeHandle>,
36+
pub(crate) in_use_by_wait_set: Arc<AtomicBool>,
37+
}
38+
39+
impl ActionServerHandle {
40+
pub(crate) fn lock(&self) -> MutexGuard<rcl_action_server_t> {
41+
self.rcl_action_server.lock().unwrap()
42+
}
43+
}
44+
45+
impl Drop for ActionServerHandle {
46+
fn drop(&mut self) {
47+
let rcl_action_server = self.rcl_action_server.get_mut().unwrap();
48+
let mut rcl_node = self.node_handle.rcl_node.lock().unwrap();
49+
let _lifecycle_lock = ENTITY_LIFECYCLE_MUTEX.lock().unwrap();
50+
// SAFETY: The entity lifecycle mutex is locked to protect against the risk of
51+
// global variables in the rmw implementation being unsafely modified during cleanup.
52+
unsafe {
53+
rcl_action_server_fini(rcl_action_server, &mut *rcl_node);
54+
}
55+
}
56+
}
57+
58+
/// Trait to be implemented by concrete ActionServer structs.
59+
///
60+
/// See [`ActionServer<T>`] for an example
61+
pub trait ActionServerBase: Send + Sync {
62+
/// Internal function to get a reference to the `rcl` handle.
63+
fn handle(&self) -> &ActionServerHandle;
64+
// /// Tries to take a new request and run the callback with it.
65+
// fn execute(&self) -> Result<(), RclrsError>;
66+
}
67+
2568
pub struct ActionClient<T>
2669
where
2770
T: rosidl_runtime_rs::Action,
@@ -49,6 +92,10 @@ where
4992
T: rosidl_runtime_rs::Action,
5093
{
5194
_marker: PhantomData<T>,
95+
pub(crate) handle: Arc<ActionServerHandle>,
96+
// goal_callback: (),
97+
// cancel_callback: (),
98+
// accepted_callback: (),
5299
}
53100

54101
impl<T> ActionServer<T>
@@ -60,8 +107,50 @@ where
60107
where
61108
T: rosidl_runtime_rs::Action,
62109
{
110+
// SAFETY: Getting a zero-initialized value is always safe.
111+
let mut rcl_action_server = unsafe { rcl_action_get_zero_initialized_server() };
112+
let type_support = <T as rosidl_runtime_rs::Action>::get_type_support()
113+
as *const rosidl_action_type_support_t;
114+
let topic_c_string = CString::new(topic).map_err(|err| RclrsError::StringContainsNul {
115+
err,
116+
s: topic.into(),
117+
})?;
118+
119+
// SAFETY: No preconditions for this function.
120+
let action_server_options = unsafe { rcl_action_server_get_default_options() };
121+
122+
{
123+
let mut rcl_node = node_handle.rcl_node.lock().unwrap();
124+
let _lifecycle_lock = ENTITY_LIFECYCLE_MUTEX.lock().unwrap();
125+
unsafe {
126+
// SAFETY:
127+
// * The rcl_action_server is zero-initialized as mandated by this function.
128+
// * The rcl_node is kept alive by the NodeHandle it is a dependency of the action server.
129+
// * The topic name and the options are copied by this function, so they can be dropped
130+
// afterwards.
131+
// * The entity lifecycle mutex is locked to protect against the risk of global
132+
// variables in the rmw implementation being unsafely modified during initialization.
133+
rcl_action_server_init(
134+
&mut rcl_action_server,
135+
&mut *rcl_node,
136+
todo!(),
137+
type_support,
138+
topic_c_string.as_ptr(),
139+
&action_server_options as *const _,
140+
)
141+
.ok()?;
142+
}
143+
}
144+
145+
let handle = Arc::new(ActionServerHandle {
146+
rcl_action_server: Mutex::new(rcl_action_server),
147+
node_handle,
148+
in_use_by_wait_set: Arc::new(AtomicBool::new(false)),
149+
});
150+
63151
Ok(Self {
64152
_marker: Default::default(),
153+
handle,
65154
})
66155
}
67156
}

rclrs/src/rcl_wrapper.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
#include <rcl/graph.h>
22
#include <rcl/rcl.h>
3-
#include <rcl_action/types.h>
4-
#include <rcl_action/goal_handle.h>
3+
#include <rcl_action/rcl_action.h>
54
#include <rcl_yaml_param_parser/parser.h>
65
#include <rcutils/error_handling.h>
76
#include <rmw/types.h>
87
#include <rosidl_typesupport_introspection_c/field_types.h>
98
#include <rosidl_typesupport_introspection_c/message_introspection.h>
109

1110
const size_t rmw_gid_storage_size_constant = RMW_GID_STORAGE_SIZE;
12-
const size_t rcl_action_uuid_size_constant = UUID_SIZE;
11+
const size_t rcl_action_uuid_size_constant = UUID_SIZE;

rosidl_generator_rs/resource/action.rs.em

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ type_name = action_spec.namespaced_type.name
5151
type Goal = crate::@(subfolder)::rmw::@(type_name)_Goal;
5252
type Result = crate::@(subfolder)::rmw::@(type_name)_Result;
5353
type Feedback = crate::@(subfolder)::rmw::@(type_name)_Feedback;
54+
55+
fn get_type_support() -> *const std::os::raw::c_void {
56+
// SAFETY: No preconditions for this function.
57+
unsafe { rosidl_typesupport_c__get_action_type_support_handle__@(package_name)__@(subfolder)__@(type_name)() }
58+
}
5459
}
5560

5661
@[end for]

rosidl_runtime_rs/src/traits.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,7 @@ pub trait Action: 'static {
172172

173173
/// The feedback message associated with this service.
174174
type Feedback: Message;
175+
176+
/// Get a pointer to the correct `rosidl_action_type_support_t` structure.
177+
fn get_type_support() -> *const std::os::raw::c_void;
175178
}

0 commit comments

Comments
 (0)