Skip to content

Instantly share code, notes, and snippets.

@mxgrey
Last active January 7, 2022 03:54
Show Gist options
  • Save mxgrey/939e7af24202c294a63f852eb0d810aa to your computer and use it in GitHub Desktop.
Save mxgrey/939e7af24202c294a63f852eb0d810aa to your computer and use it in GitHub Desktop.
Rough draft of idea for safely blocking ros2_rust client
// The code in this file should be treated as a rough sketch. It probably contains errors, and it is definitely missing
// large chunks of implementation.
struct Executor {
// ... details ...
}
enum SpinError {
/// The spinning has timed out
Timeout,
/// The client you provided does not belong to the callback group of this executor
WrongGroup,
/// You are waiting on a spin result from inside of a callback in this same callback group
Recursive
}
impl Executor {
fn is_in_group<ST>(&self, client: &Client<ST>) -> bool {
// TODO: Check if client belongs to the callback group of this executor
}
fn ensure_spinning(&self) -> SpinAssurance {
// TODO: If the executor is not spinning, create a thread for the executor to perform its spinning in.
// If the executor is already spinning, do nothing.
// TODO: SpinAssurance would be some type that does reference counting. When the SpinAssurance instance gets
// dropped, the spinning thread gets terminated.
}
fn spin(&self) {
let spin_assurance = self.ensure_spinning();
// TODO: Block the thread while the context is okay
}
async fn spin_until_service_available<ST>(
&self,
&client: Client<ST>,
timeout: Option<std::time::Duration>)
-> Result<(), SpinError>
where ST: ServiceType {
if !self.is_in_group(client) {
return SpinError::WrongGroup;
}
let spin_assurance = self.ensure_spinning();
if std::thread::current().id() == self.spin_thread {
return SpinError::Recursive;
}
// TODO: Have this function wait on some condition variable which watches whether a service has become available
}
async fn spin_until_response_arrives<ST>(
&self,
&mut client: Client<ST>,
request: ST::Request,
timeout: Option<std::time::Duration>)
-> Result<ST::Response, Timeout>
where ST: ServiceType {
if !self.is_in_group(client) {
return SpinError::WrongGroup;
}
let spin_assurance = self.ensure_spinning();
if std::thread::current().id() == self.spin_thread {
return SpinError::Recursive;
}
self.spin_until_service_available(client).await;
let (completer, promise) = std::futures::promise::<ST::Response>();
client.send_request(
request,
move |response: ST::Response| {
completer.complete(response);
}
// TODO: Await on promise, but give up if we reach the timeout
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment