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

Add UserPtr, rewrite poll by async

This commit is contained in:
Jiajie Chen 2020-06-16 09:31:54 +08:00
parent bc845fa9ff
commit 5d05bccdd5
10 changed files with 293 additions and 70 deletions

10
kernel/Cargo.lock generated
View File

@ -491,7 +491,7 @@ dependencies = [
[[package]]
name = "rcore-fs"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-fs?rev=1fb7c0ee#1fb7c0ee2eedb37516344e93c271c3e6795f9a89"
source = "git+https://github.com/rcore-os/rcore-fs?rev=517af47#517af47ff3f632f05b91b9ea73a047aa8df363f3"
dependencies = [
"filetime",
"spin",
@ -501,7 +501,7 @@ dependencies = [
[[package]]
name = "rcore-fs-devfs"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-fs?rev=1fb7c0ee#1fb7c0ee2eedb37516344e93c271c3e6795f9a89"
source = "git+https://github.com/rcore-os/rcore-fs?rev=517af47#517af47ff3f632f05b91b9ea73a047aa8df363f3"
dependencies = [
"log",
"rcore-fs",
@ -511,7 +511,7 @@ dependencies = [
[[package]]
name = "rcore-fs-mountfs"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-fs?rev=1fb7c0ee#1fb7c0ee2eedb37516344e93c271c3e6795f9a89"
source = "git+https://github.com/rcore-os/rcore-fs?rev=517af47#517af47ff3f632f05b91b9ea73a047aa8df363f3"
dependencies = [
"lazy_static",
"log",
@ -522,7 +522,7 @@ dependencies = [
[[package]]
name = "rcore-fs-ramfs"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-fs?rev=1fb7c0ee#1fb7c0ee2eedb37516344e93c271c3e6795f9a89"
source = "git+https://github.com/rcore-os/rcore-fs?rev=517af47#517af47ff3f632f05b91b9ea73a047aa8df363f3"
dependencies = [
"log",
"rcore-fs",
@ -532,7 +532,7 @@ dependencies = [
[[package]]
name = "rcore-fs-sfs"
version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-fs?rev=1fb7c0ee#1fb7c0ee2eedb37516344e93c271c3e6795f9a89"
source = "git+https://github.com/rcore-os/rcore-fs?rev=517af47#517af47ff3f632f05b91b9ea73a047aa8df363f3"
dependencies = [
"bitvec",
"log",

View File

@ -66,11 +66,11 @@ pci = { git = "https://github.com/rcore-os/pci-rs", rev = "a4e7cea6" }
pc-keyboard = "0.5"
rcore-console = { git = "https://github.com/rcore-os/rcore-console", rev = "b7bacf9", default-features = false }
rcore-memory = { path = "../crate/memory" }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1fb7c0ee" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1fb7c0ee" }
rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1fb7c0ee" }
rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1fb7c0ee" }
rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "1fb7c0ee" }
rcore-fs = { git = "https://github.com/rcore-os/rcore-fs", rev = "517af47" }
rcore-fs-sfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "517af47" }
rcore-fs-ramfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "517af47" }
rcore-fs-mountfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "517af47" }
rcore-fs-devfs = { git = "https://github.com/rcore-os/rcore-fs", rev = "517af47" }
rlibc = "1.0"
smoltcp = { git = "https://github.com/rcore-os/smoltcp", rev = "5bd87c7c", default-features = false, features = ["alloc", "log", "ethernet", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] }
spin = "0.5"

View File

@ -79,7 +79,7 @@ use x86_64::registers::control::Cr2;
#[allow(non_upper_case_globals)]
#[no_mangle]
pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
info!(
trace!(
"Interrupt: {:#x} @ CPU{}",
tf.trap_num,
super::super::cpu::id()

View File

@ -220,6 +220,10 @@ impl FileHandle {
self.inode.poll()
}
pub async fn async_poll(&self) -> Result<PollStatus> {
self.inode.async_poll().await
}
pub fn io_control(&self, cmd: u32, arg: usize) -> Result<usize> {
self.inode.io_control(cmd, arg)
}

View File

@ -75,6 +75,19 @@ impl FileLike {
};
Ok(status)
}
pub async fn async_poll(&self) -> Result<PollStatus, SysError> {
let status = match self {
FileLike::File(file) => file.async_poll().await?,
FileLike::Socket(socket) => {
let (read, write, error) = socket.poll();
PollStatus { read, write, error }
}
FileLike::EpollInstance(_) => {
return Err(SysError::ENOSYS);
}
};
Ok(status)
}
}
impl fmt::Debug for FileLike {

View File

@ -369,7 +369,7 @@ impl Thread {
Arc::new(Thread {
id: 0,
inner: Mutex::new(ThreadInner {
context: Some(Box::from(context))
context: Some(Box::from(context)),
}),
kstack,
clear_child_tid: 0,

View File

@ -13,6 +13,10 @@ use crate::fs::*;
use crate::memory::MemorySet;
use crate::sync::Condvar;
use crate::trap::TICK_ACTIVITY;
use alloc::boxed::Box;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
use bitvec::prelude::{BitSlice, BitVec, Lsb0};
@ -81,31 +85,33 @@ impl Syscall<'_> {
/// sys_ppoll function is for handling the third argument of sys_poll.
pub fn sys_ppoll(
pub async fn sys_ppoll(
&mut self,
ufds: *mut PollFd,
ufds: UserInOutPtr<PollFd>,
nfds: usize,
timeout: *const TimeSpec,
timeout: UserInPtr<TimeSpec>,
) -> SysResult {
let proc = self.process();
if !proc.pid.is_init() {
info!(
"ppoll: ufds: {:#x}, nfds: {}, timeout: {:#x}",
ufds as usize, nfds, timeout as usize
);
info!("ppoll: nfds: {}", nfds);
}
let timeout_msecs = if timeout.is_null() {
1 << 31 // infinity
} else {
let timeout = unsafe { self.vm().check_read_ptr(timeout)? };
let timeout = timeout.read().unwrap();
timeout.to_msec()
};
drop(proc);
self.sys_poll(ufds, nfds, timeout_msecs as usize)
self.sys_poll(ufds, nfds, timeout_msecs as usize).await
}
pub fn sys_poll(&mut self, ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResult {
pub async fn sys_poll(
&mut self,
ufds: UserInOutPtr<PollFd>,
nfds: usize,
timeout_msecs: usize,
) -> SysResult {
let proc = self.process();
if !proc.pid.is_init() {
// we trust pid 0 process
@ -118,7 +124,7 @@ impl Syscall<'_> {
// check whether the fds is valid and is owned by this process
let condvars = alloc::vec![&(*TICK_ACTIVITY), &STDIN.pushed, &(*SOCKET_ACTIVITY)];
let polls = unsafe { self.vm().check_write_array(ufds, nfds)? };
let polls = ufds.read_array(nfds).unwrap();
if !proc.pid.is_init() {
info!("poll: fds: {:?}", polls);
@ -126,55 +132,62 @@ impl Syscall<'_> {
drop(proc);
let begin_time_ms = crate::trap::uptime_msec();
Condvar::wait_events(condvars.as_slice(), move || {
if has_signal_to_do() {
return Some(Err(EINTR));
}
struct PollFuture<'a> {
polls: Vec<PollFd>,
syscall: &'a Syscall<'a>,
}
use PollEvents as PE;
let proc = self.process();
let mut events = 0;
impl<'a> Future for PollFuture<'a> {
type Output = SysResult;
// iterate each poll to check whether it is ready
for poll in polls.iter_mut() {
poll.revents = PE::empty();
if let Some(file_like) = proc.files.get(&(poll.fd as usize)) {
let status = match file_like.poll() {
Ok(ret) => ret,
Err(err) => return Some(Err(err)),
};
if status.error {
poll.revents |= PE::HUP;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
use PollEvents as PE;
let proc = self.syscall.process();
let mut events = 0;
// iterate each poll to check whether it is ready
for poll in self.as_mut().polls.iter_mut() {
poll.revents = PE::empty();
if let Some(file_like) = proc.files.get(&(poll.fd as usize)) {
let mut fut = Box::pin(file_like.async_poll());
let status = match fut.as_mut().poll(cx) {
Poll::Ready(Ok(ret)) => ret,
Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
Poll::Pending => continue,
};
if status.error {
poll.revents |= PE::HUP;
events += 1;
}
if status.read && poll.events.contains(PE::IN) {
poll.revents |= PE::IN;
events += 1;
}
if status.write && poll.events.contains(PE::OUT) {
poll.revents |= PE::OUT;
events += 1;
}
} else {
poll.revents |= PE::ERR;
events += 1;
}
if status.read && poll.events.contains(PE::IN) {
poll.revents |= PE::IN;
events += 1;
}
if status.write && poll.events.contains(PE::OUT) {
poll.revents |= PE::OUT;
events += 1;
}
} else {
poll.revents |= PE::ERR;
events += 1;
}
}
drop(proc);
drop(proc);
// some event happens, so evoke the process
if events > 0 {
return Some(Ok(events));
}
// some event happens, so evoke the process
if events > 0 {
return Poll::Ready(Ok(events));
}
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 Poll::Pending;
}
return None;
})
}
let future = PollFuture {
polls,
syscall: self,
};
future.await
}
pub fn sys_pselect6(

View File

@ -27,6 +27,7 @@ pub use self::proc::*;
#[cfg(target_arch = "x86_64")]
pub use self::signal::*;
pub use self::time::*;
pub use self::user::*;
mod custom;
mod fs;
@ -39,6 +40,7 @@ mod proc;
#[cfg(target_arch = "x86_64")]
mod signal;
mod time;
mod user;
use crate::signal::{Signal, SignalAction, SignalFrame, SignalStack, SignalUserContext, Sigset};
#[cfg(feature = "profile")]
@ -97,7 +99,7 @@ impl Syscall<'_> {
let cid = cpu::id();
let pid = self.process().pid.clone();
//let tid = thread::current().id();
let tid = 0;
let tid: usize = 0;
//if !pid.is_init() {
// we trust pid 0 process
debug!("{}:{}:{} syscall id {} begin", cid, pid, tid, id);
@ -190,7 +192,12 @@ impl Syscall<'_> {
args[5] as *const u32,
),
SYS_PPOLL => {
self.sys_ppoll(args[0] as *mut PollFd, args[1], args[2] as *const TimeSpec)
self.sys_ppoll(
UserInOutPtr::from(args[0]),
args[1],
UserInPtr::from(args[2]),
)
.await
} // ignore sigmask
SYS_EPOLL_CREATE1 => self.sys_epoll_create1(args[0]),
SYS_EPOLL_CTL => {
@ -402,7 +409,7 @@ impl Syscall<'_> {
_ => {
let ret = match () {
#[cfg(target_arch = "x86_64")]
() => self.x86_64_syscall(id, args),
() => self.x86_64_syscall(id, args).await,
#[cfg(target_arch = "mips")]
() => self.mips_syscall(id, args),
#[cfg(all(not(target_arch = "x86_64"), not(target_arch = "mips")))]
@ -499,12 +506,15 @@ impl Syscall<'_> {
}
#[cfg(target_arch = "x86_64")]
fn x86_64_syscall(&mut self, id: usize, args: [usize; 6]) -> Option<SysResult> {
async fn x86_64_syscall(&mut self, id: usize, args: [usize; 6]) -> Option<SysResult> {
let ret = match id {
SYS_OPEN => self.sys_open(args[0] as *const u8, args[1], args[2]),
SYS_STAT => self.sys_stat(args[0] as *const u8, args[1] as *mut Stat),
SYS_LSTAT => self.sys_lstat(args[0] as *const u8, args[1] as *mut Stat),
SYS_POLL => self.sys_poll(args[0] as *mut PollFd, args[1], args[2]),
SYS_POLL => {
self.sys_poll(UserInOutPtr::from(args[0]), args[1], args[2])
.await
}
SYS_ACCESS => self.sys_access(args[0] as *const u8, args[1]),
SYS_PIPE => self.sys_pipe(args[0] as *mut u32),
SYS_SELECT => self.sys_select(

184
kernel/src/syscall/user.rs Normal file
View File

@ -0,0 +1,184 @@
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt::{Debug, Formatter};
use core::marker::PhantomData;
#[repr(C)]
pub struct UserPtr<T, P: Policy> {
ptr: *mut T,
mark: PhantomData<P>,
}
pub trait Policy {}
pub trait Read: Policy {}
pub trait Write: Policy {}
pub enum In {}
pub enum Out {}
pub enum InOut {}
impl Policy for In {}
impl Policy for Out {}
impl Policy for InOut {}
impl Read for In {}
impl Write for Out {}
impl Read for InOut {}
impl Write for InOut {}
pub type UserInPtr<T> = UserPtr<T, In>;
pub type UserOutPtr<T> = UserPtr<T, Out>;
pub type UserInOutPtr<T> = UserPtr<T, InOut>;
type Result<T> = core::result::Result<T, Error>;
/// The error type which is returned from user pointer.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Error {
InvalidUtf8,
InvalidPointer,
}
impl<T, P: Policy> Debug for UserPtr<T, P> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.ptr)
}
}
// FIXME: this is a workaround for `clear_child_tid`.
unsafe impl<T, P: Policy> Send for UserPtr<T, P> {}
unsafe impl<T, P: Policy> Sync for UserPtr<T, P> {}
impl<T, P: Policy> From<usize> for UserPtr<T, P> {
fn from(x: usize) -> Self {
UserPtr {
ptr: x as _,
mark: PhantomData,
}
}
}
impl<T, P: Policy> UserPtr<T, P> {
pub fn is_null(&self) -> bool {
self.ptr.is_null()
}
pub fn add(&self, count: usize) -> Self {
UserPtr {
ptr: unsafe { self.ptr.add(count) },
mark: PhantomData,
}
}
pub fn as_ptr(&self) -> *mut T {
self.ptr
}
pub fn check(&self) -> Result<()> {
if self.ptr.is_null() {
return Err(Error::InvalidPointer);
}
Ok(())
}
}
impl<T, P: Read> UserPtr<T, P> {
pub fn as_ref(&self) -> Result<&'static T> {
Ok(unsafe { &*self.ptr })
}
pub fn read(&self) -> Result<T> {
// TODO: check ptr and return err
self.check()?;
Ok(unsafe { self.ptr.read() })
}
pub fn read_if_not_null(&self) -> Result<Option<T>> {
if self.ptr.is_null() {
return Ok(None);
}
let value = self.read()?;
Ok(Some(value))
}
pub fn read_array(&self, len: usize) -> Result<Vec<T>> {
if len == 0 {
return Ok(Vec::default());
}
self.check()?;
let mut ret = Vec::<T>::with_capacity(len);
unsafe {
ret.set_len(len);
ret.as_mut_ptr().copy_from_nonoverlapping(self.ptr, len);
}
Ok(ret)
}
}
impl<P: Read> UserPtr<u8, P> {
pub fn read_string(&self, len: usize) -> Result<String> {
self.check()?;
let src = unsafe { core::slice::from_raw_parts(self.ptr, len) };
let s = core::str::from_utf8(src).map_err(|_| Error::InvalidUtf8)?;
Ok(String::from(s))
}
pub fn read_cstring(&self) -> Result<String> {
self.check()?;
let len = unsafe { (0usize..).find(|&i| *self.ptr.add(i) == 0).unwrap() };
self.read_string(len)
}
}
impl<P: Read> UserPtr<UserPtr<u8, P>, P> {
pub fn read_cstring_array(&self) -> Result<Vec<String>> {
self.check()?;
let len = unsafe {
(0usize..)
.find(|&i| self.ptr.add(i).read().is_null())
.unwrap()
};
self.read_array(len)?
.into_iter()
.map(|ptr| ptr.read_cstring())
.collect()
}
}
impl<T, P: Write> UserPtr<T, P> {
pub fn write(&mut self, value: T) -> Result<()> {
self.check()?;
unsafe {
self.ptr.write(value);
}
Ok(())
}
pub fn write_if_not_null(&mut self, value: T) -> Result<()> {
if self.ptr.is_null() {
return Ok(());
}
self.write(value)
}
pub fn write_array(&mut self, values: &[T]) -> Result<()> {
if values.is_empty() {
return Ok(());
}
self.check()?;
unsafe {
self.ptr
.copy_from_nonoverlapping(values.as_ptr(), values.len());
}
Ok(())
}
}
impl<P: Write> UserPtr<u8, P> {
pub fn write_cstring(&mut self, s: &str) -> Result<()> {
let bytes = s.as_bytes();
self.write_array(bytes)?;
unsafe {
self.ptr.add(bytes.len()).write(0);
}
Ok(())
}
}

View File

@ -23,7 +23,6 @@ lazy_static! {
}
pub fn timer() {
info!("timer");
let now = crate::arch::timer::timer_now();
NAIVE_TIMER.lock().expire(now);
}