@@ -10,7 +10,7 @@ use crate::{
1010 error:: { RclReturnCode , ToResult } ,
1111 qos:: QoSProfile ,
1212 rcl_bindings:: * ,
13- NodeHandle , RclrsError , ENTITY_LIFECYCLE_MUTEX ,
13+ Node , NodeHandle , RclrsError , ENTITY_LIFECYCLE_MUTEX ,
1414} ;
1515
1616mod callback;
8484 pub ( crate ) handle : Arc < SubscriptionHandle > ,
8585 /// The callback function that runs when a message was received.
8686 pub callback : Mutex < AnySubscriptionCallback < T > > ,
87+ /// Ensure the parent node remains alive as long as the subscription is held.
88+ /// This implementation will change in the future.
89+ #[ allow( unused) ]
90+ node : Arc < Node > ,
8791 message : PhantomData < T > ,
8892}
8993
9397{
9498 /// Creates a new subscription.
9599 pub ( crate ) fn new < Args > (
96- node_handle : Arc < NodeHandle > ,
100+ node : & Arc < Node > ,
97101 topic : & str ,
98102 qos : QoSProfile ,
99103 callback : impl SubscriptionCallback < T , Args > ,
@@ -117,7 +121,7 @@ where
117121 subscription_options. qos = qos. into ( ) ;
118122
119123 {
120- let rcl_node = node_handle . rcl_node . lock ( ) . unwrap ( ) ;
124+ let rcl_node = node . handle . rcl_node . lock ( ) . unwrap ( ) ;
121125 let _lifecycle_lock = ENTITY_LIFECYCLE_MUTEX . lock ( ) . unwrap ( ) ;
122126 unsafe {
123127 // SAFETY:
@@ -139,13 +143,14 @@ where
139143
140144 let handle = Arc :: new ( SubscriptionHandle {
141145 rcl_subscription : Mutex :: new ( rcl_subscription) ,
142- node_handle,
146+ node_handle : Arc :: clone ( & node . handle ) ,
143147 in_use_by_wait_set : Arc :: new ( AtomicBool :: new ( false ) ) ,
144148 } ) ;
145149
146150 Ok ( Self {
147151 handle,
148152 callback : Mutex :: new ( callback. into_callback ( ) ) ,
153+ node : Arc :: clone ( node) ,
149154 message : PhantomData ,
150155 } )
151156 }
@@ -396,4 +401,41 @@ mod tests {
396401 ) ;
397402 Ok ( ( ) )
398403 }
404+
405+ #[ test]
406+ fn test_node_subscription_raii ( ) {
407+ use crate :: * ;
408+ use std:: sync:: atomic:: Ordering ;
409+
410+ let mut executor = Context :: default ( ) . create_basic_executor ( ) ;
411+
412+ let triggered = Arc :: new ( AtomicBool :: new ( false ) ) ;
413+ let inner_triggered = Arc :: clone ( & triggered) ;
414+ let callback = move |_: msg:: Empty | {
415+ inner_triggered. store ( true , Ordering :: Release ) ;
416+ } ;
417+
418+ let ( _subscription, publisher) = {
419+ let node = executor
420+ . create_node ( & format ! ( "test_node_subscription_raii_{}" , line!( ) ) )
421+ . unwrap ( ) ;
422+
423+ let qos = QoSProfile :: default ( ) . keep_all ( ) . reliable ( ) ;
424+ let subscription = node
425+ . create_subscription :: < msg:: Empty , _ > ( "test_topic" , qos, callback)
426+ . unwrap ( ) ;
427+ let publisher = node
428+ . create_publisher :: < msg:: Empty > ( "test_topic" , qos)
429+ . unwrap ( ) ;
430+
431+ ( subscription, publisher)
432+ } ;
433+
434+ publisher. publish ( msg:: Empty :: default ( ) ) . unwrap ( ) ;
435+ let start_time = std:: time:: Instant :: now ( ) ;
436+ while !triggered. load ( Ordering :: Acquire ) {
437+ assert ! ( executor. spin( SpinOptions :: spin_once( ) ) . is_empty( ) ) ;
438+ assert ! ( start_time. elapsed( ) < std:: time:: Duration :: from_secs( 10 ) ) ;
439+ }
440+ }
399441}
0 commit comments