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
+ } ;
3
6
4
7
// SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread
5
8
// they are running in. Therefore, this type can be safely sent to another thread.
@@ -22,6 +25,46 @@ pub enum CancelResponse {
22
25
Accept = 2 ,
23
26
}
24
27
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
+
25
68
pub struct ActionClient < T >
26
69
where
27
70
T : rosidl_runtime_rs:: Action ,
49
92
T : rosidl_runtime_rs:: Action ,
50
93
{
51
94
_marker : PhantomData < T > ,
95
+ pub ( crate ) handle : Arc < ActionServerHandle > ,
96
+ // goal_callback: (),
97
+ // cancel_callback: (),
98
+ // accepted_callback: (),
52
99
}
53
100
54
101
impl < T > ActionServer < T >
@@ -60,8 +107,50 @@ where
60
107
where
61
108
T : rosidl_runtime_rs:: Action ,
62
109
{
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
+
63
151
Ok ( Self {
64
152
_marker : Default :: default ( ) ,
153
+ handle,
65
154
} )
66
155
}
67
156
}
0 commit comments