2024-01-30 02:05:37 -08:00
|
|
|
pub mod error;
|
2024-01-08 17:07:00 -08:00
|
|
|
pub mod sys;
|
|
|
|
|
2024-02-14 20:50:11 +00:00
|
|
|
use crate::error::{Error, Result};
|
2024-01-08 17:07:00 -08:00
|
|
|
use crate::sys::{BindInterdomain, BindUnboundPort, BindVirq, Notify, UnbindPort};
|
2024-01-30 02:05:37 -08:00
|
|
|
|
2024-02-14 20:50:11 +00:00
|
|
|
use log::error;
|
|
|
|
use std::collections::hash_map::Entry;
|
|
|
|
use std::collections::HashMap;
|
2024-03-27 06:28:47 +00:00
|
|
|
use std::mem::size_of;
|
2024-01-08 17:07:00 -08:00
|
|
|
use std::os::fd::AsRawFd;
|
2024-03-27 06:28:47 +00:00
|
|
|
use std::os::raw::c_void;
|
2024-02-14 20:50:11 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
use tokio::fs::{File, OpenOptions};
|
2024-03-27 06:28:47 +00:00
|
|
|
use tokio::io::AsyncReadExt;
|
2024-02-14 20:50:11 +00:00
|
|
|
use tokio::select;
|
|
|
|
use tokio::sync::broadcast::{
|
|
|
|
channel as broadcast_channel, Receiver as BroadcastReceiver, Sender as BroadastSender,
|
|
|
|
};
|
|
|
|
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
|
|
|
use tokio::sync::Mutex;
|
|
|
|
use tokio::task::JoinHandle;
|
2024-01-08 17:07:00 -08:00
|
|
|
|
2024-03-27 06:28:47 +00:00
|
|
|
const UNBIND_CHANNEL_QUEUE_LEN: usize = 30;
|
2024-02-14 20:50:11 +00:00
|
|
|
const UNMASK_CHANNEL_QUEUE_LEN: usize = 30;
|
|
|
|
const BROADCAST_CHANNEL_QUEUE_LEN: usize = 30;
|
|
|
|
|
|
|
|
type WakeMap = Arc<Mutex<HashMap<u32, BroadastSender<u32>>>>;
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
2024-01-08 17:07:00 -08:00
|
|
|
pub struct EventChannel {
|
2024-02-14 20:50:11 +00:00
|
|
|
handle: Arc<Mutex<File>>,
|
|
|
|
wakes: WakeMap,
|
2024-03-27 06:28:47 +00:00
|
|
|
unbind_sender: Sender<u32>,
|
2024-02-14 20:50:11 +00:00
|
|
|
unmask_sender: Sender<u32>,
|
|
|
|
task: Arc<JoinHandle<()>>,
|
2024-01-08 17:07:00 -08:00
|
|
|
}
|
|
|
|
|
2024-03-27 06:28:47 +00:00
|
|
|
pub struct BoundEventChannel {
|
|
|
|
pub local_port: u32,
|
|
|
|
pub receiver: BroadcastReceiver<u32>,
|
|
|
|
unbind_sender: Sender<u32>,
|
|
|
|
pub unmask_sender: Sender<u32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for BoundEventChannel {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
let _ = self.unbind_sender.try_send(self.local_port);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-08 17:07:00 -08:00
|
|
|
impl EventChannel {
|
2024-02-14 20:50:11 +00:00
|
|
|
pub async fn open() -> Result<EventChannel> {
|
2024-01-08 17:07:00 -08:00
|
|
|
let file = OpenOptions::new()
|
|
|
|
.read(true)
|
|
|
|
.write(true)
|
2024-02-14 20:50:11 +00:00
|
|
|
.open("/dev/xen/evtchn")
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
let wakes = Arc::new(Mutex::new(HashMap::new()));
|
2024-03-27 06:28:47 +00:00
|
|
|
let (unbind_sender, unbind_receiver) = channel(UNBIND_CHANNEL_QUEUE_LEN);
|
2024-02-14 20:50:11 +00:00
|
|
|
let (unmask_sender, unmask_receiver) = channel(UNMASK_CHANNEL_QUEUE_LEN);
|
|
|
|
let task = {
|
|
|
|
let file = file.try_clone().await?;
|
|
|
|
let wakes = wakes.clone();
|
|
|
|
tokio::task::spawn(async move {
|
2024-03-27 06:28:47 +00:00
|
|
|
if let Err(error) =
|
|
|
|
EventChannel::process(file, wakes, unmask_receiver, unbind_receiver).await
|
|
|
|
{
|
2024-02-14 20:50:11 +00:00
|
|
|
error!("event channel processor failed: {}", error);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
};
|
|
|
|
Ok(EventChannel {
|
|
|
|
handle: Arc::new(Mutex::new(file)),
|
|
|
|
wakes,
|
2024-03-27 06:28:47 +00:00
|
|
|
unbind_sender,
|
2024-02-14 20:50:11 +00:00
|
|
|
unmask_sender,
|
|
|
|
task: Arc::new(task),
|
|
|
|
})
|
2024-01-08 17:07:00 -08:00
|
|
|
}
|
|
|
|
|
2024-02-14 20:50:11 +00:00
|
|
|
pub async fn bind_virq(&self, virq: u32) -> Result<u32> {
|
|
|
|
let handle = self.handle.lock().await;
|
2024-01-08 17:07:00 -08:00
|
|
|
unsafe {
|
|
|
|
let mut request = BindVirq { virq };
|
2024-02-14 20:50:11 +00:00
|
|
|
Ok(sys::bind_virq(handle.as_raw_fd(), &mut request)? as u32)
|
2024-01-08 17:07:00 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-14 20:50:11 +00:00
|
|
|
pub async fn bind_interdomain(&self, domid: u32, port: u32) -> Result<u32> {
|
|
|
|
let handle = self.handle.lock().await;
|
2024-01-08 17:07:00 -08:00
|
|
|
unsafe {
|
|
|
|
let mut request = BindInterdomain {
|
|
|
|
remote_domain: domid,
|
|
|
|
remote_port: port,
|
|
|
|
};
|
2024-02-14 20:50:11 +00:00
|
|
|
Ok(sys::bind_interdomain(handle.as_raw_fd(), &mut request)? as u32)
|
2024-01-08 17:07:00 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-14 20:50:11 +00:00
|
|
|
pub async fn bind_unbound_port(&self, domid: u32) -> Result<u32> {
|
|
|
|
let handle = self.handle.lock().await;
|
2024-01-08 17:07:00 -08:00
|
|
|
unsafe {
|
|
|
|
let mut request = BindUnboundPort {
|
|
|
|
remote_domain: domid,
|
|
|
|
};
|
2024-02-14 20:50:11 +00:00
|
|
|
Ok(sys::bind_unbound_port(handle.as_raw_fd(), &mut request)? as u32)
|
2024-01-08 17:07:00 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-14 20:50:11 +00:00
|
|
|
pub async fn unbind(&self, port: u32) -> Result<u32> {
|
|
|
|
let handle = self.handle.lock().await;
|
2024-01-08 17:07:00 -08:00
|
|
|
unsafe {
|
|
|
|
let mut request = UnbindPort { port };
|
2024-02-14 20:50:11 +00:00
|
|
|
Ok(sys::unbind(handle.as_raw_fd(), &mut request)? as u32)
|
2024-01-08 17:07:00 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-14 20:50:11 +00:00
|
|
|
pub async fn notify(&self, port: u32) -> Result<u32> {
|
|
|
|
let handle = self.handle.lock().await;
|
2024-01-08 17:07:00 -08:00
|
|
|
unsafe {
|
|
|
|
let mut request = Notify { port };
|
2024-02-14 20:50:11 +00:00
|
|
|
Ok(sys::notify(handle.as_raw_fd(), &mut request)? as u32)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn reset(&self) -> Result<u32> {
|
|
|
|
let handle = self.handle.lock().await;
|
|
|
|
unsafe { Ok(sys::reset(handle.as_raw_fd())? as u32) }
|
|
|
|
}
|
|
|
|
|
2024-03-27 06:28:47 +00:00
|
|
|
pub async fn bind(&self, domid: u32, port: u32) -> Result<BoundEventChannel> {
|
|
|
|
let local_port = self.bind_interdomain(domid, port).await?;
|
|
|
|
let (receiver, unmask_sender) = self.subscribe(local_port).await?;
|
|
|
|
let bound = BoundEventChannel {
|
|
|
|
local_port,
|
|
|
|
receiver,
|
|
|
|
unbind_sender: self.unbind_sender.clone(),
|
|
|
|
unmask_sender,
|
|
|
|
};
|
|
|
|
Ok(bound)
|
|
|
|
}
|
|
|
|
|
2024-02-14 20:50:11 +00:00
|
|
|
pub async fn subscribe(&self, port: u32) -> Result<(BroadcastReceiver<u32>, Sender<u32>)> {
|
|
|
|
let mut wakes = self.wakes.lock().await;
|
|
|
|
let receiver = match wakes.entry(port) {
|
|
|
|
Entry::Occupied(entry) => entry.get().subscribe(),
|
|
|
|
|
|
|
|
Entry::Vacant(entry) => {
|
|
|
|
let (sender, receiver) = broadcast_channel::<u32>(BROADCAST_CHANNEL_QUEUE_LEN);
|
|
|
|
entry.insert(sender);
|
|
|
|
receiver
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Ok((receiver, self.unmask_sender.clone()))
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn process(
|
|
|
|
mut file: File,
|
|
|
|
wakers: WakeMap,
|
|
|
|
mut unmask_receiver: Receiver<u32>,
|
2024-03-27 06:28:47 +00:00
|
|
|
mut unbind_receiver: Receiver<u32>,
|
2024-02-14 20:50:11 +00:00
|
|
|
) -> Result<()> {
|
|
|
|
loop {
|
|
|
|
select! {
|
|
|
|
result = file.read_u32_le() => {
|
|
|
|
match result {
|
|
|
|
Ok(port) => {
|
|
|
|
if let Some(sender) = wakers.lock().await.get(&port) {
|
|
|
|
if let Err(error) = sender.send(port) {
|
|
|
|
return Err(Error::WakeSend(error));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(error) => return Err(Error::Io(error))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = unmask_receiver.recv() => {
|
|
|
|
match result {
|
|
|
|
Some(port) => {
|
2024-03-27 06:28:47 +00:00
|
|
|
unsafe {
|
|
|
|
let mut port = port;
|
|
|
|
let result = libc::write(file.as_raw_fd(), &mut port as *mut u32 as *mut c_void, size_of::<u32>());
|
|
|
|
if result != size_of::<u32>() as isize {
|
|
|
|
return Err(Error::Io(std::io::Error::from_raw_os_error(result as i32)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None => {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = unbind_receiver.recv() => {
|
|
|
|
match result {
|
|
|
|
Some(port) => {
|
|
|
|
unsafe {
|
|
|
|
let mut request = UnbindPort { port };
|
|
|
|
sys::unbind(file.as_raw_fd(), &mut request)?;
|
|
|
|
}
|
2024-02-14 20:50:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
None => {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2024-01-08 17:07:00 -08:00
|
|
|
}
|
2024-02-14 20:50:11 +00:00
|
|
|
|
|
|
|
Ok(())
|
2024-01-08 17:07:00 -08:00
|
|
|
}
|
2024-02-14 20:50:11 +00:00
|
|
|
}
|
2024-01-08 17:07:00 -08:00
|
|
|
|
2024-02-14 20:50:11 +00:00
|
|
|
impl Drop for EventChannel {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
if Arc::strong_count(&self.task) <= 1 {
|
|
|
|
self.task.abort();
|
|
|
|
}
|
2024-01-08 17:07:00 -08:00
|
|
|
}
|
|
|
|
}
|