1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-22 16:16:16 +04:00

finish epoll implementation

This commit is contained in:
ssryps 2019-10-23 20:39:15 +08:00
parent 47e01cc79e
commit 14f0965bd2
7 changed files with 457 additions and 23 deletions

View File

@ -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

View File

@ -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<dyn Socket>),
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()"),
}
}
}

View File

@ -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<Stdin> = Arc::new(Stdin::default());
pub static ref STDOUT: Arc<Stdout> = Arc::new(Stdout::default());
pub static ref STDIN_EPOLL_LIST: Arc<VecDeque<(Arc<Process>, usize)>> = Arc::new(VecDeque::default());
}
impl INode for Stdin {

View File

@ -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<VecDeque<Arc<thread::Thread>>>,
pub epoll_queue: SpinNoIrqLock< VecDeque<(Arc<SpinNoIrqLock<Process>>, 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<SpinNoIrqLock<Process>>, 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<Thread>) {
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) => {}
}
}
}
}
}

View File

@ -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<usize, EpollEvent>,
pub readyList: SpinNoIrqLock<VecDeque<usize>>,
}
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::<EpollEvent>();
let written_len = size_of::<EpollEvent>();
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;

View File

@ -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::*;
@ -166,9 +167,12 @@ impl Syscall<'_> {
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_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)

View File

@ -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();