sound: code refactoring

This commit is contained in:
Stefano Garzarella 2023-03-31 16:45:41 +02:00
parent 8d3ebf35e1
commit b81c55fbe2
2 changed files with 17 additions and 129 deletions

View File

@ -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<SoundArgs> 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)]

View File

@ -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<T> = std::result::Result<T, Error>;
/// 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<Error> 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<GuestMemoryAtomic<GuestMemoryMmap>>,
event_idx: bool,
@ -161,10 +82,10 @@ impl VhostUserSoundThread {
}
}
pub(crate) struct VhostUserSoundBackend {
pub struct VhostUserSoundBackend {
threads: Vec<RwLock<VhostUserSoundThread>>,
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<VringRwLock, ()> for VhostUserSoundBackend {