Skip to content

Commit f8a5803

Browse files
committed
Fix tests and eliminate (most) warnings
Signed-off-by: Michael X. Grey <[email protected]>
1 parent 4af6efe commit f8a5803

17 files changed

+192
-80
lines changed

rclrs/src/context.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ pub struct Context {
6868
pub(crate) handle: Arc<ContextHandle>,
6969
}
7070

71+
impl std::fmt::Debug for Context {
72+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73+
f.debug_struct("Context")
74+
.field("handle", &self.handle.rcl_context.lock())
75+
.finish()
76+
}
77+
}
78+
7179
/// This struct manages the lifetime and access to the `rcl_context_t`. It will also
7280
/// account for the lifetimes of any dependencies, if we need to add
7381
/// dependencies in the future (currently there are none). It is not strictly

rclrs/src/executor.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ pub trait WorkerChannel: Send + Sync {
304304
/// to create a new worker. Downstream users of rclrs should not be using this class
305305
/// unless you are implementing your own [`ExecutorRuntime`].
306306
pub struct ExecutorWorkerOptions {
307+
/// The context that the executor is associated with
307308
pub context: Context,
308309
/// The payload that the worker provides to different primitives.
309310
pub payload: Box<dyn Any + Send>,

rclrs/src/executor/basic_executor.rs

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ use crate::{
2121
GuardCondition, ExecutorWorkerOptions,
2222
};
2323

24+
static FAILED_TO_SEND_WORKER: &'static str =
25+
"Failed to send the new runner. This should never happen. \
26+
Please report this to the rclrs maintainers with a minimal reproducible example.";
27+
2428
/// The implementation of this runtime is based off of the async Rust reference book:
2529
/// https://rust-lang.github.io/async-book/02_execution/04_executor.html
2630
///
@@ -52,7 +56,14 @@ impl AllGuardConditions {
5256
fn trigger(&self) {
5357
self.inner.lock().unwrap().retain(|guard_condition| {
5458
if let Some(guard_condition) = guard_condition.upgrade() {
55-
guard_condition.trigger();
59+
if let Err(err) = guard_condition.trigger() {
60+
log_fatal!(
61+
"rclrs.executor.basic_executor",
62+
"Failed to trigger a guard condition. This should never happen. \
63+
Please report this to the rclrs maintainers with a minimal reproducible example. \
64+
Error: {err}",
65+
);
66+
}
5667
true
5768
} else {
5869
false
@@ -61,7 +72,13 @@ impl AllGuardConditions {
6172
}
6273

6374
fn push(&self, guard_condition: Weak<GuardCondition>) {
64-
self.inner.lock().unwrap().push(guard_condition);
75+
let mut inner = self.inner.lock().unwrap();
76+
if inner.iter().find(|other| guard_condition.ptr_eq(other)).is_some() {
77+
// This guard condition is already known
78+
return;
79+
}
80+
81+
inner.push(guard_condition);
6582
}
6683
}
6784

@@ -81,11 +98,20 @@ impl ExecutorRuntime for BasicExecutorRuntime {
8198
// is returned to self. Therefore we create this blocking channel to
8299
// prevent the function from returning until the WaitSetRunner has been
83100
// re-obtained.
84-
let (worker_sender, worker_receiver) = channel();
101+
let (worker_result_sender, worker_result_receiver) = channel();
85102

86103
// Use this atomic bool to recognize when we should stop spinning.
87104
let workers_finished = Arc::new(AtomicBool::new(false));
88105

106+
for runner in self.wait_set_runners.drain(..) {
107+
if let Err(err) = self.new_worker_sender.unbounded_send(runner) {
108+
log_fatal!(
109+
"rclrs.executor.basic_executor",
110+
"{FAILED_TO_SEND_WORKER} Error: {err}",
111+
);
112+
}
113+
}
114+
89115
// Use this to terminate the spinning once the wait set is finished.
90116
let workers_finished_clone = Arc::clone(&workers_finished);
91117
self.task_sender.add_async_task(Box::pin(async move {
@@ -95,7 +121,14 @@ impl ExecutorRuntime for BasicExecutorRuntime {
95121
conditions,
96122
).await;
97123

98-
worker_sender.send(workers);
124+
if let Err(err) = worker_result_sender.send(workers) {
125+
log_fatal!(
126+
"rclrs.executor.basic_executor",
127+
"Failed to send a runner result. This should never happen. \
128+
Please report this to the rclrs maintainers with a minimal \
129+
reproducible example. Error: {err}",
130+
);
131+
}
99132
workers_finished_clone.store(true, Ordering::Release);
100133
}));
101134

@@ -116,7 +149,7 @@ impl ExecutorRuntime for BasicExecutorRuntime {
116149
}
117150
}
118151

119-
let (runners, new_worker_receiver, errors) = worker_receiver.recv().expect(
152+
let (runners, new_worker_receiver, errors) = worker_result_receiver.recv().expect(
120153
"Basic executor failed to receive the WaitSetRunner at the end of its spinning. \
121154
This is a critical bug in rclrs. \
122155
Please report this bug to the maintainers of rclrs by providing a minimum reproduction of the problem."
@@ -190,7 +223,7 @@ impl BasicExecutorRuntime {
190223
// TODO(@mxgrey): We should change this to a log when logging
191224
// becomes available.
192225
log_warn!(
193-
"basic_executor",
226+
"rclrs.executor.basic_executor",
194227
"Sender for SpinOptions::until_promise_resolved was \
195228
dropped, so the Promise will never be fulfilled. \
196229
Spinning will stop now. Error message: {err}"
@@ -246,7 +279,14 @@ impl ExecutorChannel for BasicExecutorChannel {
246279
) -> Arc<dyn WorkerChannel> {
247280
let runner = WaitSetRunner::new(options);
248281
let waitable_sender = runner.sender();
249-
self.new_worker_sender.unbounded_send(runner);
282+
283+
if let Err(err) = self.new_worker_sender.unbounded_send(runner) {
284+
log_fatal!(
285+
"rclrs.executor.basic_executor",
286+
"{FAILED_TO_SEND_WORKER} Error: {err}",
287+
);
288+
}
289+
250290
Arc::new(BasicWorkerChannel {
251291
waitable_sender,
252292
task_sender: self.task_sender.clone(),
@@ -321,6 +361,26 @@ async fn manage_workers(
321361
let mut finished_runners: Vec<WaitSetRunner> = Vec::new();
322362
let mut errors: Vec<RclrsError> = Vec::new();
323363

364+
let add_runner = |
365+
new_runner: Option<WaitSetRunner>,
366+
active_runners: &mut Vec<_>,
367+
finished_runners: &mut Vec<_>,
368+
| {
369+
if let Some(runner) = new_runner {
370+
all_guard_conditions.push(Arc::downgrade(runner.guard_condition()));
371+
if conditions.halt_spinning.load(Ordering::Acquire) {
372+
finished_runners.push(runner);
373+
} else {
374+
active_runners.push(runner.run(conditions.clone()));
375+
}
376+
}
377+
};
378+
379+
// We expect to start with at least one worker
380+
let (initial_worker, new_worker_receiver) = new_workers.await;
381+
new_workers = new_worker_receiver.into_future();
382+
add_runner(initial_worker, &mut active_runners, &mut finished_runners);
383+
324384
while !active_runners.is_empty() {
325385
let next_event = select(
326386
select_all(active_runners),
@@ -341,7 +401,7 @@ async fn manage_workers(
341401
}
342402
Err(_) => {
343403
log_fatal!(
344-
"basic_executor",
404+
"rclrs.basic_executor",
345405
"WaitSetRunner unexpectedly dropped. This should never happen. \
346406
Please report this to the rclrs maintainers with a minimal \
347407
reproducible example.",
@@ -353,21 +413,12 @@ async fn manage_workers(
353413
new_workers = new_worker_stream;
354414
}
355415
Either::Right((
356-
(new_worker, new_worker_stream),
416+
(new_worker, new_worker_receiver),
357417
remaining_workers,
358418
)) => {
359419
active_runners = remaining_workers.into_inner();
360-
361-
if let Some(runner) = new_worker {
362-
all_guard_conditions.push(Arc::downgrade(runner.guard_condition()));
363-
if conditions.halt_spinning.load(Ordering::Acquire) {
364-
finished_runners.push(runner);
365-
} else {
366-
active_runners.push(runner.run(conditions.clone()));
367-
}
368-
}
369-
370-
new_workers = new_worker_stream.into_future();
420+
add_runner(new_worker, &mut active_runners, &mut finished_runners);
421+
new_workers = new_worker_receiver.into_future();
371422
}
372423
}
373424
};

rclrs/src/service.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ pub use worker_service_callback::*;
5656
///
5757
pub type Service<T> = Arc<ServiceState<T, Node>>;
5858

59+
/// Provide a [`Service`] that runs on a [`Worker`].
60+
///
61+
/// Create a worker service using [`Worker::create_service`].
5962
pub type WorkerService<T, Payload> = Arc<ServiceState<T, Worker<Payload>>>;
6063

6164
/// The inner state of a [`Service`].

rclrs/src/service/any_service_callback.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rosidl_runtime_rs::{Message, Service};
1+
use rosidl_runtime_rs::Service;
22

33
use crate::{WorkerCommands, RclrsError, ServiceHandle, NodeServiceCallback, WorkerServiceCallback};
44

@@ -10,7 +10,9 @@ where
1010
T: Service,
1111
Payload: 'static + Send,
1212
{
13+
/// A callback in the Node scope
1314
Node(NodeServiceCallback<T>),
15+
/// A callback in the worker scope
1416
Worker(WorkerServiceCallback<T, Payload>),
1517
}
1618

rclrs/src/service/node_service_callback.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
use rosidl_runtime_rs::{Message, Service};
1+
use rosidl_runtime_rs::Service;
22

33
use crate::{
4-
error::ToResult,
5-
rcl_bindings::{
6-
rcl_send_response, rcl_take_request, rcl_take_request_with_info, rmw_request_id_t,
7-
rmw_service_info_t,
8-
},
9-
WorkerCommands, MessageCow, RclReturnCode, RclrsError, RequestId, ServiceHandle, ServiceInfo,
4+
rcl_bindings::rmw_request_id_t,
5+
WorkerCommands, RclrsError, RequestId, ServiceHandle, ServiceInfo,
106
log_error, ToLogParams, RclrsErrorFilter,
117
};
128

rclrs/src/service/service_scope.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::{Node, Worker};
44
/// well as what kind of callbacks can be used with it. Users should not implement
55
/// this trait.
66
pub trait ServiceScope {
7+
/// What kind of payload should the worker hold for this scope.
78
type Payload: 'static + Send;
89
}
910

rclrs/src/service/worker_service_callback.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ use crate::{
66

77
use std::{any::Any, sync::Arc};
88

9+
/// An enum capturing the various possible function signatures for service
10+
/// callbacks that can be used by a [`Worker`][crate::Worker].
11+
///
12+
/// The correct enum variant is deduced by the [`IntoWorkerServiceCallback`][1] trait.
13+
///
14+
/// [1]: crate::IntoWorkerServiceCallback
915
pub enum WorkerServiceCallback<T, Payload>
1016
where
1117
T: Service,

rclrs/src/subscription.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ pub use worker_subscription_callback::*;
5959
/// [4]: crate::Node
6060
pub type Subscription<T> = Arc<SubscriptionState<T, Node>>;
6161

62+
/// A [`Subscription`] that runs on a [`Worker`].
63+
///
64+
/// Create a worker subscription using [`Worker::create_subscription`].
6265
pub type WorkerSubscription<T, Payload> = Arc<SubscriptionState<T, Worker<Payload>>>;
6366

6467
/// The inner state of a [`Subscription`].

rclrs/src/subscription/any_subscription_callback.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,18 @@ use crate::{
77

88
use std::{any::Any, sync::Arc};
99

10+
/// An enum capturing the various possible function signatures for subscription callbacks.
11+
///
12+
/// The correct enum variant is deduced by the [`IntoNodeSubscriptionCallback`][1],
13+
/// [`IntoAsyncSubscriptionCallback`][2], or [`IntoWorkerSubscriptionCallback`][3] trait.
14+
///
15+
/// [1]: crate::IntoNodeSubscriptionCallback
16+
/// [2]: crate::IntoAsyncSubscriptionCallback
17+
/// [3]: crate::IntoWorkerSubscriptionCallback
1018
pub enum AnySubscriptionCallback<T: Message, Payload> {
19+
/// A callback in the Node scope
1120
Node(NodeSubscriptionCallback<T>),
21+
/// A callback in the worker scope
1222
Worker(WorkerSubscriptionCallback<T, Payload>),
1323
}
1424

0 commit comments

Comments
 (0)