From 14f0965bd2de40f5f451501dcd115ae0b13478ac Mon Sep 17 00:00:00 2001 From: ssryps <825160150@qq.com> Date: Wed, 23 Oct 2019 20:39:15 +0800 Subject: [PATCH] finish epoll implementation --- kernel/src/arch/mipsel/interrupt.rs | 2 +- kernel/src/fs/file_like.rs | 23 ++ kernel/src/fs/stdio.rs | 4 + kernel/src/sync/condvar.rs | 52 +++- kernel/src/syscall/fs.rs | 382 ++++++++++++++++++++++++++-- kernel/src/syscall/mod.rs | 16 +- kernel/src/trap.rs | 1 + 7 files changed, 457 insertions(+), 23 deletions(-) diff --git a/kernel/src/arch/mipsel/interrupt.rs b/kernel/src/arch/mipsel/interrupt.rs index 578a16dd..f8e68e6f 100644 --- a/kernel/src/arch/mipsel/interrupt.rs +++ b/kernel/src/arch/mipsel/interrupt.rs @@ -119,7 +119,7 @@ fn external() { fn try_process_serial() -> bool { match super::io::getchar_option() { - Some(ch) => { + Some(ch) => {is trace!("Get char {} from serial", ch); crate::trap::serial(ch); true diff --git a/kernel/src/fs/file_like.rs b/kernel/src/fs/file_like.rs index d6539df6..1e219044 100644 --- a/kernel/src/fs/file_like.rs +++ b/kernel/src/fs/file_like.rs @@ -2,6 +2,7 @@ use core::fmt; use super::ioctl::*; use super::FileHandle; +use crate::syscall::EpollInstance; use crate::net::Socket; use crate::syscall::{SysError, SysResult}; use alloc::boxed::Box; @@ -15,6 +16,7 @@ use alloc::vec::Vec; pub enum FileLike { File(FileHandle), Socket(Box), + EpollInstance(EpollInstance), } impl FileLike { @@ -22,6 +24,9 @@ impl FileLike { let len = match self { FileLike::File(file) => file.read(buf)?, FileLike::Socket(socket) => socket.read(buf).0?, + FileLike::EpollInstance(instance) => { + return Err(SysError::EPERM); + } }; Ok(len) } @@ -29,6 +34,9 @@ impl FileLike { let len = match self { FileLike::File(file) => file.write(buf)?, FileLike::Socket(socket) => socket.write(buf, None)?, + FileLike::EpollInstance(instance) => { + return Err(SysError::EPERM); + } }; Ok(len) } @@ -43,6 +51,9 @@ impl FileLike { FileLike::Socket(socket) => { socket.ioctl(request, arg1, arg2, arg3)?; } + FileLike::EpollInstance(instance) => { + + } } Ok(0) } @@ -55,6 +66,9 @@ impl FileLike { let (read, write, error) = socket.poll(); PollStatus { read, write, error } } + FileLike::EpollInstance(instance) => { + return Err(SysError::EPERM); + } }; Ok(status) } @@ -67,6 +81,9 @@ impl FileLike { FileLike::Socket(socket) => { condvars.push(&(*crate::drivers::SOCKET_ACTIVITY)); }, + FileLike::EpollInstance(instance) => { + + } }; } @@ -76,9 +93,14 @@ impl FileLike { FileLike::Socket(socket) => { //TODO } + FileLike::EpollInstance(instance) => { + + } } Ok(0) } + + } impl fmt::Debug for FileLike { @@ -86,6 +108,7 @@ impl fmt::Debug for FileLike { match self { FileLike::File(file) => write!(f, "File({:?})", file), FileLike::Socket(socket) => write!(f, "Socket({:?})", socket), + FileLike::EpollInstance(instance) => write!(f, "EpollInstance()"), } } } diff --git a/kernel/src/fs/stdio.rs b/kernel/src/fs/stdio.rs index 8202d03c..88512474 100644 --- a/kernel/src/fs/stdio.rs +++ b/kernel/src/fs/stdio.rs @@ -8,6 +8,7 @@ use rcore_fs::vfs::*; use super::ioctl::*; use crate::sync::Condvar; use crate::sync::SpinNoIrqLock as Mutex; +use crate::process::Process; #[derive(Default)] pub struct Stdin { @@ -43,6 +44,8 @@ impl Stdin { pub fn can_read(&self) -> bool { return self.buf.lock().len() > 0; } + + } #[derive(Default)] @@ -51,6 +54,7 @@ pub struct Stdout; lazy_static! { pub static ref STDIN: Arc = Arc::new(Stdin::default()); pub static ref STDOUT: Arc = Arc::new(Stdout::default()); + pub static ref STDIN_EPOLL_LIST: Arc, usize)>> = Arc::new(VecDeque::default()); } impl INode for Stdin { diff --git a/kernel/src/sync/condvar.rs b/kernel/src/sync/condvar.rs index e9e4ae01..e36f9724 100644 --- a/kernel/src/sync/condvar.rs +++ b/kernel/src/sync/condvar.rs @@ -1,13 +1,17 @@ use super::*; -use crate::process::processor; +use crate::process::{processor, current_thread}; use crate::thread; use alloc::collections::VecDeque; use alloc::sync::Arc; use alloc::vec::Vec; +use crate::process::Process; +use rcore_thread::std_thread::Thread; + #[derive(Default)] pub struct Condvar { wait_queue: SpinNoIrqLock>>, + pub epoll_queue: SpinNoIrqLock< VecDeque<(Arc>, usize, usize, usize)> >, } impl Condvar { @@ -91,12 +95,16 @@ impl Condvar { pub fn notify_one(&self) { if let Some(t) = self.wait_queue.lock().front() { + self.epoll_callback(t); t.unpark(); } } + + pub fn notify_all(&self) { let queue = self.wait_queue.lock(); for t in queue.iter() { + self.epoll_callback(t); t.unpark(); } } @@ -115,4 +123,46 @@ impl Condvar { count } + + pub fn add_epoll_list(condvar: &Condvar, proc: Arc>, tid :usize, epfd: usize, fd: usize){ + condvar.epoll_queue.lock().push_back((proc, tid, epfd, fd)); + } + + pub fn remove_epoll_list(condvar: &Condvar, tid :usize, epfd: usize, fd: usize) -> bool{ + let mut epoll_list = condvar.epoll_queue.lock(); + for idx in 0..epoll_list.len(){ + if epoll_list[idx].1 == tid && epoll_list[idx].2 == epfd && epoll_list[idx].3 == fd{ + epoll_list.remove(idx); + return true; + } + } + return false; + } + + fn epoll_callback(&self, thread: &Arc) { + let epoll_list = self.epoll_queue.lock(); + if epoll_list.len() <= 0 { + return; + } + for idx in 0..epoll_list.len(){ + let proc = &epoll_list[idx].0; + let tid = &epoll_list[idx].1; + let epfd = &epoll_list[idx].2; + let fd = &epoll_list[idx].3; + + if thread.id() == *tid { + let mut proc = proc.lock(); + match proc.get_epoll_instance(*epfd) { + Ok(instacne) => { + let mut readylist = instacne.readyList.lock(); + if !readylist.contains(fd) { + readylist.push_back(*fd); + } + } + Err(r) => {} + } + } + } + } + } diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index eda7c6fe..ae1fd713 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -9,11 +9,17 @@ use crate::drivers::SOCKET_ACTIVITY; use crate::trap::TICK_ACTIVITY; use crate::fs::*; use crate::memory::MemorySet; -use crate::sync::Condvar; +use crate::sync::{Condvar, SpinNoIrqLock}; +use alloc::{collections::BTreeMap}; use bitvec::prelude::{BitSlice, BitVec, LittleEndian}; use super::*; +use bitflags::_core::task::Poll; +use alloc::collections::VecDeque; +use rcore_fs::vfs::PollStatus; +use crate::net::server; +use crate::process::Process; impl Syscall<'_> { pub fn sys_read(&mut self, fd: usize, base: *mut u8, len: usize) -> SysResult { @@ -273,7 +279,11 @@ impl Syscall<'_> { ) -> SysResult { info!("epoll_create: size: {:?}", size); - return Ok(0); + if (size as i32) < 0 { + return Err(SysError::EINVAL); + + } + return self.sys_epoll_create1(0); } @@ -283,7 +293,13 @@ impl Syscall<'_> { ) -> SysResult { info!("epoll_create1: flags: {:?}", flags); - return Ok(0); + let mut proc = self.process(); + + let epollInstance = EpollInstance::new(flags); + let fd = proc.add_file(FileLike::EpollInstance(epollInstance)); + + println!("kernel> epoll create "); + Ok(fd) } pub fn sys_epoll_ctl( @@ -291,9 +307,32 @@ impl Syscall<'_> { epfd: usize, op: usize, fd: usize, - event: *mut PollEvents, + event: *mut EpollEvent, ) -> SysResult { - return Ok(0); + + let mut proc = self.process(); + if !proc.pid.is_init() { + // we trust pid 0 process + info!("sys_epoll_ctl: epfd: {}, op: {:?}, fd: {:#x}", epfd, op, fd); + } + + let slice = unsafe { self.vm().check_read_array(event, 1)? }; + + if proc.files.get(&fd).is_none(){ + return Err(SysError::EPERM); + } + + let epollInstance = match proc.get_epoll_instance(epfd) { + Ok(ins) => ins, + Err(err) => { + return Err(err); + } + }; + + let ret = epollInstance.epoll_ctl(&self.vm(),op, fd, event)?; + + println!("kernel> epoll ctl"); + return Ok(ret); } @@ -304,8 +343,7 @@ impl Syscall<'_> { maxevents: usize, timeout: usize, ) -> SysResult { - return Ok(0); - + self.sys_epoll_pwait(epfd, events, maxevents, timeout, 0) } pub fn sys_epoll_pwait( @@ -313,11 +351,176 @@ impl Syscall<'_> { epfd: usize, events: *mut EpollEvent, maxevents: usize, - timeout: usize, - sigset_t: *mut SigSet_t, + timeout_msecs: usize, + sigset_t: usize, ) -> SysResult { - return Ok(0); + info!("epoll_pwait: epfd: {}, timeout: {:?}", epfd, timeout_msecs); + let mut proc = self.process(); + let writeslice = unsafe { self.vm().check_write_array(events, maxevents)? }; + let epollInstance = proc.get_unmut_epoll_instance(epfd)?; + let keys: Vec<_> = epollInstance.events.keys().cloned().collect(); + + for (k, v) in epollInstance.events.iter(){ + // if !v.contains(EpollEvent::EPOLLET) { + match &proc.files.get(k) { + None => { + return Err(SysError::EINVAL); + }, + Some(file_like) => { + let status = file_like.poll()?; + if status.write || status.read || status.error { + epollInstance.readyList.lock().push_back(*k); + } + } + } + // } + } + + drop(proc); + + + let mut callbacks = alloc::vec![]; + for fd in &keys { + let mut proc = self.process(); + match proc.files.get(&fd){ + None => { + return Err(SysError::EINVAL); + }, + Some(file_like) => { + match file_like{ + FileLike::File(file) => { + Condvar::add_epoll_list( &crate::fs::STDIN.pushed, self.thread.proc.clone(), + thread::current().id(), epfd, *fd); + callbacks.push((0, thread::current().id(), epfd, *fd)); + }, + FileLike::Socket(socket) => { + Condvar::add_epoll_list( &(*crate::drivers::SOCKET_ACTIVITY), self.thread.proc.clone(), + thread::current().id(), epfd, *fd); + callbacks.push((1, thread::current().id(), epfd, *fd)); + }, + FileLike::EpollInstance(instance) => { + return Err(SysError::EINVAL); + } + }; + } + } + drop(proc); + } + + let mut condvars = Vec::new(); + condvars.push(&(*TICK_ACTIVITY)); + condvars.push(&STDIN.pushed); + condvars.push(&(*SOCKET_ACTIVITY)); + + + let begin_time_ms = crate::trap::uptime_msec(); + let condition = move || { + use PollEvents as PE; + let mut proc = self.process(); + + let epollInstance = match proc.get_epoll_instance(epfd) { + Ok(ins) => ins, + Err(err) => { + return Some(Err(err)); + } + }; + let readylist = epollInstance.readyList.lock().clone(); + // println!("readylist : {:?}", readylist); + let mut events_num = 0; + + for infd in readylist.iter() { + let mut status: PollStatus = Default::default(); + { + if proc.files.get(&infd).is_some() { + let file_like = proc.files.get(&infd).unwrap(); + let _status = match file_like.poll() { + Ok(ret) => ret, + Err(err) => return Some(Err(err)), + }; + status.write = _status.write; + status.read = _status.read; + status.error = _status.error; + } + } + + { + let epollInstance = match proc.get_epoll_instance(epfd) { + Ok(ins) => ins, + Err(err) => { + return Some(Err(err)); + } + }; + let epollevent = epollInstance.events.get_mut(&infd)?; + + if status.error { + unsafe { + let _ = epollevent.copy_result_to(EpollEvent::EPOLLERR, &self.vm(), events, events_num); + } + events_num += 1; + } + if status.read && epollevent.contains(EpollEvent::EPOLLIN) { + unsafe { + let _ = epollevent.copy_result_to(EpollEvent::EPOLLIN, &self.vm(), events, events_num); + } + events_num += 1; + } + if status.write && epollevent.contains(EpollEvent::EPOLLOUT) { + unsafe { + let _ = epollevent.copy_result_to(EpollEvent::EPOLLOUT, &self.vm(), events, events_num); + } + events_num += 1; + } + } +// } else { +// unsafe { +// epollevent.copy_result_to(EpollEvent::EPOLLERR, &self.vm(), events, events_num); +// } +// events_num += 1; +// } + } + + { + let epollInstance = match proc.get_epoll_instance(epfd) { + Ok(ins) => ins, + Err(err) => { + return Some(Err(err)); + } + }; + let mut lock = epollInstance.readyList.lock(); + lock.retain(|x| false); + } + + drop(proc); + + // some event happens, so evoke the process + if events_num > 0 { + return Some(Ok(events_num)); + } + + let current_time_ms = crate::trap::uptime_msec(); + // time runs out, so the evoke the process + if timeout_msecs < (1 << 31) && current_time_ms - begin_time_ms > timeout_msecs { + return Some(Ok(0)); + } + return None; + }; + + let num = Condvar::wait_events(condvars.as_slice(), condition).unwrap(); + + for cb in callbacks.iter(){ + if cb.0 == 0 { + if !Condvar::remove_epoll_list( &crate::fs::STDIN.pushed, cb.1, cb.2, cb.3){ + println!("something goes wrong"); + } + } + if cb.0 == 1 { + if !Condvar::remove_epoll_list( &(*crate::drivers::SOCKET_ACTIVITY), cb.1, cb.2, cb.3){ + println!("something goes wrong"); + } + } + } + Ok(num) } pub fn sys_readv(&mut self, fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult { @@ -1610,22 +1813,167 @@ impl FdSet { } } -pub struct SigSet_t { - __val: [u64; 1024 / 8 / 8], + +//#[derive(Clone)] +pub struct EpollInstance { + pub events: BTreeMap, + pub readyList: SpinNoIrqLock>, } -union epoll_data_t { +impl Clone for EpollInstance { + fn clone(&self) -> Self { + EpollInstance::new(0) + } +} + +impl EpollInstance { + pub fn new(flags: usize) -> Self { + return EpollInstance { + events: BTreeMap::new(), + readyList: Default::default(), + } + } + + pub fn epoll_ctl(&mut self, vm: &MemorySet, op: usize, fd: usize, event: *mut EpollEvent) -> SysResult { + match (op as i32) { + EPollCtlOp::EPOLLCTLADD => { + if self.events.get(&fd).is_none() { + let evs = unsafe { vm.check_read_array(event, 1)? }; + for ev in evs.iter() { + self.events.insert(fd, ev.clone()); + } + } else { + return Err(SysError::EPERM); + } + + } + EPollCtlOp::EPOLLCTLMOD => { + if self.events.get(&fd).is_some() { + let evs = unsafe { vm.check_read_array(event, 1)? }; + for ev in evs.iter() { + self.events.remove(&fd); + self.events.insert(fd, ev.clone()); + } + } else { + return Err(SysError::EPERM); + } + } + EPollCtlOp::EPOLLCTLDEL => { + if self.events.get(&fd).is_some() { + let evs = unsafe { vm.check_read_array(event, 1)? }; + for ev in evs.iter() { + self.events.remove(&fd); + } + } else { + return Err(SysError::EPERM); + } + + } + _ => { + return Err(SysError::EPERM); + } + } + Ok(0) + } +} + + +//#[derive(Clone)] +//union EpollData { +// ptr: u64, +// fd: i32, +// v32: u32, +// v64: u64, +//} + +#[derive(Clone)] +pub struct EpollData { ptr: u64, - fd: i32, - v32: u32, - v64: u64, } +#[repr(packed)] +#[derive(Clone)] pub struct EpollEvent { events: u32, /* Epoll events */ - data: epoll_data_t, /* User data variable */ + data: EpollData, /* User data variable */ } +impl EpollEvent{ + unsafe fn copy_result_to(&mut self, events: u32, vm: &MemorySet, + baseAddr: *mut EpollEvent, idx: usize) -> SysResult{ + let tmp = self.events; + self.events = events; + + let addr = baseAddr as usize + idx * size_of::(); + let written_len = size_of::(); + let target = vm.check_write_array(addr as *mut u8, written_len)?; + let source = slice::from_raw_parts(self as *mut EpollEvent as *const u8, written_len); + target.copy_from_slice(source); + self.events = tmp; + + Ok(0) + } + + fn contains(&self, events: u32) -> bool { + if (self.events & events) == 0 { + return false; + } else { + return true; + } + } +} + +pub struct EPollCtlOp; +impl EPollCtlOp{ + const EPOLLCTLADD: i32 = 1; /* Add a file descriptor to the interface. */ + const EPOLLCTLDEL: i32 = 2; /* Remove a file descriptor from the interface. */ + const EPOLLCTLMOD: i32 = 3; /* Change file descriptor epoll_event structure. */ +} + + +impl EpollEvent { + const EPOLLIN: u32 = 0x001; + const EPOLLOUT: u32 = 0x004; + const EPOLLERR: u32 = 0x008; + const EPOLLHUP: u32 = 0x010; + + const EPOLLPRI: u32 = 0x002; + const EPOLLRDNORM: u32 = 0x040; + const EPOLLRDBAND: u32 = 0x080; + const EPOLLWRNORM: u32 = 0x100; + const EPOLLWRBAND: u32 = 0x200; + const EPOLLMSG: u32 = 0x400; + const EPOLLRDHUP: u32 = 0x2000; + const EPOLLEXCLUSIVE: u32 = 1 << 28; + const EPOLLWAKEUP: u32 = 1 << 29; + const EPOLLONESHOT: u32 = 1 << 30; + const EPOLLET: u32 = 1 << 31; +} + + +impl Process { + pub fn get_epoll_instance(&mut self, fd: usize) -> Result<&mut EpollInstance, SysError> { + match self.get_file_like(fd)? { + FileLike::EpollInstance(instance) => Ok(instance), + _ => Err(SysError::EPERM), + } + } + + pub fn get_unmut_epoll_instance(&self, fd: usize) -> Result<&EpollInstance, SysError> { + match self.files.get(&fd) { + Some(file_like) => { + match file_like { + FileLike::EpollInstance(instance) => Ok(&instance), + _ => Err(SysError::EPERM), + } + } + None => { + return Err(SysError::EPERM); + } + } + } + +} /// Pathname is interpreted relative to the current working directory(CWD) const AT_FDCWD: usize = -100isize as usize; diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 599b6060..ce9a3a49 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -15,6 +15,7 @@ use crate::process::*; use crate::sync::{Condvar, MutexGuard, SpinNoIrq}; use crate::thread; use crate::util; +use crate::syscall::{EpollEvent}; pub use self::custom::*; pub use self::fs::*; @@ -165,10 +166,13 @@ impl Syscall<'_> { SYS_PPOLL => { self.sys_ppoll(args[0] as *mut PollFd, args[1], args[2] as *const TimeSpec) } // ignore sigmask - SYS_EPOLL_CREATE1 => self.sys_epoll_create1(args[0]), + SYS_EPOLL_CREATE1 => self.sys_epoll_create1(args[0]), + SYS_EPOLL_CTL => self.sys_epoll_ctl(args[0], args[1], args[2], args[3] as *mut EpollEvent), SYS_EPOLL_PWAIT => self.sys_epoll_pwait(args[0], args[1] as *mut EpollEvent, - args[2], args[3], args[4] as *mut SigSet_t), + args[2], args[3], args[4]), + SYS_EVENTFD2=> self.unimplemented("eventfd2", Err(SysError::EACCES)), + SYS_SOCKETPAIR => self.unimplemented("socketpair", Err(SysError::EACCES)), // file system SYS_STATFS => self.unimplemented("statfs", Err(SysError::EACCES)), SYS_FSTATFS => self.unimplemented("fstatfs", Err(SysError::EACCES)), @@ -348,6 +352,7 @@ impl Syscall<'_> { if let Some(ret) = ret { ret } else { + println!("unknown syscall id: {}, args: {:x?}", id, args); error!("unknown syscall id: {}, args: {:x?}", id, args); crate::trap::error(self.tf); } @@ -424,6 +429,9 @@ impl Syscall<'_> { 3 => self.sys_semctl(args[1], args[2], args[3], args[4] as isize), _ => return None, }, + SYS_EPOLL_CREATE => self.sys_epoll_create(args[0]), + SYS_EPOLL_WAIT =>self.sys_epoll_wait(args[0], args[1] as *mut EpollEvent, args[2], args[3]), + _ => return None, }; Some(ret) @@ -459,8 +467,8 @@ impl Syscall<'_> { SYS_CHOWN => self.unimplemented("chown", Ok(0)), SYS_ARCH_PRCTL => self.sys_arch_prctl(args[0] as i32, args[1]), SYS_TIME => self.sys_time(args[0] as *mut u64), - SYS_EPOLL_CREATE => self.unimplemented("epoll_create", Err(SysError::ENOSYS)), - // SYS_EPOLL_WAIT =>self.sys_epoll_wait(args[0], args[1] as *mut EpollEvent, args[2], args[3]), + SYS_EPOLL_CREATE => self.sys_epoll_create(args[0]), + SYS_EPOLL_WAIT =>self.sys_epoll_wait(args[0], args[1] as *mut EpollEvent, args[2], args[3]), _ => return None, }; Some(ret) diff --git a/kernel/src/trap.rs b/kernel/src/trap.rs index 402f9a7f..b846e152 100644 --- a/kernel/src/trap.rs +++ b/kernel/src/trap.rs @@ -29,6 +29,7 @@ pub fn timer() { } pub fn error(tf: &TrapFrame) -> ! { + println!("kernel error"); error!("{:#x?}", tf); unsafe { let mut proc = current_thread().proc.lock();