From a6bb042bd9f9a100e5badf4df4b34237fe053bd6 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Wed, 13 Mar 2019 11:41:06 +0800 Subject: [PATCH] Support zero timeout in sys_select. Improve e1000 driver speed --- kernel/src/drivers/net/e1000.rs | 155 +++++++++++++++----------------- kernel/src/syscall/fs.rs | 6 ++ user | 2 +- 3 files changed, 81 insertions(+), 82 deletions(-) diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index 560f162..d07032e 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -27,6 +27,11 @@ use crate::HEAP_ALLOCATOR; use super::super::{DeviceType, Driver, NetDriver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY}; +// At the beginning, all transmit descriptors have there status non-zero, +// so we need to track whether we are using the descriptor for the first time. +// When the descriptors wrap around, we set first_trans to false, +// and lookup status instead for checking whether it is empty. + pub struct E1000 { header: usize, size: usize, @@ -116,51 +121,6 @@ impl Driver for E1000Interface { } } -impl E1000 { - fn transmit_available(&self) -> bool { - if let None = active_table().get_entry(self.header) { - let mut current_addr = self.header; - while current_addr < self.header + self.size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - - let e1000 = - unsafe { slice::from_raw_parts_mut(self.header as *mut Volatile, self.size / 4) }; - let send_queue_size = PAGE_SIZE / size_of::(); - let send_queue = unsafe { - slice::from_raw_parts_mut(self.send_page as *mut E1000RecvDesc, send_queue_size) - }; - let tdt = e1000[E1000_TDT].read(); - let index = (tdt as usize) % send_queue_size; - let send_desc = &mut send_queue[index]; - - return self.first_trans || (*send_desc).status & 1 != 0; - } - - fn receive_available(&self) -> bool { - if let None = active_table().get_entry(self.header) { - let mut current_addr = self.header; - while current_addr < self.header + self.size { - active_table().map_if_not_exists(current_addr, current_addr); - current_addr = current_addr + PAGE_SIZE; - } - } - - let e1000 = - unsafe { slice::from_raw_parts_mut(self.header as *mut Volatile, self.size / 4) }; - let recv_queue_size = PAGE_SIZE / size_of::(); - let mut recv_queue = unsafe { - slice::from_raw_parts_mut(self.recv_page as *mut E1000RecvDesc, recv_queue_size) - }; - let mut rdt = e1000[E1000_RDT].read(); - let index = (rdt as usize + 1) % recv_queue_size; - let recv_desc = &mut recv_queue[index]; - return (*recv_desc).status & 1 != 0; - } -} - impl NetDriver for E1000Interface { fn get_mac(&self) -> EthernetAddress { self.iface.lock().ethernet_addr() @@ -215,7 +175,7 @@ struct E1000RecvDesc { special: u8, } -pub struct E1000RxToken(E1000Driver); +pub struct E1000RxToken(Vec); pub struct E1000TxToken(E1000Driver); impl<'a> phy::Device<'a> for E1000Driver { @@ -224,9 +184,51 @@ impl<'a> phy::Device<'a> for E1000Driver { fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { let driver = self.0.lock(); - if driver.transmit_available() && driver.receive_available() { - // potential racing - Some((E1000RxToken(self.clone()), E1000TxToken(self.clone()))) + + if let None = active_table().get_entry(driver.header) { + let mut current_addr = driver.header; + while current_addr < driver.header + driver.size { + active_table().map_if_not_exists(current_addr, current_addr); + current_addr = current_addr + PAGE_SIZE; + } + } + + let e1000 = + unsafe { slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) }; + + let send_queue_size = PAGE_SIZE / size_of::(); + let send_queue = unsafe { + slice::from_raw_parts_mut(driver.send_page as *mut E1000SendDesc, send_queue_size) + }; + let tdt = e1000[E1000_TDT].read(); + let index = (tdt as usize) % send_queue_size; + let send_desc = &mut send_queue[index]; + + let recv_queue_size = PAGE_SIZE / size_of::(); + let mut recv_queue = unsafe { + slice::from_raw_parts_mut(driver.recv_page as *mut E1000RecvDesc, recv_queue_size) + }; + let mut rdt = e1000[E1000_RDT].read(); + let index = (rdt as usize + 1) % recv_queue_size; + let recv_desc = &mut recv_queue[index]; + + let transmit_avail = driver.first_trans || (*send_desc).status & 1 != 0; + let receive_avail = (*recv_desc).status & 1 != 0; + + if transmit_avail && receive_avail { + let buffer = unsafe { + slice::from_raw_parts( + driver.recv_buffers[index] as *const u8, + recv_desc.len as usize, + ) + }; + + recv_desc.status = recv_desc.status & !1; + + rdt = (rdt + 1) % recv_queue_size as u32; + e1000[E1000_RDT].write(rdt); + + Some((E1000RxToken(buffer.to_vec()), E1000TxToken(self.clone()))) } else { None } @@ -234,7 +236,27 @@ impl<'a> phy::Device<'a> for E1000Driver { fn transmit(&'a mut self) -> Option { let driver = self.0.lock(); - if driver.transmit_available() { + + if let None = active_table().get_entry(driver.header) { + let mut current_addr = driver.header; + while current_addr < driver.header + driver.size { + active_table().map_if_not_exists(current_addr, current_addr); + current_addr = current_addr + PAGE_SIZE; + } + } + + let e1000 = + unsafe { slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) }; + + let send_queue_size = PAGE_SIZE / size_of::(); + let send_queue = unsafe { + slice::from_raw_parts_mut(driver.send_page as *mut E1000RecvDesc, send_queue_size) + }; + let tdt = e1000[E1000_TDT].read(); + let index = (tdt as usize) % send_queue_size; + let send_desc = &mut send_queue[index]; + let transmit_avail = driver.first_trans || (*send_desc).status & 1 != 0; + if transmit_avail { Some(E1000TxToken(self.clone())) } else { None @@ -244,7 +266,7 @@ impl<'a> phy::Device<'a> for E1000Driver { fn capabilities(&self) -> DeviceCapabilities { let mut caps = DeviceCapabilities::default(); caps.max_transmission_unit = 1536; - caps.max_burst_size = Some(32); + caps.max_burst_size = Some(64); caps } } @@ -254,36 +276,7 @@ impl phy::RxToken for E1000RxToken { where F: FnOnce(&[u8]) -> Result, { - let data = { - let mut driver = (self.0).0.lock(); - let e1000 = unsafe { - slice::from_raw_parts_mut(driver.header as *mut Volatile, driver.size / 4) - }; - let recv_queue_size = PAGE_SIZE / size_of::(); - let mut recv_queue = unsafe { - slice::from_raw_parts_mut(driver.recv_page as *mut E1000RecvDesc, recv_queue_size) - }; - let mut rdt = e1000[E1000_RDT].read(); - let index = (rdt as usize + 1) % recv_queue_size; - let recv_desc = &mut recv_queue[index]; - assert!(recv_desc.status & 1 != 0); - let buffer = unsafe { - slice::from_raw_parts( - driver.recv_buffers[index] as *const u8, - recv_desc.len as usize, - ) - }; - - recv_desc.status = recv_desc.status & !1; - - rdt = (rdt + 1) % recv_queue_size as u32; - e1000[E1000_RDT].write(rdt); - - buffer - }; - let result = f(&data); - - result + f(&self.0) } } diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 552ed8d..e0a8143 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -245,7 +245,13 @@ pub fn sys_select(nfds: usize, read: *mut u32, write: *mut u32, err: *mut u32, t return Ok(events); } + if timeout_msecs == 0 { + // no timeout, return now; + return Ok(0); + } + let current_time_ms = crate::trap::uptime_msec(); + // infinity check if timeout_msecs < (1 << 31) && current_time_ms - begin_time_ms > timeout_msecs as usize { return Ok(0); } diff --git a/user b/user index 7db2bd1..bae6866 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit 7db2bd11e523f6c176d8aa278a57e5412bc448fa +Subproject commit bae6866610fc24ca66584c1a5200648d2de7d767