@@ -24,7 +24,9 @@ use std::time::Duration;
24
24
use std:: vec:: Vec ;
25
25
26
26
mod exclusivity_guard;
27
+ mod guard_condition;
27
28
use exclusivity_guard:: * ;
29
+ pub use guard_condition:: * ;
28
30
29
31
/// A struct for waiting on subscriptions and other waitable entities to become ready.
30
32
pub struct WaitSet {
@@ -36,6 +38,8 @@ pub struct WaitSet {
36
38
// even in the error case.
37
39
subscriptions : Vec < ExclusivityGuard < Arc < dyn SubscriptionBase > > > ,
38
40
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 > > > ,
39
43
services : Vec < ExclusivityGuard < Arc < dyn ServiceBase > > > ,
40
44
}
41
45
@@ -45,6 +49,8 @@ pub struct ReadyEntities {
45
49
pub subscriptions : Vec < Arc < dyn SubscriptionBase > > ,
46
50
/// A list of clients that have potentially received responses.
47
51
pub clients : Vec < Arc < dyn ClientBase > > ,
52
+ /// A list of guard conditions that have been triggered.
53
+ pub guard_conditions : Vec < Arc < GuardCondition > > ,
48
54
/// A list of services that have potentially received requests.
49
55
pub services : Vec < Arc < dyn ServiceBase > > ,
50
56
}
@@ -105,6 +111,7 @@ impl WaitSet {
105
111
rcl_wait_set,
106
112
_rcl_context_mtx : context. rcl_context_mtx . clone ( ) ,
107
113
subscriptions : Vec :: new ( ) ,
114
+ guard_conditions : Vec :: new ( ) ,
108
115
clients : Vec :: new ( ) ,
109
116
services : Vec :: new ( ) ,
110
117
} )
@@ -116,6 +123,7 @@ impl WaitSet {
116
123
/// [`WaitSet::new`].
117
124
pub fn clear ( & mut self ) {
118
125
self . subscriptions . clear ( ) ;
126
+ self . guard_conditions . clear ( ) ;
119
127
self . clients . clear ( ) ;
120
128
self . services . clear ( ) ;
121
129
// This cannot fail – the rcl_wait_set_clear function only checks that the input handle is
@@ -159,6 +167,38 @@ impl WaitSet {
159
167
Ok ( ( ) )
160
168
}
161
169
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
+
162
202
/// Adds a client to the wait set.
163
203
///
164
204
/// # Errors
@@ -262,6 +302,7 @@ impl WaitSet {
262
302
let mut ready_entities = ReadyEntities {
263
303
subscriptions : Vec :: new ( ) ,
264
304
clients : Vec :: new ( ) ,
305
+ guard_conditions : Vec :: new ( ) ,
265
306
services : Vec :: new ( ) ,
266
307
} ;
267
308
for ( i, subscription) in self . subscriptions . iter ( ) . enumerate ( ) {
@@ -275,6 +316,7 @@ impl WaitSet {
275
316
. push ( Arc :: clone ( & subscription. waitable ) ) ;
276
317
}
277
318
}
319
+
278
320
for ( i, client) in self . clients . iter ( ) . enumerate ( ) {
279
321
// SAFETY: The `clients` entry is an array of pointers, and this dereferencing is
280
322
// equivalent to
@@ -284,6 +326,19 @@ impl WaitSet {
284
326
ready_entities. clients . push ( Arc :: clone ( & client. waitable ) ) ;
285
327
}
286
328
}
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
+
287
342
for ( i, service) in self . services . iter ( ) . enumerate ( ) {
288
343
// SAFETY: The `services` entry is an array of pointers, and this dereferencing is
289
344
// equivalent to
@@ -309,4 +364,20 @@ mod tests {
309
364
assert_send :: < WaitSet > ( ) ;
310
365
assert_sync :: < WaitSet > ( ) ;
311
366
}
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
+ }
312
383
}
0 commit comments