use crate::io::epoll::{Epoll, FileIndex};
use crate::io::internal_pipe::{Receiver, Sender};
use crate::persist::blueprint::Blueprint;
use crate::persist::subsystem::{Command, Report};
use crate::{error::*, Pollable};
use std::os::unix::io::{AsRawFd, RawFd};
use std::thread::JoinHandle;
pub struct HostInterface {
pub(super) commander: Sender<Command>,
pub(super) reporter: Receiver<Report>,
pub(super) join_handle: JoinHandle<()>,
}
impl HostInterface {
pub fn add_blueprint(&mut self, blueprint: Blueprint) -> Result<(), SystemError> {
self.commander.send(Command::AddBlueprint(blueprint))
}
pub fn request_shutdown(&mut self) -> Result<(), SystemError> {
self.commander.send(Command::Shutdown)
}
pub fn await_shutdown(mut self) {
if self.request_shutdown().is_ok() {
let _ = self.join_handle.join();
}
}
pub fn recv(&mut self) -> Result<Report, SystemError> {
self.reporter.recv()
}
}
impl AsRawFd for HostInterface {
fn as_raw_fd(&self) -> RawFd {
self.reporter.as_raw_fd()
}
}
pub enum HostInterfaceState {
NotStarted,
Running(FileIndex),
Error,
Shutdown,
}
impl HostInterfaceState {
pub fn new() -> HostInterfaceState {
HostInterfaceState::NotStarted
}
pub fn require<'a>(&mut self, epoll: &'a mut Epoll<Pollable>) -> Option<&'a mut HostInterface> {
use HostInterfaceState::*;
if let NotStarted = self {
let interface = match crate::persist::subsystem::launch() {
Ok(interface) => interface,
Err(error) => {
eprintln!("Warning: failed to start the persistence subsystem. Devices with the persist flag may not be (re)opened successfully.");
error.print_err();
*self = Error;
return None;
}
};
let index = match epoll.add_file(crate::Pollable::PersistSubsystem(interface)) {
Ok(index) => index,
Err(error) => {
error
.with_context(
"While adding the persistence subsystem interface to an epoll:",
)
.print_err();
*self = Error;
return None;
}
};
*self = Running(index);
}
self.get(epoll)
}
pub fn get<'a>(&mut self, epoll: &'a mut Epoll<Pollable>) -> Option<&'a mut HostInterface> {
use HostInterfaceState::*;
match self {
Running(index) => {
if let Some(crate::Pollable::PersistSubsystem(ref mut interface)) =
epoll.get_mut(*index)
{
Some(interface)
} else {
None
}
}
NotStarted => None,
Error => None,
Shutdown => None,
}
}
pub fn mark_as_broken(&mut self) {
*self = HostInterfaceState::Error;
}
pub fn mark_as_shutdown(&mut self) {
*self = HostInterfaceState::Shutdown;
}
pub fn await_shutdown(self, epoll: &mut Epoll<Pollable>) {
if let HostInterfaceState::Running(index) = self {
if let Some(Pollable::PersistSubsystem(interface)) = epoll.remove(index) {
interface.await_shutdown();
}
}
}
}