@@ -25,6 +25,9 @@ use std::vec::Vec;
25
25
26
26
use parking_lot:: Mutex ;
27
27
28
+ mod exclusivity_guard;
29
+ use exclusivity_guard:: * ;
30
+
28
31
/// A struct for waiting on subscriptions and other waitable entities to become ready.
29
32
pub struct WaitSet {
30
33
rcl_wait_set : rcl_wait_set_t ,
@@ -33,9 +36,9 @@ pub struct WaitSet {
33
36
// The subscriptions that are currently registered in the wait set.
34
37
// This correspondence is an invariant that must be maintained by all functions,
35
38
// even in the error case.
36
- subscriptions : Vec < Arc < dyn SubscriptionBase > > ,
37
- clients : Vec < Arc < dyn ClientBase > > ,
38
- services : Vec < Arc < dyn ServiceBase > > ,
39
+ subscriptions : Vec < ExclusivityGuard < Arc < dyn SubscriptionBase > > > ,
40
+ clients : Vec < ExclusivityGuard < Arc < dyn ClientBase > > > ,
41
+ services : Vec < ExclusivityGuard < Arc < dyn ServiceBase > > > ,
39
42
}
40
43
41
44
/// A list of entities that are ready, returned by [`WaitSet::wait`].
@@ -118,17 +121,22 @@ impl WaitSet {
118
121
119
122
/// Adds a subscription to the wait set.
120
123
///
121
- /// It is possible, but not useful, to add the same subscription twice.
122
- ///
123
- /// This will return an error if the number of subscriptions in the wait set is larger than the
124
- /// capacity set in [`WaitSet::new`].
124
+ /// # Errors
125
+ /// - If the subscription was already added to this wait set or another one,
126
+ /// [`AlreadyAddedToWaitSet`][1] will be returned
127
+ /// - If the number of subscriptions in the wait set is larger than the
128
+ /// capacity set in [`WaitSet::new`], [`WaitSetFull`][2] will be returned
125
129
///
126
- /// The same subscription must not be added to multiple wait sets, because that would make it
127
- /// unsafe to simultaneously wait on those wait sets.
130
+ /// [1]: crate::RclrsError
131
+ /// [2]: crate::RclReturnCode
128
132
pub fn add_subscription (
129
133
& mut self ,
130
134
subscription : Arc < dyn SubscriptionBase > ,
131
135
) -> Result < ( ) , RclrsError > {
136
+ let exclusive_subscription = ExclusivityGuard :: new (
137
+ Arc :: clone ( & subscription) ,
138
+ Arc :: clone ( & subscription. handle ( ) . in_use_by_wait_set ) ,
139
+ ) ?;
132
140
unsafe {
133
141
// SAFETY: I'm not sure if it's required, but the subscription pointer will remain valid
134
142
// for as long as the wait set exists, because it's stored in self.subscriptions.
@@ -140,20 +148,25 @@ impl WaitSet {
140
148
)
141
149
}
142
150
. ok ( ) ?;
143
- self . subscriptions . push ( subscription ) ;
151
+ self . subscriptions . push ( exclusive_subscription ) ;
144
152
Ok ( ( ) )
145
153
}
146
154
147
155
/// Adds a client to the wait set.
148
156
///
149
- /// It is possible, but not useful, to add the same client twice.
150
- ///
151
- /// This will return an error if the number of clients in the wait set is larger than the
152
- /// capacity set in [`WaitSet::new`].
157
+ /// # Errors
158
+ /// - If the client was already added to this wait set or another one,
159
+ /// [`AlreadyAddedToWaitSet`][1] will be returned
160
+ /// - If the number of clients in the wait set is larger than the
161
+ /// capacity set in [`WaitSet::new`], [`WaitSetFull`][2] will be returned
153
162
///
154
- /// The same client must not be added to multiple wait sets, because that would make it
155
- /// unsafe to simultaneously wait on those wait sets.
163
+ /// [1]: crate::RclrsError
164
+ /// [2]: crate::RclReturnCode
156
165
pub fn add_client ( & mut self , client : Arc < dyn ClientBase > ) -> Result < ( ) , RclrsError > {
166
+ let exclusive_client = ExclusivityGuard :: new (
167
+ Arc :: clone ( & client) ,
168
+ Arc :: clone ( & client. handle ( ) . in_use_by_wait_set ) ,
169
+ ) ?;
157
170
unsafe {
158
171
// SAFETY: I'm not sure if it's required, but the client pointer will remain valid
159
172
// for as long as the wait set exists, because it's stored in self.clients.
@@ -165,20 +178,25 @@ impl WaitSet {
165
178
)
166
179
}
167
180
. ok ( ) ?;
168
- self . clients . push ( client ) ;
181
+ self . clients . push ( exclusive_client ) ;
169
182
Ok ( ( ) )
170
183
}
171
184
172
185
/// Adds a service to the wait set.
173
186
///
174
- /// It is possible, but not useful, to add the same service twice.
175
- ///
176
- /// This will return an error if the number of services in the wait set is larger than the
177
- /// capacity set in [`WaitSet::new`].
187
+ /// # Errors
188
+ /// - If the service was already added to this wait set or another one,
189
+ /// [`AlreadyAddedToWaitSet`][1] will be returned
190
+ /// - If the number of services in the wait set is larger than the
191
+ /// capacity set in [`WaitSet::new`], [`WaitSetFull`][2] will be returned
178
192
///
179
- /// The same service must not be added to multiple wait sets, because that would make it
180
- /// unsafe to simultaneously wait on those wait sets.
193
+ /// [1]: crate::RclrsError
194
+ /// [2]: crate::RclReturnCode
181
195
pub fn add_service ( & mut self , service : Arc < dyn ServiceBase > ) -> Result < ( ) , RclrsError > {
196
+ let exclusive_service = ExclusivityGuard :: new (
197
+ Arc :: clone ( & service) ,
198
+ Arc :: clone ( & service. handle ( ) . in_use_by_wait_set ) ,
199
+ ) ?;
182
200
unsafe {
183
201
// SAFETY: I'm not sure if it's required, but the service pointer will remain valid
184
202
// for as long as the wait set exists, because it's stored in self.services.
@@ -190,7 +208,7 @@ impl WaitSet {
190
208
)
191
209
}
192
210
. ok ( ) ?;
193
- self . services . push ( service ) ;
211
+ self . services . push ( exclusive_service ) ;
194
212
Ok ( ( ) )
195
213
}
196
214
@@ -245,7 +263,9 @@ impl WaitSet {
245
263
// https://github.com/ros2/rcl/blob/35a31b00a12f259d492bf53c0701003bd7f1745c/rcl/include/rcl/wait.h#L419
246
264
let wait_set_entry = unsafe { * self . rcl_wait_set . subscriptions . add ( i) } ;
247
265
if !wait_set_entry. is_null ( ) {
248
- ready_entities. subscriptions . push ( subscription. clone ( ) ) ;
266
+ ready_entities
267
+ . subscriptions
268
+ . push ( Arc :: clone ( & subscription. waitable ) ) ;
249
269
}
250
270
}
251
271
for ( i, client) in self . clients . iter ( ) . enumerate ( ) {
@@ -254,7 +274,7 @@ impl WaitSet {
254
274
// https://github.com/ros2/rcl/blob/35a31b00a12f259d492bf53c0701003bd7f1745c/rcl/include/rcl/wait.h#L419
255
275
let wait_set_entry = unsafe { * self . rcl_wait_set . clients . add ( i) } ;
256
276
if !wait_set_entry. is_null ( ) {
257
- ready_entities. clients . push ( client . clone ( ) ) ;
277
+ ready_entities. clients . push ( Arc :: clone ( & client . waitable ) ) ;
258
278
}
259
279
}
260
280
for ( i, service) in self . services . iter ( ) . enumerate ( ) {
@@ -263,7 +283,7 @@ impl WaitSet {
263
283
// https://github.com/ros2/rcl/blob/35a31b00a12f259d492bf53c0701003bd7f1745c/rcl/include/rcl/wait.h#L419
264
284
let wait_set_entry = unsafe { * self . rcl_wait_set . services . add ( i) } ;
265
285
if !wait_set_entry. is_null ( ) {
266
- ready_entities. services . push ( service . clone ( ) ) ;
286
+ ready_entities. services . push ( Arc :: clone ( & service . waitable ) ) ;
267
287
}
268
288
}
269
289
Ok ( ready_entities)
0 commit comments