@@ -24,7 +24,9 @@ use std::time::Duration;
2424use std:: vec:: Vec ;
2525
2626mod exclusivity_guard;
27+ mod guard_condition;
2728use exclusivity_guard:: * ;
29+ pub use guard_condition:: * ;
2830
2931/// A struct for waiting on subscriptions and other waitable entities to become ready.
3032pub struct WaitSet {
@@ -36,6 +38,8 @@ pub struct WaitSet {
3638 // even in the error case.
3739 subscriptions : Vec < ExclusivityGuard < Arc < dyn SubscriptionBase > > > ,
3840 clients : Vec < ExclusivityGuard < Arc < dyn ClientBase > > > ,
41+ // The guard conditions that are currently registered in the wait set.
42+ guard_conditions : Vec < ExclusivityGuard < Arc < GuardCondition > > > ,
3943 services : Vec < ExclusivityGuard < Arc < dyn ServiceBase > > > ,
4044}
4145
@@ -45,6 +49,8 @@ pub struct ReadyEntities {
4549 pub subscriptions : Vec < Arc < dyn SubscriptionBase > > ,
4650 /// A list of clients that have potentially received responses.
4751 pub clients : Vec < Arc < dyn ClientBase > > ,
52+ /// A list of guard conditions that have been triggered.
53+ pub guard_conditions : Vec < Arc < GuardCondition > > ,
4854 /// A list of services that have potentially received requests.
4955 pub services : Vec < Arc < dyn ServiceBase > > ,
5056}
@@ -105,6 +111,7 @@ impl WaitSet {
105111 rcl_wait_set,
106112 _rcl_context_mtx : context. rcl_context_mtx . clone ( ) ,
107113 subscriptions : Vec :: new ( ) ,
114+ guard_conditions : Vec :: new ( ) ,
108115 clients : Vec :: new ( ) ,
109116 services : Vec :: new ( ) ,
110117 } )
@@ -116,6 +123,7 @@ impl WaitSet {
116123 /// [`WaitSet::new`].
117124 pub fn clear ( & mut self ) {
118125 self . subscriptions . clear ( ) ;
126+ self . guard_conditions . clear ( ) ;
119127 self . clients . clear ( ) ;
120128 self . services . clear ( ) ;
121129 // This cannot fail – the rcl_wait_set_clear function only checks that the input handle is
@@ -159,6 +167,38 @@ impl WaitSet {
159167 Ok ( ( ) )
160168 }
161169
170+ /// Adds a guard condition to the wait set.
171+ ///
172+ /// # Errors
173+ /// - If the guard condition was already added to this wait set or another one,
174+ /// [`AlreadyAddedToWaitSet`][1] will be returned
175+ /// - If the number of guard conditions in the wait set is larger than the
176+ /// capacity set in [`WaitSet::new`], [`WaitSetFull`][2] will be returned
177+ ///
178+ /// [1]: crate::RclrsError
179+ /// [2]: crate::RclReturnCode
180+ pub fn add_guard_condition (
181+ & mut self ,
182+ guard_condition : Arc < GuardCondition > ,
183+ ) -> Result < ( ) , RclrsError > {
184+ let exclusive_guard_condition = ExclusivityGuard :: new (
185+ Arc :: clone ( & guard_condition) ,
186+ Arc :: clone ( & guard_condition. in_use_by_wait_set ) ,
187+ ) ?;
188+
189+ unsafe {
190+ // SAFETY: Safe if the wait set and guard condition are initialized
191+ rcl_wait_set_add_guard_condition (
192+ & mut self . rcl_wait_set ,
193+ & * guard_condition. rcl_guard_condition . lock ( ) . unwrap ( ) ,
194+ std:: ptr:: null_mut ( ) ,
195+ )
196+ . ok ( ) ?;
197+ }
198+ self . guard_conditions . push ( exclusive_guard_condition) ;
199+ Ok ( ( ) )
200+ }
201+
162202 /// Adds a client to the wait set.
163203 ///
164204 /// # Errors
@@ -262,6 +302,7 @@ impl WaitSet {
262302 let mut ready_entities = ReadyEntities {
263303 subscriptions : Vec :: new ( ) ,
264304 clients : Vec :: new ( ) ,
305+ guard_conditions : Vec :: new ( ) ,
265306 services : Vec :: new ( ) ,
266307 } ;
267308 for ( i, subscription) in self . subscriptions . iter ( ) . enumerate ( ) {
@@ -275,6 +316,7 @@ impl WaitSet {
275316 . push ( Arc :: clone ( & subscription. waitable ) ) ;
276317 }
277318 }
319+
278320 for ( i, client) in self . clients . iter ( ) . enumerate ( ) {
279321 // SAFETY: The `clients` entry is an array of pointers, and this dereferencing is
280322 // equivalent to
@@ -284,6 +326,19 @@ impl WaitSet {
284326 ready_entities. clients . push ( Arc :: clone ( & client. waitable ) ) ;
285327 }
286328 }
329+
330+ for ( i, guard_condition) in self . guard_conditions . iter ( ) . enumerate ( ) {
331+ // SAFETY: The `clients` entry is an array of pointers, and this dereferencing is
332+ // equivalent to
333+ // https://github.com/ros2/rcl/blob/35a31b00a12f259d492bf53c0701003bd7f1745c/rcl/include/rcl/wait.h#L419
334+ let wait_set_entry = unsafe { * self . rcl_wait_set . guard_conditions . add ( i) } ;
335+ if !wait_set_entry. is_null ( ) {
336+ ready_entities
337+ . guard_conditions
338+ . push ( Arc :: clone ( & guard_condition. waitable ) ) ;
339+ }
340+ }
341+
287342 for ( i, service) in self . services . iter ( ) . enumerate ( ) {
288343 // SAFETY: The `services` entry is an array of pointers, and this dereferencing is
289344 // equivalent to
@@ -309,4 +364,20 @@ mod tests {
309364 assert_send :: < WaitSet > ( ) ;
310365 assert_sync :: < WaitSet > ( ) ;
311366 }
367+
368+ #[ test]
369+ fn guard_condition_in_wait_set_readies ( ) -> Result < ( ) , RclrsError > {
370+ let context = Context :: new ( [ ] ) ?;
371+
372+ let guard_condition = Arc :: new ( GuardCondition :: new ( & context) ) ;
373+
374+ let mut wait_set = WaitSet :: new ( 0 , 1 , 0 , 0 , 0 , 0 , & context) ?;
375+ wait_set. add_guard_condition ( Arc :: clone ( & guard_condition) ) ?;
376+ guard_condition. trigger ( ) ?;
377+
378+ let readies = wait_set. wait ( Some ( std:: time:: Duration :: from_millis ( 10 ) ) ) ?;
379+ assert ! ( readies. guard_conditions. contains( & guard_condition) ) ;
380+
381+ Ok ( ( ) )
382+ }
312383}
0 commit comments