use ::arrayvec::ArrayVec;
use ::demikernel::{
demi_sgarray_t,
demi_sgaseg_t,
inetstack::protocols::{
layer1::PhysicalLayer,
MAX_HEADER_SIZE,
},
runtime::{
fail::Fail,
memory::{
DemiBuffer,
MemoryRuntime,
},
network::consts::RECEIVE_BATCH_SIZE,
SharedObject,
},
};
use ::libc::c_void;
use ::log::error;
use ::std::{
mem,
ops::{
Deref,
DerefMut,
},
};
pub struct DummyRuntime {
incoming: crossbeam_channel::Receiver<DemiBuffer>,
outgoing: crossbeam_channel::Sender<DemiBuffer>,
}
#[derive(Clone)]
pub struct SharedDummyRuntime(SharedObject<DummyRuntime>);
impl SharedDummyRuntime {
pub fn new(
incoming: crossbeam_channel::Receiver<DemiBuffer>,
outgoing: crossbeam_channel::Sender<DemiBuffer>,
) -> Self {
Self(SharedObject::new(DummyRuntime { incoming, outgoing }))
}
}
impl PhysicalLayer for SharedDummyRuntime {
fn transmit(&mut self, pkt: DemiBuffer) -> Result<(), Fail> {
assert!(pkt.len() < u16::MAX as usize);
match self.outgoing.try_send(pkt) {
Ok(_) => Ok(()),
Err(_) => Err(Fail::new(
libc::EAGAIN,
"Could not push outgoing packet to the shared channel",
)),
}
}
fn receive(&mut self) -> Result<ArrayVec<DemiBuffer, RECEIVE_BATCH_SIZE>, Fail> {
let mut out = ArrayVec::new();
if let Some(buf) = self.incoming.try_recv().ok() {
out.push(buf);
}
Ok(out)
}
}
impl MemoryRuntime for SharedDummyRuntime {
fn sgaalloc(&self, size: usize) -> Result<demi_sgarray_t, Fail> {
if size == 0 {
let cause: String = format!("cannot allocate a zero-sized buffer");
error!("sgaalloc(): {}", cause);
return Err(Fail::new(libc::EINVAL, &cause));
}
if size > u16::MAX as usize {
return Err(Fail::new(libc::EINVAL, "size too large for a single demi_sgaseg_t"));
}
let buf: DemiBuffer = DemiBuffer::new_with_headroom(size as u16, MAX_HEADER_SIZE as u16);
let data: *const u8 = buf.as_ptr();
let sga_seg: demi_sgaseg_t = demi_sgaseg_t {
sgaseg_buf: data as *mut c_void,
sgaseg_len: size as u32,
};
Ok(demi_sgarray_t {
sga_buf: buf.into_raw().as_ptr() as *mut c_void,
sga_numsegs: 1,
sga_segs: [sga_seg],
sga_addr: unsafe { mem::zeroed() },
})
}
}
impl Deref for SharedDummyRuntime {
type Target = DummyRuntime;
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl DerefMut for SharedDummyRuntime {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.deref_mut()
}
}