diff --git a/kernel/src/drivers/net/e1000.rs b/kernel/src/drivers/net/e1000.rs index 7368208..0e90021 100644 --- a/kernel/src/drivers/net/e1000.rs +++ b/kernel/src/drivers/net/e1000.rs @@ -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(_) => { diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 15b3301..6394e6e 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -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::(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::(); +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 { + 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::()) |= 1 << (fd % (8 * size_of::())); + } + 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::()] & (1 << (fd % (8 * size_of::()))) != 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(); diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index b5cf478..1901595 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -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(), diff --git a/kernel/src/syscall/net.rs b/kernel/src/syscall/net.rs index 4cf4ea4..bf056bd 100644 --- a/kernel/src/syscall/net.rs +++ b/kernel/src/syscall/net.rs @@ -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) } -} \ No newline at end of file +} + +/// 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::(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) +} diff --git a/kernel/src/syscall/time.rs b/kernel/src/syscall/time.rs index 2140193..35c2ea5 100644 --- a/kernel/src/syscall/time.rs +++ b/kernel/src/syscall/time.rs @@ -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); diff --git a/kernel/src/trap.rs b/kernel/src/trap.rs index 61e2495..bff1c57 100644 --- a/kernel/src/trap.rs +++ b/kernel/src/trap.rs @@ -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; }