Implement sys_select and nc is working

master
Jiajie Chen 6 years ago
parent 8b9aecca1c
commit 781630e06d

@ -93,9 +93,7 @@ impl Driver for E1000Interface {
};
if irq {
let timestamp = Instant::from_millis(unsafe {
(crate::trap::TICK / crate::consts::USEC_PER_TICK / 1000) as i64
});
let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
let mut sockets = self.sockets.lock();
match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(_) => {
@ -176,9 +174,7 @@ impl NetDriver for E1000Interface {
}
fn poll(&self) {
let timestamp = Instant::from_millis(unsafe {
(crate::trap::TICK / crate::consts::USEC_PER_TICK / 1000) as i64
});
let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
let mut sockets = self.sockets.lock();
match self.iface.lock().poll(&mut sockets, timestamp) {
Ok(_) => {

@ -1,5 +1,6 @@
//! Syscalls for file system
use core::mem::size_of;
use rcore_fs::vfs::Timespec;
use smoltcp::socket::*;
@ -58,7 +59,7 @@ pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResu
}
drop(proc);
let begin_time_ms = unsafe {crate::trap::TICK / crate::consts::USEC_PER_TICK / 1000};
let begin_time_ms = crate::trap::uptime_msec();
loop {
use PollEvents as PE;
let mut proc = process();
@ -74,27 +75,18 @@ pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResu
}
},
Some(FileLike::Socket(wrapper)) => {
if let SocketType::Tcp(_) = wrapper.socket_type {
let iface = &*(NET_DRIVERS.read()[0]);
let mut sockets = iface.sockets();
let mut socket = sockets.get::<TcpSocket>(wrapper.handle);
if !socket.is_open() {
poll.revents = poll.revents | PE::HUP;
events = events + 1;
} else {
if socket.can_recv() && poll.events.contains(PE::IN) {
poll.revents = poll.revents | PE::IN;
events = events + 1;
}
if socket.can_send() && poll.events.contains(PE::OUT) {
poll.revents = poll.revents | PE::OUT;
events = events + 1;
}
}
} else {
unimplemented!()
let (input, output, err) = poll_socket(&wrapper);
if err {
poll.revents = poll.revents | PE::HUP;
events = events + 1;
}
if input && poll.events.contains(PE::IN) {
poll.revents = poll.revents | PE::IN;
events = events + 1;
}
if output && poll.events.contains(PE::IN) {
poll.revents = poll.revents | PE::IN;
events = events + 1;
}
}
None => {
@ -109,7 +101,7 @@ pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResu
return Ok(events as isize);
}
let current_time_ms = unsafe {crate::trap::TICK / crate::consts::USEC_PER_TICK / 1000};
let current_time_ms = crate::trap::uptime_msec();
if timeout_msecs < (1 << 31) && current_time_ms - begin_time_ms > timeout_msecs {
return Ok(0);
}
@ -118,6 +110,130 @@ pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResu
}
}
const FD_PER_ITEM: usize = 8 * size_of::<u32>();
const MAX_FDSET_SIZE: usize = 1024 / FD_PER_ITEM;
struct FdSet {
addr: *mut u32,
nfds: usize,
saved: [u32; MAX_FDSET_SIZE]
}
impl FdSet {
/// Initialize a `FdSet` from pointer and number of fds
/// Check if the array is large enough
fn new(proc: &Process, addr: *mut u32, nfds: usize) -> Result<FdSet, SysError> {
let mut saved = [0u32; MAX_FDSET_SIZE];
if addr as usize != 0 {
let len = (nfds + FD_PER_ITEM - 1) / FD_PER_ITEM;
proc.memory_set.check_mut_array(addr, len)?;
if len > MAX_FDSET_SIZE {
return Err(SysError::EINVAL);
}
let slice = unsafe {slice::from_raw_parts_mut(addr, len)};
// save the fdset, and clear it
for i in 0..len {
saved[i] = slice[i];
slice[i] = 0;
}
}
Ok(FdSet {
addr,
nfds,
saved
})
}
/// Try to set fd in `FdSet`
/// Return true when `FdSet` is valid, and false when `FdSet` is bad (i.e. null pointer)
/// Fd should be less than nfds
fn set(&mut self, fd: usize) -> bool {
if self.addr as usize != 0 {
assert!(fd < self.nfds);
unsafe {
*self.addr.add(fd / 8 / size_of::<u32>()) |= 1 << (fd % (8 * size_of::<u32>()));
}
true
} else {
false
}
}
/// Check to see fd is see in original `FdSet`
/// Fd should be less than nfds
fn is_set(&mut self, fd: usize) -> bool {
assert!(fd < self.nfds);
self.saved[fd / 8 / size_of::<u32>()] & (1 << (fd % (8 * size_of::<u32>()))) != 0
}
}
pub fn sys_select(nfds: usize, read: *mut u32, write: *mut u32, err: *mut u32, timeout: *const TimeVal) -> SysResult {
info!("select: nfds: {}, read: {:?}, write: {:?}, err: {:?}, timeout: {:?}", nfds, read, write, err, timeout);
let mut proc = process();
let mut read_fds = FdSet::new(&proc, read, nfds)?;
let mut write_fds = FdSet::new(&proc, write, nfds)?;
let mut err_fds = FdSet::new(&proc, err, nfds)?;
let timeout_msecs = if timeout as usize != 0 {
proc.memory_set.check_ptr(timeout)?;
unsafe { *timeout }.to_msec()
} else {
// infinity
1 << 31
};
drop(proc);
let begin_time_ms = crate::trap::uptime_msec();
loop {
let mut proc = process();
let mut events = 0;
for (fd, file) in proc.files.iter() {
if *fd < nfds {
match file {
FileLike::File(_) => {
// FIXME: assume it is stdin for now
if STDIN.can_read() {
if read_fds.is_set(*fd){
read_fds.set(*fd);
events = events + 1;
}
}
},
FileLike::Socket(wrapper) => {
let (input, output, err) = poll_socket(&wrapper);
if err && err_fds.is_set(*fd){
err_fds.set(*fd);
events = events + 1;
}
if input && read_fds.is_set(*fd){
read_fds.set(*fd);
events = events + 1;
}
if output && write_fds.is_set(*fd){
write_fds.set(*fd);
events = events + 1;
}
}
}
}
}
drop(proc);
if events > 0 {
return Ok(events as isize);
}
let current_time_ms = crate::trap::uptime_msec();
if timeout_msecs < (1 << 31) && current_time_ms - begin_time_ms > timeout_msecs as usize {
return Ok(0);
}
Condvar::wait_any(&[&STDIN.pushed, &(*SOCKET_ACTIVITY)]);
}
}
pub fn sys_readv(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult {
info!("readv: fd: {}, iov: {:?}, count: {}", fd, iov_ptr, iov_count);
let mut proc = process();

@ -50,6 +50,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
019 => sys_readv(args[0], args[1] as *const IoVec, args[2]),
020 => sys_writev(args[0], args[1] as *const IoVec, args[2]),
// 021 => sys_access(),
023 => sys_select(args[0], args[1] as *mut u32, args[2] as *mut u32, args[3] as *mut u32, args[4] as *const TimeVal),
024 => sys_yield(),
033 => sys_dup2(args[0], args[1]),
// 034 => sys_pause(),

@ -325,18 +325,6 @@ pub fn sys_read_socket(proc: &mut Process, fd: usize, base: *mut u8, len: usize)
}
}
pub fn sys_select(
fd: usize,
inp: *const u8,
outp: *const u8,
exp: *const u8,
tvp: *const u8,
) -> SysResult {
info!("sys_select: fd: {}", fd);
warn!("sys_select is unimplemented");
Err(SysError::EINVAL)
}
pub fn sys_sendto(
fd: usize,
buffer: *const u8,
@ -527,10 +515,7 @@ pub fn sys_close_socket(proc: &mut Process, fd: usize, handle: SocketHandle) ->
}
pub fn sys_bind(fd: usize, addr: *const u8, len: usize) -> SysResult {
info!(
"sys_bind: fd: {} addr: {:?} len: {}",
fd, addr, len
);
info!("sys_bind: fd: {} addr: {:?} len: {}", fd, addr, len);
let mut proc = process();
proc.memory_set.check_array(addr, len)?;
@ -559,10 +544,7 @@ pub fn sys_bind(fd: usize, addr: *const u8, len: usize) -> SysResult {
}
pub fn sys_listen(fd: usize, backlog: usize) -> SysResult {
info!(
"sys_listen: fd: {} backlog: {}",
fd, backlog
);
info!("sys_listen: fd: {} backlog: {}", fd, backlog);
// smoltcp tcp sockets do not support backlog
// open multiple sockets for each connection
let mut proc = process();
@ -688,4 +670,33 @@ pub fn sys_getsockname(fd: usize, addr: *mut u8, addr_len: *mut u32) -> SysResul
} else {
Err(SysError::EINVAL)
}
}
}
/// Check socket state
/// return (in, out, err)
pub fn poll_socket(wrapper: &SocketWrapper) -> (bool, bool, bool) {
let mut input = false;
let mut output = false;
let mut err = false;
if let SocketType::Tcp(_) = wrapper.socket_type {
let iface = &*(NET_DRIVERS.read()[0]);
let mut sockets = iface.sockets();
let mut socket = sockets.get::<TcpSocket>(wrapper.handle);
if !socket.is_open() {
err = true;
} else {
if socket.can_recv() {
input = true;
}
if socket.can_send() {
output = true;
}
}
} else {
unimplemented!()
}
(input, output, err)
}

@ -17,6 +17,16 @@ pub struct TimeVal {
usec: u64,
}
impl TimeVal {
pub fn to_msec(&self) -> u64 {
self.sec * 1000 + self.usec / 1000
}
pub fn to_usec(&self) -> u64 {
self.sec * 1000_000 + self.usec
}
}
pub fn sys_gettimeofday(tv: *mut TimeVal, tz: *const u8) -> SysResult {
if tz as usize != 0 {
return Err(SysError::EINVAL);

@ -5,6 +5,10 @@ use log::*;
pub static mut TICK: usize = 0;
pub fn uptime_msec() -> usize {
unsafe {crate::trap::TICK / crate::consts::USEC_PER_TICK / 1000}
}
pub fn timer() {
if cpu::id() == 0 {
unsafe { TICK += 1; }

Loading…
Cancel
Save