use super::*;
use crossbeam::utils::Backoff;
#[doc(hidden)]
pub trait MachineImpl: 'static + Send + Sync {
type Adapter;
type SenderAdapter;
type InstructionSet: Send + Sync;
fn park_sender(
channel_id: usize, receiver_machine: Weak<self::tls::collective::MachineAdapter>,
sender: crossbeam::channel::Sender<Self::InstructionSet>, instruction: Self::InstructionSet,
) -> Result<(), Self::InstructionSet>;
}
pub trait Machine<T>: Send + Sync
where
T: 'static + Send + Sync,
{
fn receive(&self, cmd: T);
fn disconnected(&self) {}
fn connected(&self, _uuid: Uuid) {}
}
impl<T, P> Machine<P> for Mutex<T>
where
T: Machine<P>,
P: MachineImpl,
{
fn receive(&self, cmd: P) {
if let Some(ref mut mutex) = self.try_lock() {
(*mutex).receive(cmd);
} else {
log::warn!("try_lock failed for receive, retrying");
let backoff = Backoff::new();
loop {
if let Some(ref mut mutex) = self.try_lock() {
(*mutex).receive(cmd);
return;
} else if backoff.is_completed() {
log::error!("try_lock failed for receive, giving up after multiple retries");
return;
} else {
backoff.snooze();
}
}
}
}
fn disconnected(&self) {
if let Some(ref mut mutex) = self.try_lock() {
(*mutex).disconnected();
} else {
log::warn!("try_lock failed for disconnected, retrying");
let backoff = Backoff::new();
loop {
if let Some(ref mut mutex) = self.try_lock() {
(*mutex).disconnected();
return;
} else if backoff.is_completed() {
log::error!("try_lock failed for disconnected, giving up after multiple retries");
return;
} else {
backoff.snooze();
}
}
}
}
fn connected(&self, uuid: Uuid) {
if let Some(ref mut mutex) = self.try_lock() {
(*mutex).connected(uuid);
} else {
log::warn!("try_lock failed for connected, retrying");
let backoff = Backoff::new();
loop {
if let Some(ref mut mutex) = self.try_lock() {
(*mutex).connected(uuid);
return;
} else if backoff.is_completed() {
log::error!("try_lock failed for connected, giving up after multiple retries");
return;
} else {
backoff.snooze();
}
}
}
}
}