Add BufferPool.
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
use std::ops::{Deref, DerefMut, Drop};
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::mem::swap;
|
||||
|
||||
type BufferStack = Rc<RefCell<Vec<Vec<u8>>>>;
|
||||
|
||||
pub struct Buffer {
|
||||
buffer: Vec<u8>,
|
||||
stack: BufferStack,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub fn resize(&mut self, new_len: usize) {
|
||||
self.buffer.resize(new_len, 0u8);
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Buffer {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<[u8]> for Buffer {
|
||||
fn as_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Buffer {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Buffer {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Buffer {
|
||||
fn drop(&mut self) {
|
||||
let mut tmp = vec![];
|
||||
swap(&mut tmp, &mut self.buffer);
|
||||
{
|
||||
let mut stack = self.stack.borrow_mut();
|
||||
trace!("Returning buffer: {}", stack.len());
|
||||
stack.push(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BufferPool {
|
||||
buffers_size: usize,
|
||||
stack: BufferStack,
|
||||
}
|
||||
|
||||
impl BufferPool {
|
||||
pub fn new(buffers_size: usize) -> BufferPool {
|
||||
BufferPool {
|
||||
buffers_size,
|
||||
stack: Rc::new(RefCell::new(vec![])),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_buffer(&mut self) -> Buffer {
|
||||
let buffer = match self.stack.borrow_mut().pop() {
|
||||
None => {
|
||||
trace!("Allocating ingress buffer");
|
||||
vec![0u8; self.buffers_size]
|
||||
}
|
||||
Some(mut v) => {
|
||||
trace!("Reusing ingress buffer");
|
||||
// memsetting the buffer with `resize` would be a waste of time
|
||||
let capacity = v.capacity();
|
||||
unsafe {
|
||||
v.set_len(capacity);
|
||||
}
|
||||
v
|
||||
}
|
||||
};
|
||||
|
||||
Buffer {
|
||||
buffer,
|
||||
stack: self.stack.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,11 @@ use std::cell::RefCell;
|
||||
use std::io::Write;
|
||||
use std::collections::VecDeque;
|
||||
use smoltcp;
|
||||
use buffer_pool::Buffer;
|
||||
|
||||
pub struct NetworkDevice {
|
||||
network_file: Rc<RefCell<File>>,
|
||||
input_queue: Rc<RefCell<VecDeque<Vec<u8>>>>,
|
||||
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
|
||||
}
|
||||
|
||||
impl NetworkDevice {
|
||||
@@ -15,7 +16,7 @@ impl NetworkDevice {
|
||||
|
||||
pub fn new(
|
||||
network_file: Rc<RefCell<File>>,
|
||||
input_queue: Rc<RefCell<VecDeque<Vec<u8>>>>,
|
||||
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
|
||||
) -> NetworkDevice {
|
||||
NetworkDevice {
|
||||
network_file,
|
||||
@@ -48,7 +49,7 @@ impl Drop for TxBuffer {
|
||||
}
|
||||
|
||||
impl smoltcp::phy::Device for NetworkDevice {
|
||||
type RxBuffer = Vec<u8>;
|
||||
type RxBuffer = Buffer;
|
||||
type TxBuffer = TxBuffer;
|
||||
|
||||
fn limits(&self) -> smoltcp::phy::DeviceLimits {
|
||||
|
||||
@@ -15,6 +15,7 @@ use std::process;
|
||||
use std::rc::Rc;
|
||||
|
||||
mod error;
|
||||
mod buffer_pool;
|
||||
mod device;
|
||||
mod scheme;
|
||||
mod logger;
|
||||
|
||||
+18
-13
@@ -1,5 +1,3 @@
|
||||
use device::NetworkDevice;
|
||||
use error::{Error, Result};
|
||||
use netutils::{getcfg, MacAddr};
|
||||
use smoltcp;
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
@@ -15,6 +13,10 @@ use smoltcp::socket::AsSocket;
|
||||
use syscall::SchemeMut;
|
||||
use syscall;
|
||||
|
||||
use device::NetworkDevice;
|
||||
use error::{Error, Result};
|
||||
use buffer_pool::{Buffer, BufferPool};
|
||||
|
||||
struct RawHandle {
|
||||
flags: usize,
|
||||
events: usize,
|
||||
@@ -43,14 +45,16 @@ pub struct Smolnetd {
|
||||
raw_sockets: BTreeMap<usize, RawHandle>,
|
||||
udp_sockets: BTreeMap<usize, UdpHandle>,
|
||||
|
||||
input_queue: Rc<RefCell<VecDeque<Vec<u8>>>>,
|
||||
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
|
||||
input_buffer_pool: BufferPool,
|
||||
}
|
||||
|
||||
struct IpScheme<'a>(&'a mut Smolnetd);
|
||||
struct UdpScheme<'a>(&'a mut Smolnetd);
|
||||
|
||||
impl Smolnetd {
|
||||
const IP_BUFFER_SIZE: usize = 128;
|
||||
const INGRESS_PACKET_SIZE: usize = 2048;
|
||||
const SOCKET_BUFFER_SIZE: usize = 128; //packets
|
||||
const CHECK_TIMEOUT_MS: i64 = 1000;
|
||||
|
||||
pub fn new(network_file: File, ip_file: File, udp_file: File, time_file: File) -> Smolnetd {
|
||||
@@ -93,6 +97,7 @@ impl Smolnetd {
|
||||
next_fd: 0,
|
||||
input_queue,
|
||||
network_file,
|
||||
input_buffer_pool: BufferPool::new(Self::INGRESS_PACKET_SIZE),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +160,7 @@ impl Smolnetd {
|
||||
fn read_frames(&mut self) -> Result<usize> {
|
||||
let mut total_frames = 0;
|
||||
loop {
|
||||
let mut buffer = vec![0; 65536];
|
||||
let mut buffer = self.input_buffer_pool.get_buffer();
|
||||
let count = self.network_file
|
||||
.borrow_mut()
|
||||
.read(&mut buffer)
|
||||
@@ -166,7 +171,7 @@ impl Smolnetd {
|
||||
break;
|
||||
}
|
||||
trace!("got frame {}", count);
|
||||
buffer.resize(count, 0);
|
||||
buffer.resize(count);
|
||||
self.input_queue.borrow_mut().push_back(buffer);
|
||||
total_frames += 1;
|
||||
}
|
||||
@@ -206,9 +211,9 @@ impl<'a> syscall::SchemeMut for IpScheme<'a> {
|
||||
let path = str::from_utf8(url).or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?;
|
||||
let proto = u8::from_str_radix(path, 16).or(Err(syscall::Error::new(syscall::ENOENT)))?;
|
||||
|
||||
let mut rx_packets = Vec::with_capacity(Smolnetd::IP_BUFFER_SIZE);
|
||||
let mut tx_packets = Vec::with_capacity(Smolnetd::IP_BUFFER_SIZE);
|
||||
for _ in 0..Smolnetd::IP_BUFFER_SIZE {
|
||||
let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
|
||||
let mut tx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
|
||||
for _ in 0..Smolnetd::SOCKET_BUFFER_SIZE {
|
||||
rx_packets.push(smoltcp::socket::RawPacketBuffer::new(
|
||||
vec![0; NetworkDevice::MTU],
|
||||
));
|
||||
@@ -269,7 +274,6 @@ impl<'a> syscall::SchemeMut for IpScheme<'a> {
|
||||
}
|
||||
|
||||
fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result<usize> {
|
||||
trace!("Read {}", fd);
|
||||
use smoltcp::socket::AsSocket;
|
||||
|
||||
let handle = self.0
|
||||
@@ -280,6 +284,7 @@ impl<'a> syscall::SchemeMut for IpScheme<'a> {
|
||||
self.0.socket_set.get_mut(handle.socket_handle).as_socket();
|
||||
if socket.can_recv() {
|
||||
let length = socket.recv_slice(buf).expect("Can't receive slice");
|
||||
trace!("Read fd {} len {}", fd, length);
|
||||
Ok(length)
|
||||
} else if handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
|
||||
Ok(0)
|
||||
@@ -322,9 +327,9 @@ impl<'a> syscall::SchemeMut for UdpScheme<'a> {
|
||||
let (remote_ip, remote_port) = parse_socket(parts.next().unwrap_or(""));
|
||||
let (local_ip, local_port) = parse_socket(parts.next().unwrap_or(""));
|
||||
|
||||
let mut rx_packets = Vec::with_capacity(Smolnetd::IP_BUFFER_SIZE);
|
||||
let mut tx_packets = Vec::with_capacity(Smolnetd::IP_BUFFER_SIZE);
|
||||
for _ in 0..Smolnetd::IP_BUFFER_SIZE {
|
||||
let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
|
||||
let mut tx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
|
||||
for _ in 0..Smolnetd::SOCKET_BUFFER_SIZE {
|
||||
rx_packets.push(smoltcp::socket::UdpPacketBuffer::new(
|
||||
vec![0; NetworkDevice::MTU],
|
||||
));
|
||||
|
||||
Reference in New Issue
Block a user