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:
parent
bc845fa9ff
commit
5d05bccdd5
10
kernel/Cargo.lock
generated
10
kernel/Cargo.lock
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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
184
kernel/src/syscall/user.rs
Normal 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(())
|
||||
}
|
||||
}
|
@ -23,7 +23,6 @@ lazy_static! {
|
||||
}
|
||||
|
||||
pub fn timer() {
|
||||
info!("timer");
|
||||
let now = crate::arch::timer::timer_now();
|
||||
NAIVE_TIMER.lock().expire(now);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user