@@ -10,7 +10,7 @@ use crate::{
10
10
error:: { RclReturnCode , ToResult } ,
11
11
qos:: QoSProfile ,
12
12
rcl_bindings:: * ,
13
- NodeHandle , RclrsError , ENTITY_LIFECYCLE_MUTEX ,
13
+ Node , NodeHandle , RclrsError , ENTITY_LIFECYCLE_MUTEX ,
14
14
} ;
15
15
16
16
mod callback;
84
84
pub ( crate ) handle : Arc < SubscriptionHandle > ,
85
85
/// The callback function that runs when a message was received.
86
86
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 > ,
87
91
message : PhantomData < T > ,
88
92
}
89
93
93
97
{
94
98
/// Creates a new subscription.
95
99
pub ( crate ) fn new < Args > (
96
- node_handle : Arc < NodeHandle > ,
100
+ node : & Arc < Node > ,
97
101
topic : & str ,
98
102
qos : QoSProfile ,
99
103
callback : impl SubscriptionCallback < T , Args > ,
@@ -117,7 +121,7 @@ where
117
121
subscription_options. qos = qos. into ( ) ;
118
122
119
123
{
120
- let rcl_node = node_handle . rcl_node . lock ( ) . unwrap ( ) ;
124
+ let rcl_node = node . handle . rcl_node . lock ( ) . unwrap ( ) ;
121
125
let _lifecycle_lock = ENTITY_LIFECYCLE_MUTEX . lock ( ) . unwrap ( ) ;
122
126
unsafe {
123
127
// SAFETY:
@@ -139,13 +143,14 @@ where
139
143
140
144
let handle = Arc :: new ( SubscriptionHandle {
141
145
rcl_subscription : Mutex :: new ( rcl_subscription) ,
142
- node_handle,
146
+ node_handle : Arc :: clone ( & node . handle ) ,
143
147
in_use_by_wait_set : Arc :: new ( AtomicBool :: new ( false ) ) ,
144
148
} ) ;
145
149
146
150
Ok ( Self {
147
151
handle,
148
152
callback : Mutex :: new ( callback. into_callback ( ) ) ,
153
+ node : Arc :: clone ( node) ,
149
154
message : PhantomData ,
150
155
} )
151
156
}
@@ -396,4 +401,41 @@ mod tests {
396
401
) ;
397
402
Ok ( ( ) )
398
403
}
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
+ }
399
441
}
0 commit comments