Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring around daemon launch #389

Merged
merged 2 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 3 additions & 23 deletions staging/vhost-device-sound/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,8 @@ use std::{
};

use clap::ValueEnum;
use log::{info, warn};
pub use stream::Stream;
use thiserror::Error as ThisError;
use vhost::{vhost_user, vhost_user::Listener};
use vhost_user_backend::{VhostUserDaemon, VringRwLock, VringT};
use virtio_sound::*;
use vm_memory::{
Expand Down Expand Up @@ -347,36 +345,18 @@ impl Drop for IOMessage {
/// vhost-device-sound backend server.
pub fn start_backend_server(config: SoundConfig) {
log::trace!("Using config {:?}.", &config);
let listener = Listener::new(config.get_socket_path(), true).unwrap();
let socket = config.get_socket_path();
let backend = Arc::new(VhostUserSoundBackend::new(config).unwrap());

let mut daemon = VhostUserDaemon::new(
String::from("vhost-device-sound"),
backend.clone(),
backend,
GuestMemoryAtomic::new(GuestMemoryMmap::new()),
)
.unwrap();

log::trace!("Starting daemon.");
daemon.start(listener).unwrap();

match daemon.wait() {
Ok(()) => {
info!("Stopping cleanly.");
}
Err(vhost_user_backend::Error::HandleRequest(vhost_user::Error::PartialMessage)) => {
info!(
"vhost-user connection closed with partial message. If the VM is shutting down, \
this is expected behavior; otherwise, it might be a bug."
);
}
Err(e) => {
warn!("Error running daemon: {:?}", e);
}
}

// No matter the result, we need to shut down the worker thread.
backend.send_exit_event();
daemon.serve(socket).unwrap();
}

#[cfg(test)]
Expand Down
38 changes: 6 additions & 32 deletions staging/vhost-device-video/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ use std::{
};

use clap::Parser;
use log::{info, warn};
use log::info;
use thiserror::Error as ThisError;
use vhost::{vhost_user, vhost_user::Listener};
use vhost_user_backend::VhostUserDaemon;
use vhu_video::{BackendType, VuVideoBackend};
use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};
Expand All @@ -26,8 +25,8 @@ pub(crate) enum Error {
CouldNotCreateBackend(vhu_video::VuVideoError),
#[error("Could not create daemon: {0}")]
CouldNotCreateDaemon(vhost_user_backend::Error),
#[error("Failed creating listener: {0}")]
FailedCreatingListener(vhost_user::Error),
#[error("Fatal error: {0}")]
ServeFailed(vhost_user_backend::Error),
}

#[derive(Clone, Parser, Debug)]
Expand Down Expand Up @@ -91,33 +90,8 @@ pub(crate) fn start_backend(config: VuVideoConfig) -> Result<()> {
}

daemon
.start(Listener::new(&config.socket_path, true).map_err(Error::FailedCreatingListener)?)
.expect("Stargin daemon");

match daemon.wait() {
Ok(()) => {
info!("Stopping cleanly");
}
Err(vhost_user_backend::Error::HandleRequest(
vhost_user::Error::PartialMessage | vhost_user::Error::Disconnected,
)) => {
info!(
"vhost-user connection closed with partial message.
If the VM is shutting down, this is expected behavior;
otherwise, it might be a bug."
);
}
Err(e) => {
warn!("Error running daemon: {:?} -> {}", e, e.to_string());
}
}

vu_video_backend
.read()
.unwrap()
.exit_event
.write(1)
.expect("Shutting down worker thread");
.serve(&config.socket_path)
.map_err(Error::ServeFailed)?;
}
}

Expand Down Expand Up @@ -193,7 +167,7 @@ mod tests {
};
assert_matches!(
start_backend(VuVideoConfig::try_from(config).unwrap()).unwrap_err(),
Error::FailedCreatingListener(_)
Error::ServeFailed(_)
);
// cleanup
std::fs::remove_file(v4l2_device).expect("Failed to clean up");
Expand Down
30 changes: 6 additions & 24 deletions vhost-device-gpio/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//
// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause

use log::{error, info, warn};
use log::error;
use std::num::ParseIntError;
use std::process::exit;
use std::sync::{Arc, RwLock};
Expand All @@ -14,7 +14,6 @@ use std::thread::{spawn, JoinHandle};
use clap::Parser;
use env_logger::Env;
use thiserror::Error as ThisError;
use vhost::{vhost_user, vhost_user::Listener};
use vhost_user_backend::VhostUserDaemon;
use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};

Expand All @@ -37,8 +36,6 @@ pub(crate) enum Error {
DeviceDuplicate(u32),
#[error("Failed while parsing to integer: {0:?}")]
ParseFailure(ParseIntError),
#[error("Failed to join threads")]
FailedJoiningThreads,
#[error("Could not open gpio device: {0}")]
CouldNotOpenDevice(crate::gpio::Error),
#[error("Could not create gpio controller: {0}")]
Expand All @@ -47,6 +44,8 @@ pub(crate) enum Error {
CouldNotCreateBackend(crate::vhu_gpio::Error),
#[error("Could not create daemon: {0}")]
CouldNotCreateDaemon(vhost_user_backend::Error),
#[error("Fatal error: {0}")]
ServeFailed(vhost_user_backend::Error),
}

const GPIO_AFTER_HELP: &str = "Each device number here will be used to \
Expand Down Expand Up @@ -179,7 +178,6 @@ fn start_device_backend<D: GpioDevice>(device: D, socket: String) -> Result<()>
let backend = Arc::new(RwLock::new(
VhostUserGpioBackend::new(controller).map_err(Error::CouldNotCreateBackend)?,
));
let listener = Listener::new(socket, true).unwrap();

let mut daemon = VhostUserDaemon::new(
String::from("vhost-device-gpio-backend"),
Expand All @@ -188,21 +186,8 @@ fn start_device_backend<D: GpioDevice>(device: D, socket: String) -> Result<()>
)
.map_err(Error::CouldNotCreateDaemon)?;

daemon.start(listener).unwrap();
daemon.serve(&socket).map_err(Error::ServeFailed)?;

match daemon.wait() {
Ok(()) => {
info!("Stopping cleanly.");
}
Err(vhost_user_backend::Error::HandleRequest(vhost_user::Error::PartialMessage)) => {
info!("vhost-user connection closed with partial message. If the VM is shutting down, this is expected behavior; otherwise, it might be a bug.");
}
Err(e) => {
warn!("Error running daemon: {:?}", e);
}
}
// No matter the result, we need to shut down the worker thread.
backend.read().unwrap().exit_event.write(1).unwrap();
Ok(())
}

Expand Down Expand Up @@ -240,7 +225,7 @@ fn start_backend(args: GpioArgs) -> Result<()> {
}

for handle in handles {
handle.join().map_err(|_| Error::FailedJoiningThreads)??;
handle.join().map_err(std::panic::resume_unwind).unwrap()?;
epilys marked this conversation as resolved.
Show resolved Hide resolved
}

Ok(())
Expand Down Expand Up @@ -360,9 +345,6 @@ mod tests {
let socket_name = "~/path/not/present/gpio";
let cmd_args = get_cmd_args(socket_name, "s1:s4:s3:s5", 4);

assert_matches!(
start_backend(cmd_args).unwrap_err(),
Error::FailedJoiningThreads
);
assert_matches!(start_backend(cmd_args).unwrap_err(), Error::ServeFailed(_));
}
}
32 changes: 7 additions & 25 deletions vhost-device-i2c/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@
mod i2c;
mod vhu_i2c;

use log::{error, info, warn};
use log::error;
use std::num::ParseIntError;
use std::process::exit;
use std::sync::{Arc, RwLock};
use std::thread::{spawn, JoinHandle};

use clap::Parser;
use thiserror::Error as ThisError;
use vhost::{vhost_user, vhost_user::Listener};
use vhost_user_backend::VhostUserDaemon;
use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};

Expand All @@ -40,12 +39,12 @@ pub(crate) enum Error {
I2cFailure(i2c::Error),
#[error("Failed while parsing to integer: {0:?}")]
ParseFailure(ParseIntError),
#[error("Failed to join threads")]
FailedJoiningThreads,
#[error("Could not create backend: {0}")]
CouldNotCreateBackend(vhu_i2c::Error),
#[error("Could not create daemon: {0}")]
CouldNotCreateDaemon(vhost_user_backend::Error),
#[error("Fatal error: {0}")]
ServeFailed(vhost_user_backend::Error),
}

#[derive(Parser, Debug)]
Expand Down Expand Up @@ -199,7 +198,6 @@ fn start_backend<D: 'static + I2cDevice + Send + Sync>(args: I2cArgs) -> Result<
let backend = Arc::new(RwLock::new(
VhostUserI2cBackend::new(i2c_map.clone()).map_err(Error::CouldNotCreateBackend)?,
));
let listener = Listener::new(socket.clone(), true).unwrap();

let mut daemon = VhostUserDaemon::new(
String::from("vhost-device-i2c-backend"),
Expand All @@ -208,31 +206,14 @@ fn start_backend<D: 'static + I2cDevice + Send + Sync>(args: I2cArgs) -> Result<
)
.map_err(Error::CouldNotCreateDaemon)?;

daemon.start(listener).unwrap();

match daemon.wait() {
Ok(()) => {
info!("Stopping cleanly.");
}
Err(vhost_user_backend::Error::HandleRequest(
vhost_user::Error::PartialMessage | vhost_user::Error::Disconnected,
)) => {
info!("vhost-user connection closed with partial message. If the VM is shutting down, this is expected behavior; otherwise, it might be a bug.");
}
Err(e) => {
warn!("Error running daemon: {:?}", e);
}
}

// No matter the result, we need to shut down the worker thread.
backend.read().unwrap().exit_event.write(1).unwrap();
daemon.serve(&socket).map_err(Error::ServeFailed)?;
});

handles.push(handle);
}

for handle in handles {
handle.join().map_err(|_| Error::FailedJoiningThreads)??;
handle.join().map_err(std::panic::resume_unwind).unwrap()?;
}

Ok(())
Expand All @@ -250,6 +231,7 @@ fn main() {
#[cfg(test)]
mod tests {
use assert_matches::assert_matches;
use vhost::vhost_user::Listener;

use super::*;
use crate::i2c::tests::DummyDevice;
Expand Down Expand Up @@ -394,7 +376,7 @@ mod tests {

assert_matches!(
start_backend::<DummyDevice>(cmd_args).unwrap_err(),
Error::FailedJoiningThreads
Error::ServeFailed(_)
);
}
}
44 changes: 9 additions & 35 deletions vhost-device-rng/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
mod vhu_rng;

use log::{error, info, warn};
use log::error;
use std::fs::File;
use std::process::exit;
use std::sync::{Arc, Mutex, RwLock};
use std::thread::{self, JoinHandle};

use clap::Parser;
use thiserror::Error as ThisError;
use vhost::{vhost_user, vhost_user::Listener};
use vhost_user_backend::VhostUserDaemon;
use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap};

Expand All @@ -34,12 +33,12 @@ pub(crate) enum Error {
InvalidPeriodInput(u128),
#[error("Wrong socket count: {0}")]
InvalidSocketCount(u32),
#[error("Threads can't be joined")]
FailedJoiningThreads,
#[error("Could not create backend: {0}")]
CouldNotCreateBackend(std::io::Error),
#[error("Could not create daemon: {0}")]
CouldNotCreateDaemon(vhost_user_backend::Error),
#[error("Fatal error: {0}")]
ServeFailed(vhost_user_backend::Error),
}

#[derive(Clone, Parser, Debug, PartialEq)]
Expand Down Expand Up @@ -131,37 +130,14 @@ pub(crate) fn start_backend(config: VuRngConfig) -> Result<()> {
)
.map_err(Error::CouldNotCreateDaemon)?;

let listener = Listener::new(socket.clone(), true).unwrap();
daemon.start(listener).unwrap();

match daemon.wait() {
Ok(()) => {
info!("Stopping cleanly.");
}
Err(vhost_user_backend::Error::HandleRequest(
vhost_user::Error::PartialMessage | vhost_user::Error::Disconnected,
)) => {
info!("vhost-user connection closed with partial message. If the VM is shutting down, this is expected behavior; otherwise, it might be a bug.");
}
Err(e) => {
warn!("Error running daemon: {:?}", e);
}
}

// No matter the result, we need to shut down the worker thread.
vu_rng_backend
.read()
.unwrap()
.exit_event
.write(1)
.expect("Shutting down worker thread");
daemon.serve(&socket).map_err(Error::ServeFailed)?;
});

handles.push(handle);
}

for handle in handles {
handle.join().map_err(|_| Error::FailedJoiningThreads)??;
handle.join().map_err(std::panic::resume_unwind).unwrap()?;
}

Ok(())
Expand Down Expand Up @@ -243,12 +219,10 @@ mod tests {
);

// Set the RNG source to something valid, forcing the code to check the validity
// of the socket file. Since the latter is invalid the vhost_user::Listener will
// throw an error, forcing the thread to exit and the call to handle.join() to fail.
// of the socket file. Since the latter is invalid, serving will throw
// an error, forcing the thread to exit and the call to handle.join()
// to fail.
config.rng_source = random_path.to_str().unwrap().to_string();
assert_matches!(
start_backend(config).unwrap_err(),
Error::FailedJoiningThreads
);
assert_matches!(start_backend(config).unwrap_err(), Error::ServeFailed(_));
}
}
Loading