diff --git a/crates/sound/src/main.rs b/crates/sound/src/main.rs index 408eef9..542fdb6 100644 --- a/crates/sound/src/main.rs +++ b/crates/sound/src/main.rs @@ -1,16 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause -mod vhu_sound; - -use std::{convert::TryFrom, sync::Arc}; +use std::convert::TryFrom; use clap::Parser; -use log::{info, warn}; -use vhost::{vhost_user, vhost_user::Listener}; -use vhost_user_backend::VhostUserDaemon; -use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap}; -use crate::vhu_sound::{Error, Result, SoundConfig, VhostUserSoundBackend}; +use vhost_user_sound::{start_backend_server, Error, Result, SoundConfig}; #[derive(Parser, Debug)] #[clap(version, about, long_about = None)] @@ -30,45 +24,14 @@ impl TryFrom for SoundConfig { } } -/// This is the public API through which an external program starts the -/// vhost-user-sound backend server. -pub(crate) fn start_backend_server(config: SoundConfig) { - loop { - let backend = Arc::new(VhostUserSoundBackend::new(config.clone()).unwrap()); - - let listener = Listener::new(config.get_socket_path(), true).unwrap(); - - let mut daemon = VhostUserDaemon::new( - String::from("vhost-user-sound"), - backend.clone(), - GuestMemoryAtomic::new(GuestMemoryMmap::new()), - ) - .unwrap(); - - 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.exit_event.write(1).unwrap(); - } -} - fn main() { env_logger::init(); let config = SoundConfig::try_from(SoundArgs::parse()).unwrap(); - start_backend_server(config); + + loop { + start_backend_server(config.clone()); + } } #[cfg(test)] diff --git a/crates/sound/src/vhu_sound.rs b/crates/sound/src/vhu_sound.rs index 24643bc..9a91b68 100644 --- a/crates/sound/src/vhu_sound.rs +++ b/crates/sound/src/vhu_sound.rs @@ -1,100 +1,21 @@ // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause -use std::{ - io::{self, Result as IoResult}, - sync::RwLock, - u16, u32, u64, u8, -}; -use thiserror::Error as ThisError; +use crate::virtio_sound::*; +use crate::{Error, Result, SoundConfig}; + +use std::{io::Result as IoResult, sync::RwLock, u16, u32, u64, u8}; use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures}; use vhost_user_backend::{VhostUserBackend, VringRwLock}; use virtio_bindings::bindings::{ virtio_config::VIRTIO_F_NOTIFY_ON_EMPTY, virtio_config::VIRTIO_F_VERSION_1, virtio_ring::VIRTIO_RING_F_EVENT_IDX, virtio_ring::VIRTIO_RING_F_INDIRECT_DESC, }; -use vm_memory::{ByteValued, GuestMemoryAtomic, GuestMemoryMmap, Le32}; +use vm_memory::{ByteValued, GuestMemoryAtomic, GuestMemoryMmap}; use vmm_sys_util::{ epoll::EventSet, eventfd::{EventFd, EFD_NONBLOCK}, }; -const CONTROL_QUEUE_IDX: u16 = 0; -const EVENT_QUEUE_IDX: u16 = 1; -const TX_QUEUE_IDX: u16 = 2; -const RX_QUEUE_IDX: u16 = 3; -const NUM_QUEUES: u16 = 4; - -pub(crate) type Result = std::result::Result; - -/// Custom error types -#[derive(Debug, ThisError)] -pub(crate) enum Error { - #[error("Failed to handle event other than EPOLLIN event")] - HandleEventNotEpollIn, - #[error("Failed to handle unknown event")] - HandleUnknownEvent, - #[error("Failed to create a new EventFd")] - EventFdCreate(std::io::Error), -} - -impl std::convert::From for std::io::Error { - fn from(e: Error) -> Self { - std::io::Error::new(io::ErrorKind::Other, e) - } -} - -#[derive(Debug, Clone)] -/// This structure is the public API through which an external program -/// is allowed to configure the backend. -pub(crate) struct SoundConfig { - /// vhost-user Unix domain socket - socket: String, - multi_thread: bool, -} - -impl SoundConfig { - /// Create a new instance of the SoundConfig struct, containing the - /// parameters to be fed into the sound-backend server. - pub fn new(socket: String, multi_thread: bool) -> Self { - Self { - socket, - multi_thread, - } - } - - /// Return the path of the unix domain socket which is listening to - /// requests from the guest. - pub fn get_socket_path(&self) -> String { - String::from(&self.socket) - } -} - -/// Virtio Sound Configuration -#[derive(Copy, Clone, Debug, Default, PartialEq)] -#[repr(C)] -struct VirtioSoundConfig { - /// total number of all available jacks - jacks: Le32, - /// total number of all available PCM streams - streams: Le32, - /// total number of all available channel maps - chmpas: Le32, -} -// SAFETY: The layout of the structure is fixed and can be initialized by -// reading its content from byte array. -unsafe impl ByteValued for VirtioSoundConfig {} - -/// Virtio Sound Request / Response common header -#[derive(Copy, Clone, Debug, Default, PartialEq)] -#[repr(C)] -struct VirtioSoundHeader { - /// request type / response status - code: Le32, -} -// SAFETY: The layout of the structure is fixed and can be initialized by -// reading its content from byte array. -unsafe impl ByteValued for VirtioSoundHeader {} - struct VhostUserSoundThread { mem: Option>, event_idx: bool, @@ -161,10 +82,10 @@ impl VhostUserSoundThread { } } -pub(crate) struct VhostUserSoundBackend { +pub struct VhostUserSoundBackend { threads: Vec>, virtio_cfg: VirtioSoundConfig, - pub(crate) exit_event: EventFd, + exit_event: EventFd, } impl VhostUserSoundBackend { @@ -197,6 +118,10 @@ impl VhostUserSoundBackend { exit_event: EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?, }) } + + pub fn send_exit_event(&self) { + self.exit_event.write(1).unwrap(); + } } impl VhostUserBackend for VhostUserSoundBackend {