18
18
use std:: { sync:: Arc , time:: Duration , vec:: Vec } ;
19
19
20
20
use crate :: {
21
+ action:: {
22
+ client:: ReadyMode as ActionClientReadyMode , server:: ReadyMode as ActionServerReadyMode ,
23
+ } ,
21
24
error:: { to_rclrs_result, RclReturnCode , RclrsError , ToResult } ,
22
25
rcl_bindings:: * ,
23
26
ActionClientBase , ActionServerBase , ClientBase , Context , ContextHandle , Node , ServiceBase ,
@@ -66,6 +69,10 @@ pub struct ReadyEntities {
66
69
pub guard_conditions : Vec < Arc < GuardCondition > > ,
67
70
/// A list of services that have potentially received requests.
68
71
pub services : Vec < Arc < dyn ServiceBase > > ,
72
+ /// A list of action clients and the ways in which they are ready.
73
+ pub action_clients : Vec < ( Arc < dyn ActionClientBase > , ActionClientReadyMode ) > ,
74
+ /// A list of action servers and the ways in which they are ready.
75
+ pub action_servers : Vec < ( Arc < dyn ActionServerBase > , ActionServerReadyMode ) > ,
69
76
}
70
77
71
78
impl Drop for rcl_wait_set_t {
@@ -156,8 +163,12 @@ impl WaitSet {
156
163
let mut num_services = live_services. len ( ) ;
157
164
let mut num_events = 0 ;
158
165
159
- let action_client_entities = live_action_clients. iter ( ) . map ( |client| client. num_entities ( ) ) ;
160
- let action_server_entities = live_action_servers. iter ( ) . map ( |server| server. num_entities ( ) ) ;
166
+ let action_client_entities = live_action_clients
167
+ . iter ( )
168
+ . map ( |client| client. num_entities ( ) ) ;
169
+ let action_server_entities = live_action_servers
170
+ . iter ( )
171
+ . map ( |server| server. num_entities ( ) ) ;
161
172
for num_entities in action_client_entities. chain ( action_server_entities) {
162
173
num_subscriptions += num_entities. num_subscriptions ;
163
174
num_timers += num_entities. num_timers ;
@@ -451,8 +462,9 @@ impl WaitSet {
451
462
} ;
452
463
// SAFETY: The comments in rcl mention "This function cannot operate on the same wait set
453
464
// in multiple threads, and the wait sets may not share content."
454
- // We cannot currently guarantee that the wait sets may not share content, but it is
455
- // mentioned in the doc comment for `add_subscription`.
465
+ // By taking exclusive ownership of `self`, we can guarantee that the wait set is not in
466
+ // use from another thread. We guarantee that waits sets may not share content using
467
+ // `ExclusivityGuard`s on each entity added.
456
468
// Also, the rcl_wait_set is obviously valid.
457
469
match unsafe { rcl_wait ( & mut self . handle . rcl_wait_set , timeout_ns) } . ok ( ) {
458
470
Ok ( _) => ( ) ,
@@ -469,6 +481,8 @@ impl WaitSet {
469
481
clients : Vec :: new ( ) ,
470
482
guard_conditions : Vec :: new ( ) ,
471
483
services : Vec :: new ( ) ,
484
+ action_clients : Vec :: new ( ) ,
485
+ action_servers : Vec :: new ( ) ,
472
486
} ;
473
487
for ( i, subscription) in self . subscriptions . iter ( ) . enumerate ( ) {
474
488
// SAFETY: The `subscriptions` entry is an array of pointers, and this dereferencing is
@@ -513,6 +527,103 @@ impl WaitSet {
513
527
ready_entities. services . push ( Arc :: clone ( & service. waitable ) ) ;
514
528
}
515
529
}
530
+
531
+ for action_client in & self . action_clients {
532
+ let mut is_feedback_ready = false ;
533
+ let mut is_status_ready = false ;
534
+ let mut is_goal_response_ready = false ;
535
+ let mut is_cancel_response_ready = false ;
536
+ let mut is_result_response_ready = false ;
537
+ // SAFETY: The wait set is exclusively owned by this function, which guarantees thread
538
+ // safety.
539
+ unsafe {
540
+ rcl_action_client_wait_set_get_entities_ready (
541
+ & self . handle . rcl_wait_set ,
542
+ & * action_client. waitable . handle ( ) . lock ( ) ,
543
+ & mut is_feedback_ready,
544
+ & mut is_status_ready,
545
+ & mut is_goal_response_ready,
546
+ & mut is_cancel_response_ready,
547
+ & mut is_result_response_ready,
548
+ )
549
+ . ok ( ) ?;
550
+ }
551
+ if is_feedback_ready {
552
+ ready_entities. action_clients . push ( (
553
+ Arc :: clone ( & action_client. waitable ) ,
554
+ ActionClientReadyMode :: Feedback ,
555
+ ) ) ;
556
+ }
557
+ if is_status_ready {
558
+ ready_entities. action_clients . push ( (
559
+ Arc :: clone ( & action_client. waitable ) ,
560
+ ActionClientReadyMode :: Status ,
561
+ ) ) ;
562
+ }
563
+ if is_goal_response_ready {
564
+ ready_entities. action_clients . push ( (
565
+ Arc :: clone ( & action_client. waitable ) ,
566
+ ActionClientReadyMode :: GoalResponse ,
567
+ ) ) ;
568
+ }
569
+ if is_cancel_response_ready {
570
+ ready_entities. action_clients . push ( (
571
+ Arc :: clone ( & action_client. waitable ) ,
572
+ ActionClientReadyMode :: CancelResponse ,
573
+ ) ) ;
574
+ }
575
+ if is_result_response_ready {
576
+ ready_entities. action_clients . push ( (
577
+ Arc :: clone ( & action_client. waitable ) ,
578
+ ActionClientReadyMode :: ResultResponse ,
579
+ ) ) ;
580
+ }
581
+ }
582
+
583
+ for action_server in & self . action_servers {
584
+ let mut is_goal_request_ready = false ;
585
+ let mut is_cancel_request_ready = false ;
586
+ let mut is_result_request_ready = false ;
587
+ let mut is_goal_expired = false ;
588
+ // SAFETY: The wait set is exclusively owned by this function, which guarantees thread
589
+ // safety.
590
+ unsafe {
591
+ rcl_action_server_wait_set_get_entities_ready (
592
+ & self . handle . rcl_wait_set ,
593
+ & * action_server. waitable . handle ( ) . lock ( ) ,
594
+ & mut is_goal_request_ready,
595
+ & mut is_cancel_request_ready,
596
+ & mut is_result_request_ready,
597
+ & mut is_goal_expired,
598
+ )
599
+ . ok ( ) ?;
600
+ }
601
+ if is_goal_request_ready {
602
+ ready_entities. action_servers . push ( (
603
+ Arc :: clone ( & action_server. waitable ) ,
604
+ ActionServerReadyMode :: GoalRequest ,
605
+ ) ) ;
606
+ }
607
+ if is_cancel_request_ready {
608
+ ready_entities. action_servers . push ( (
609
+ Arc :: clone ( & action_server. waitable ) ,
610
+ ActionServerReadyMode :: CancelRequest ,
611
+ ) ) ;
612
+ }
613
+ if is_result_request_ready {
614
+ ready_entities. action_servers . push ( (
615
+ Arc :: clone ( & action_server. waitable ) ,
616
+ ActionServerReadyMode :: ResultRequest ,
617
+ ) ) ;
618
+ }
619
+ if is_goal_expired {
620
+ ready_entities. action_servers . push ( (
621
+ Arc :: clone ( & action_server. waitable ) ,
622
+ ActionServerReadyMode :: GoalExpired ,
623
+ ) ) ;
624
+ }
625
+ }
626
+
516
627
Ok ( ready_entities)
517
628
}
518
629
}
0 commit comments