1
1
use std:: sync:: { atomic:: AtomicBool , Arc , Mutex } ;
2
2
3
3
use crate :: rcl_bindings:: * ;
4
- use crate :: { Context , RclrsError , ToResult } ;
4
+ use crate :: { Context , ContextHandle , RclrsError , ToResult } ;
5
5
6
6
/// A waitable entity used for waking up a wait set manually.
7
7
///
@@ -45,18 +45,25 @@ use crate::{Context, RclrsError, ToResult};
45
45
/// ```
46
46
pub struct GuardCondition {
47
47
/// The rcl_guard_condition_t that this struct encapsulates.
48
- pub ( crate ) rcl_guard_condition : Mutex < rcl_guard_condition_t > ,
48
+ pub ( crate ) handle : GuardConditionHandle ,
49
49
/// An optional callback to call when this guard condition is triggered.
50
50
callback : Option < Box < dyn Fn ( ) + Send + Sync > > ,
51
51
/// A flag to indicate if this guard condition has already been assigned to a wait set.
52
52
pub ( crate ) in_use_by_wait_set : Arc < AtomicBool > ,
53
53
}
54
54
55
+ pub ( crate ) struct GuardConditionHandle {
56
+ pub ( crate ) rcl_guard_condition : Mutex < rcl_guard_condition_t > ,
57
+ /// Keep the context alive for the whole lifecycle of the guard condition
58
+ #[ allow( dead_code) ]
59
+ pub ( crate ) context_handle : Arc < ContextHandle > ,
60
+ }
61
+
55
62
impl Drop for GuardCondition {
56
63
fn drop ( & mut self ) {
57
64
unsafe {
58
65
// SAFETY: No precondition for this function (besides passing in a valid guard condition)
59
- rcl_guard_condition_fini ( & mut * self . rcl_guard_condition . lock ( ) . unwrap ( ) ) ;
66
+ rcl_guard_condition_fini ( & mut * self . handle . rcl_guard_condition . lock ( ) . unwrap ( ) ) ;
60
67
}
61
68
}
62
69
}
@@ -66,8 +73,8 @@ impl PartialEq for GuardCondition {
66
73
// Because GuardCondition controls the creation of the rcl_guard_condition, each unique GuardCondition should have a unique
67
74
// rcl_guard_condition. Thus comparing equality of this member should be enough.
68
75
std:: ptr:: eq (
69
- & self . rcl_guard_condition . lock ( ) . unwrap ( ) . impl_ ,
70
- & other. rcl_guard_condition . lock ( ) . unwrap ( ) . impl_ ,
76
+ & self . handle . rcl_guard_condition . lock ( ) . unwrap ( ) . impl_ ,
77
+ & other. handle . rcl_guard_condition . lock ( ) . unwrap ( ) . impl_ ,
71
78
)
72
79
}
73
80
}
@@ -80,16 +87,16 @@ unsafe impl Send for rcl_guard_condition_t {}
80
87
impl GuardCondition {
81
88
/// Creates a new guard condition with no callback.
82
89
pub fn new ( context : & Context ) -> Self {
83
- Self :: new_with_rcl_context ( & mut context. handle . rcl_context . lock ( ) . unwrap ( ) , None )
90
+ Self :: new_with_context_handle ( Arc :: clone ( & context. handle ) , None )
84
91
}
85
92
86
93
/// Creates a new guard condition with a callback.
87
94
pub fn new_with_callback < F > ( context : & Context , callback : F ) -> Self
88
95
where
89
96
F : Fn ( ) + Send + Sync + ' static ,
90
97
{
91
- Self :: new_with_rcl_context (
92
- & mut context. handle . rcl_context . lock ( ) . unwrap ( ) ,
98
+ Self :: new_with_context_handle (
99
+ Arc :: clone ( & context. handle ) ,
93
100
Some ( Box :: new ( callback) as Box < dyn Fn ( ) + Send + Sync > ) ,
94
101
)
95
102
}
@@ -98,23 +105,31 @@ impl GuardCondition {
98
105
/// Note this function enables calling `Node::create_guard_condition`[1] without providing the Context separately
99
106
///
100
107
/// [1]: Node::create_guard_condition
101
- pub ( crate ) fn new_with_rcl_context (
102
- context : & mut rcl_context_t ,
108
+ pub ( crate ) fn new_with_context_handle (
109
+ context_handle : Arc < ContextHandle > ,
103
110
callback : Option < Box < dyn Fn ( ) + Send + Sync > > ,
104
111
) -> Self {
105
- // SAFETY: Getting a zero initialized value is always safe
106
- let mut guard_condition = unsafe { rcl_get_zero_initialized_guard_condition ( ) } ;
107
- unsafe {
108
- // SAFETY: The context must be valid, and the guard condition must be zero-initialized
109
- rcl_guard_condition_init (
110
- & mut guard_condition,
111
- context,
112
- rcl_guard_condition_get_default_options ( ) ,
113
- ) ;
114
- }
112
+ let rcl_guard_condition = {
113
+ let mut rcl_context = context_handle. rcl_context . lock ( ) . unwrap ( ) ;
114
+ // SAFETY: Getting a zero initialized value is always safe
115
+ let mut guard_condition = unsafe { rcl_get_zero_initialized_guard_condition ( ) } ;
116
+ unsafe {
117
+ // SAFETY: The context must be valid, and the guard condition must be zero-initialized
118
+ rcl_guard_condition_init (
119
+ & mut guard_condition,
120
+ & mut * rcl_context,
121
+ rcl_guard_condition_get_default_options ( ) ,
122
+ ) ;
123
+ }
124
+
125
+ Mutex :: new ( guard_condition)
126
+ } ;
115
127
116
128
Self {
117
- rcl_guard_condition : Mutex :: new ( guard_condition) ,
129
+ handle : GuardConditionHandle {
130
+ rcl_guard_condition,
131
+ context_handle,
132
+ } ,
118
133
callback,
119
134
in_use_by_wait_set : Arc :: new ( AtomicBool :: new ( false ) ) ,
120
135
}
@@ -124,7 +139,7 @@ impl GuardCondition {
124
139
pub fn trigger ( & self ) -> Result < ( ) , RclrsError > {
125
140
unsafe {
126
141
// SAFETY: The rcl_guard_condition_t is valid.
127
- rcl_trigger_guard_condition ( & mut * self . rcl_guard_condition . lock ( ) . unwrap ( ) ) . ok ( ) ?;
142
+ rcl_trigger_guard_condition ( & mut * self . handle . rcl_guard_condition . lock ( ) . unwrap ( ) ) . ok ( ) ?;
128
143
}
129
144
if let Some ( callback) = & self . callback {
130
145
callback ( ) ;
0 commit comments