Refactor the implementation

This commit is contained in:
Jianfeng Jiang 2023-10-08 17:40:58 +08:00 committed by Tate, Hongliang Tian
parent 50761a5cc5
commit 0d6f6f001c
54 changed files with 433 additions and 326 deletions

7
Cargo.lock generated
View File

@ -692,6 +692,7 @@ dependencies = [
"pod",
"rsdp",
"spin 0.9.8",
"static_assertions",
"tdx-guest",
"trapframe",
"volatile",
@ -1265,6 +1266,12 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.10.0"

View File

@ -20,6 +20,7 @@ trapframe = { git = "https://github.com/sdww0/trapframe-rs", rev = "e886763" }
inherit-methods-macro = { git = "https://github.com/jinzhao-dev/inherit-methods-macro", rev = "98f7e3e" }
tdx-guest = { path = "../libs/tdx-guest", optional = true }
bitvec = { version = "1.0", default-features = false, features = ["alloc"] }
static_assertions = "1.1.0"
[target.x86_64-custom.dependencies]
x86_64 = "0.14.2"

View File

@ -36,22 +36,28 @@ pub fn init() {
fn timer_callback(trap_frame: &TrapFrame) {
let current_ticks = TICK.fetch_add(1, Ordering::SeqCst);
let mut timeout_list = TIMEOUT_LIST.get().unwrap().lock();
let mut callbacks: Vec<Arc<TimerCallback>> = Vec::new();
while let Some(t) = timeout_list.peek() {
if t.is_cancelled() {
// Just ignore the cancelled callback
timeout_list.pop();
} else if t.expire_ticks <= current_ticks && t.is_enable() {
callbacks.push(timeout_list.pop().unwrap());
} else {
break;
let callbacks = {
let mut callbacks = Vec::new();
let mut timeout_list = TIMEOUT_LIST.get().unwrap().lock();
while let Some(t) = timeout_list.peek() {
if t.is_cancelled() {
// Just ignore the cancelled callback
timeout_list.pop();
} else if t.expire_ticks <= current_ticks {
callbacks.push(timeout_list.pop().unwrap());
} else {
break;
}
}
}
drop(timeout_list);
callbacks
};
for callback in callbacks {
callback.callback.call((&callback,));
(callback.callback)(&callback);
}
if APIC_TIMER_CALLBACK.is_completed() {
APIC_TIMER_CALLBACK.get().unwrap().call(());
}
@ -63,7 +69,6 @@ pub struct TimerCallback {
expire_ticks: u64,
data: Arc<dyn Any + Send + Sync>,
callback: Box<dyn Fn(&TimerCallback) + Send + Sync>,
enable: AtomicBool,
is_cancelled: AtomicBool,
}
@ -77,7 +82,6 @@ impl TimerCallback {
expire_ticks: timeout_ticks,
data,
callback,
enable: AtomicBool::new(true),
is_cancelled: AtomicBool::new(false),
}
}
@ -86,20 +90,6 @@ impl TimerCallback {
&self.data
}
/// disable this timeout
pub fn disable(&self) {
self.enable.store(false, Ordering::Release)
}
/// enable this timeout
pub fn enable(&self) {
self.enable.store(false, Ordering::Release)
}
pub fn is_enable(&self) -> bool {
self.enable.load(Ordering::Acquire)
}
/// Whether the set timeout is reached
pub fn is_expired(&self) -> bool {
let current_tick = TICK.load(Ordering::Acquire);

View File

@ -7,5 +7,4 @@ pub enum Error {
AccessDenied,
IoError,
NotEnoughResources,
TimeOut,
}

View File

@ -17,6 +17,8 @@
#![feature(let_chains)]
extern crate alloc;
#[macro_use]
extern crate static_assertions;
pub mod arch;
pub mod boot;

View File

@ -26,7 +26,7 @@ impl<T> Mutex<T> {
///
/// This method runs in a block way until the mutex can be acquired.
pub fn lock(&self) -> MutexGuard<T> {
self.queue.wait_until(|| self.try_lock(), None).unwrap()
self.queue.wait_until(|| self.try_lock())
}
/// Try Acquire the mutex immedidately.

View File

@ -35,12 +35,12 @@ impl<T> RwMutex<T> {
/// Acquire a read mutex, and if there is a writer, this thread will sleep in the wait queue.
pub fn read(&self) -> RwMutexReadGuard<T> {
self.queue.wait_until(|| self.try_read(), None).unwrap()
self.queue.wait_until(|| self.try_read())
}
/// Acquire a write mutex, and if there is another writer or other readers, this thread will sleep in the wait queue.
pub fn write(&self) -> RwMutexWriteGuard<T> {
self.queue.wait_until(|| self.try_write(), None).unwrap()
self.queue.wait_until(|| self.try_write())
}
/// Try acquire a read mutex and return immediately if it fails.

View File

@ -1,8 +1,6 @@
use super::SpinLock;
use crate::arch::timer::add_timeout_list;
use crate::config::TIMER_FREQ;
use crate::error::Error;
use crate::prelude::*;
use alloc::{collections::VecDeque, sync::Arc};
use bitflags::bitflags;
use core::sync::atomic::{AtomicBool, Ordering};
@ -37,15 +35,29 @@ impl WaitQueue {
///
/// By taking a condition closure, his wait-wakeup mechanism becomes
/// more efficient and robust.
///
/// The only error result is Error::TIMEOUT, which means the timeout is readched
/// and the condition returns false.
pub fn wait_until<F, R>(&self, mut cond: F, timeout: Option<&Duration>) -> Result<R>
pub fn wait_until<F, R>(&self, cond: F) -> R
where
F: FnMut() -> Option<R>,
{
self.do_wait(cond, None).unwrap()
}
/// Wait until some condition returns Some(_), or a given timeout is reached. If
/// the condition does not becomes Some(_) before the timeout is reached, the
/// function will return None.
pub fn wait_until_or_timeout<F, R>(&self, cond: F, timeout: &Duration) -> Option<R>
where
F: FnMut() -> Option<R>,
{
self.do_wait(cond, Some(timeout))
}
fn do_wait<F, R>(&self, mut cond: F, timeout: Option<&Duration>) -> Option<R>
where
F: FnMut() -> Option<R>,
{
if let Some(res) = cond() {
return Ok(res);
return Some(res);
}
let waiter = Arc::new(Waiter::new());
@ -53,12 +65,12 @@ impl WaitQueue {
let timer_callback = timeout.map(|timeout| {
let remaining_ticks = {
let ms_per_tick = 1000 / TIMER_FREQ;
// FIXME: We currently require 1000 to be a multiple of TIMER_FREQ, but
// this may not hold true in the future, because TIMER_FREQ can be greater
// than 1000. Then, the code need to be refactored.
debug_assert!(ms_per_tick * TIMER_FREQ == 1000);
const_assert!(1000 % TIMER_FREQ == 0);
let ms_per_tick = 1000 / TIMER_FREQ;
// The ticks should be equal to or greater than timeout
(timeout.as_millis() as u64 + ms_per_tick - 1) / ms_per_tick
@ -81,11 +93,11 @@ impl WaitQueue {
timer_callback.cancel();
}
return Ok(res);
return Some(res);
};
if let Some(ref timer_callback) = timer_callback && timer_callback.is_expired() {
return Err(Error::TimeOut);
return None;
}
waiter.wait();

View File

@ -60,7 +60,7 @@ impl Timer {
let mut lock = self.inner.lock_irq_disabled();
match &lock.timer_callback {
Some(callback) => {
callback.disable();
callback.cancel();
}
None => {}
}
@ -94,7 +94,7 @@ impl Timer {
pub fn clear(&self) {
let mut lock = self.inner.lock_irq_disabled();
if let Some(callback) = &lock.timer_callback {
callback.disable();
callback.cancel();
}
lock.timeout_tick = 0;
lock.start_tick = 0;

View File

@ -2,11 +2,13 @@ use alloc::format;
use ringbuf::{ring_buffer::RbBase, HeapRb, Rb};
use crate::device::tty::line_discipline::LineDiscipline;
use crate::events::IoEvents;
use crate::fs::device::{Device, DeviceId, DeviceType};
use crate::fs::file_handle::FileLike;
use crate::fs::fs_resolver::FsPath;
use crate::fs::utils::{AccessMode, Inode, InodeMode, IoEvents, IoctlCmd, Pollee, Poller};
use crate::fs::utils::{AccessMode, Inode, InodeMode, IoctlCmd};
use crate::prelude::*;
use crate::process::signal::{Pollee, Poller};
use crate::util::{read_val_from_user, write_val_to_user};
const PTS_DIR: &str = "/dev/pts";
@ -106,7 +108,7 @@ impl FileLike for PtyMaster {
if events.is_empty() {
drop(input);
// FIXME: deal with pty read timeout
poller.wait_interruptible(None)?;
poller.wait()?;
}
continue;
}

View File

@ -1,5 +1,6 @@
use crate::fs::utils::{IoEvents, Pollee, Poller};
use crate::events::IoEvents;
use crate::process::signal::constants::{SIGINT, SIGQUIT};
use crate::process::signal::{Pollee, Poller};
use crate::process::ProcessGroup;
use crate::thread::work_queue::work_item::WorkItem;
use crate::thread::work_queue::{submit_work_item, WorkPriority};
@ -253,7 +254,7 @@ impl LineDiscipline {
let revents = self.pollee.poll(IoEvents::IN, need_poller);
if revents.is_empty() {
// FIXME: deal with ldisc read timeout
poller.as_ref().unwrap().wait_interruptible(None)?;
poller.as_ref().unwrap().wait()?;
}
}
}

View File

@ -3,8 +3,10 @@ use spin::Once;
use self::driver::TtyDriver;
use self::line_discipline::LineDiscipline;
use super::*;
use crate::fs::utils::{IoEvents, IoctlCmd, Poller};
use crate::events::IoEvents;
use crate::fs::utils::IoctlCmd;
use crate::prelude::*;
use crate::process::signal::Poller;
use crate::process::{process_table, ProcessGroup};
use crate::util::{read_val_from_user, write_val_to_user};

View File

@ -187,7 +187,6 @@ impl From<jinux_frame::Error> for Error {
jinux_frame::Error::IoError => Error::new(Errno::EIO),
jinux_frame::Error::NotEnoughResources => Error::new(Errno::EBUSY),
jinux_frame::Error::PageFault => Error::new(Errno::EFAULT),
jinux_frame::Error::TimeOut => Error::new(Errno::ETIME),
}
}
}

View File

@ -1,4 +1,4 @@
use crate::events::{Events, EventsFilter};
use super::{Events, EventsFilter};
crate::bitflags! {
pub struct IoEvents: u32 {

View File

@ -1,8 +1,10 @@
#[allow(clippy::module_inception)]
mod events;
mod io_events;
mod observer;
mod subject;
pub use self::events::{Events, EventsFilter};
pub use self::observer::Observer;
pub use self::subject::Subject;
pub use io_events::IoEvents;

View File

@ -1,7 +1,9 @@
use crate::events::IoEvents;
use crate::fs::fs_resolver::{FsPath, FsResolver};
use crate::fs::utils::Dentry;
use crate::fs::utils::{InodeMode, InodeType, IoEvents, IoctlCmd, Poller};
use crate::fs::utils::{InodeMode, InodeType, IoctlCmd};
use crate::prelude::*;
use crate::process::signal::Poller;
/// The abstract of device
pub trait Device: Sync + Send {

View File

@ -1,4 +1,7 @@
use crate::{fs::file_handle::FileLike, prelude::*};
use crate::events::IoEvents;
use crate::fs::file_handle::FileLike;
use crate::prelude::*;
use crate::process::signal::Poller;
use super::*;

View File

@ -1,7 +1,7 @@
use crate::fs::device::{Device, DeviceId, DeviceType};
use crate::fs::utils::{
DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoEvents, IoctlCmd, Metadata,
Poller, SuperBlock, NAME_MAX,
DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata,
SuperBlock, NAME_MAX,
};
use crate::prelude::*;

View File

@ -1,4 +1,6 @@
use crate::events::IoEvents;
use crate::prelude::*;
use crate::process::signal::Poller;
use super::*;

View File

@ -1,7 +1,8 @@
use crate::events::Observer;
use crate::events::{IoEvents, Observer};
use crate::fs::file_handle::FileLike;
use crate::fs::file_table::{FdEvents, FileDescripter};
use crate::fs::utils::{IoEvents, IoctlCmd, Pollee, Poller};
use crate::fs::utils::IoctlCmd;
use crate::process::signal::{Pollee, Poller};
use core::sync::atomic::{AtomicBool, Ordering};
use core::time::Duration;
@ -191,7 +192,11 @@ impl EpollFile {
}
}
poller.as_ref().unwrap().wait_interruptible(timeout)?;
if let Some(timeout) = timeout {
poller.as_ref().unwrap().wait_timeout(timeout)?;
} else {
poller.as_ref().unwrap().wait()?;
}
}
}

View File

@ -1,5 +1,5 @@
use super::file_table::FileDescripter;
use super::utils::IoEvents;
use crate::events::IoEvents;
use crate::prelude::*;
mod epoll_file;

View File

@ -1,9 +1,10 @@
//! Opend File Handle
use crate::events::Observer;
use crate::fs::utils::{AccessMode, IoEvents, IoctlCmd, Metadata, Poller, SeekFrom, StatusFlags};
use crate::events::{IoEvents, Observer};
use crate::fs::utils::{AccessMode, IoctlCmd, Metadata, SeekFrom, StatusFlags};
use crate::net::socket::Socket;
use crate::prelude::*;
use crate::process::signal::Poller;
use core::any::Any;

View File

@ -1,4 +1,6 @@
use crate::events::IoEvents;
use crate::prelude::*;
use crate::process::signal::Poller;
use jinux_rights::{Rights, TRights};
use super::*;

View File

@ -7,8 +7,7 @@ use core::sync::atomic::{AtomicU32, Ordering};
use crate::fs::file_handle::FileLike;
use crate::fs::utils::{
AccessMode, Dentry, DirentVisitor, InodeType, IoEvents, IoctlCmd, Metadata, Poller, SeekFrom,
StatusFlags,
AccessMode, Dentry, DirentVisitor, InodeType, IoctlCmd, Metadata, SeekFrom, StatusFlags,
};
use crate::prelude::*;
use jinux_rights::Rights;

View File

@ -1,10 +1,9 @@
use crate::events::Observer;
use crate::events::{IoEvents, Observer};
use crate::prelude::*;
use crate::process::signal::Poller;
use super::file_handle::FileLike;
use super::utils::{
AccessMode, Consumer, InodeMode, InodeType, IoEvents, Metadata, Poller, Producer, StatusFlags,
};
use super::utils::{AccessMode, Consumer, InodeMode, InodeType, Metadata, Producer, StatusFlags};
pub struct PipeReader {
consumer: Consumer<u8>,

View File

@ -1,4 +1,6 @@
use crate::events::IoEvents;
use crate::prelude::*;
use crate::process::signal::Poller;
use alloc::str;
use alloc::string::String;
use core::sync::atomic::{AtomicUsize, Ordering};
@ -10,8 +12,8 @@ use jinux_util::slot_vec::SlotVec;
use super::*;
use crate::fs::device::Device;
use crate::fs::utils::{
DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoEvents, IoctlCmd, Metadata,
Poller, SuperBlock, NAME_MAX,
DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata,
SuperBlock, NAME_MAX,
};
/// A volatile file system whose data and metadata exists only in memory.

View File

@ -2,11 +2,13 @@ use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use jinux_rights_proc::require;
use ringbuf::{HeapConsumer as HeapRbConsumer, HeapProducer as HeapRbProducer, HeapRb};
use crate::events::IoEvents;
use crate::events::Observer;
use crate::prelude::*;
use crate::process::signal::{Pollee, Poller};
use jinux_rights::{Read, ReadOp, TRights, Write, WriteOp};
use super::{IoEvents, Pollee, Poller, StatusFlags};
use super::StatusFlags;
/// A unidirectional communication channel, intended to implement IPC, e.g., pipe,
/// unix domain sockets, etc.
@ -153,7 +155,7 @@ impl<T: Copy> Producer<T> {
let events = self.poll(mask, Some(&poller));
if events.is_empty() {
// FIXME: should channel deal with timeout?
poller.wait_interruptible(None)?;
poller.wait()?;
}
}
}
@ -242,7 +244,7 @@ impl<T: Copy> Consumer<T> {
let events = self.poll(mask, Some(&poller));
if events.is_empty() {
// FIXME: should channel have timeout?
poller.wait_interruptible(None)?;
poller.wait()?;
}
}
}

View File

@ -5,9 +5,11 @@ use core::any::Any;
use core::time::Duration;
use jinux_frame::vm::VmFrame;
use super::{DirentVisitor, FileSystem, IoEvents, IoctlCmd, Poller, SuperBlock};
use super::{DirentVisitor, FileSystem, IoctlCmd, SuperBlock};
use crate::events::IoEvents;
use crate::fs::device::{Device, DeviceType};
use crate::prelude::*;
use crate::process::signal::Poller;
#[repr(u32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]

View File

@ -9,11 +9,9 @@ pub use direntry_vec::DirEntryVecExt;
pub use file_creation_mask::FileCreationMask;
pub use fs::{FileSystem, FsFlags, SuperBlock};
pub use inode::{Inode, InodeMode, InodeType, Metadata};
pub use io_events::IoEvents;
pub use ioctl::IoctlCmd;
pub use mount::MountNode;
pub use page_cache::PageCache;
pub use poll::{Pollee, Poller};
pub use status_flags::StatusFlags;
pub use vnode::{Vnode, VnodeWriter};
@ -26,11 +24,9 @@ mod direntry_vec;
mod file_creation_mask;
mod fs;
mod inode;
mod io_events;
mod ioctl;
mod mount;
mod page_cache;
mod poll;
mod status_flags;
mod vnode;

View File

@ -1,9 +1,10 @@
use super::{
DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoEvents, IoctlCmd, Metadata,
PageCache, Poller,
DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata, PageCache,
};
use crate::events::IoEvents;
use crate::fs::device::Device;
use crate::prelude::*;
use crate::process::signal::Poller;
use crate::vm::vmo::Vmo;
use alloc::string::String;

View File

@ -1,7 +1,6 @@
use crate::{
fs::utils::{IoEvents, Pollee, Poller},
prelude::*,
};
use crate::events::IoEvents;
use crate::prelude::*;
use crate::process::signal::{Pollee, Poller};
use super::Iface;
use super::{IpAddress, IpEndpoint};

View File

@ -1,13 +1,12 @@
use core::sync::atomic::{AtomicBool, Ordering};
use crate::events::IoEvents;
use crate::fs::utils::StatusFlags;
use crate::net::iface::IpEndpoint;
use crate::process::signal::Poller;
use crate::{
fs::{
file_handle::FileLike,
utils::{IoEvents, Poller},
},
fs::file_handle::FileLike,
net::{
iface::{AnyBoundSocket, AnyUnboundSocket, RawUdpSocket},
poll_ifaces,
@ -259,7 +258,7 @@ impl Socket for DatagramSocket {
return_errno_with_message!(Errno::EAGAIN, "try to receive again");
}
// FIXME: deal with recvfrom timeout
poller.wait_interruptible(None)?;
poller.wait()?;
}
}
}

View File

@ -1,8 +1,9 @@
use core::sync::atomic::{AtomicBool, Ordering};
use crate::events::IoEvents;
use crate::net::iface::IpEndpoint;
use crate::process::signal::Poller;
use crate::{
fs::utils::{IoEvents, Poller},
net::{
iface::{AnyBoundSocket, RawTcpSocket},
poll_ifaces,
@ -58,7 +59,7 @@ impl ConnectedStream {
return_errno_with_message!(Errno::EAGAIN, "try to recv again");
}
// FIXME: deal with receive timeout
poller.wait_interruptible(None)?;
poller.wait()?;
}
}
}

View File

@ -1,6 +1,6 @@
use core::sync::atomic::{AtomicBool, Ordering};
use crate::fs::utils::{IoEvents, Poller};
use crate::events::IoEvents;
use crate::net::iface::Iface;
use crate::net::iface::IpEndpoint;
use crate::net::iface::{AnyBoundSocket, AnyUnboundSocket};
@ -8,6 +8,7 @@ use crate::net::poll_ifaces;
use crate::net::socket::ip::always_some::AlwaysSome;
use crate::net::socket::ip::common::{bind_socket, get_ephemeral_endpoint};
use crate::prelude::*;
use crate::process::signal::Poller;
pub struct InitStream {
inner: RwLock<Inner>,
@ -152,7 +153,7 @@ impl InitStream {
return_errno_with_message!(Errno::EAGAIN, "try connect again");
} else {
// FIXME: deal with connecting timeout
poller.wait_interruptible(None)?;
poller.wait()?;
}
}
}

View File

@ -1,9 +1,10 @@
use core::sync::atomic::{AtomicBool, Ordering};
use crate::events::IoEvents;
use crate::net::iface::{AnyUnboundSocket, BindPortConfig, IpEndpoint};
use crate::fs::utils::{IoEvents, Poller};
use crate::net::iface::{AnyBoundSocket, RawTcpSocket};
use crate::process::signal::Poller;
use crate::{net::poll_ifaces, prelude::*};
use super::connected::ConnectedStream;
@ -46,7 +47,7 @@ impl ListenStream {
return_errno_with_message!(Errno::EAGAIN, "try accept again");
}
// FIXME: deal with accept timeout
poller.wait_interruptible(None)?;
poller.wait()?;
}
continue;
};

View File

@ -1,7 +1,5 @@
use crate::fs::{
file_handle::FileLike,
utils::{IoEvents, Poller, StatusFlags},
};
use crate::events::IoEvents;
use crate::fs::{file_handle::FileLike, utils::StatusFlags};
use crate::net::socket::{
util::{
send_recv_flags::SendRecvFlags, shutdown_cmd::SockShutdownCmd,
@ -10,6 +8,7 @@ use crate::net::socket::{
Socket,
};
use crate::prelude::*;
use crate::process::signal::Poller;
use self::{connected::ConnectedStream, init::InitStream, listen::ListenStream};

View File

@ -1,7 +1,8 @@
use super::endpoint::Endpoint;
use crate::fs::utils::{IoEvents, Poller};
use crate::events::IoEvents;
use crate::net::socket::{unix::addr::UnixSocketAddrBound, SockShutdownCmd};
use crate::prelude::*;
use crate::process::signal::Poller;
pub(super) struct Connected {
local_endpoint: Arc<Endpoint>,

View File

@ -1,5 +1,7 @@
use crate::events::IoEvents;
use crate::process::signal::Poller;
use crate::{
fs::utils::{Channel, Consumer, IoEvents, Poller, Producer, StatusFlags},
fs::utils::{Channel, Consumer, Producer, StatusFlags},
net::socket::{unix::addr::UnixSocketAddrBound, SockShutdownCmd},
prelude::*,
};

View File

@ -1,9 +1,11 @@
use core::sync::atomic::{AtomicBool, Ordering};
use crate::events::IoEvents;
use crate::fs::fs_resolver::{split_path, FsPath};
use crate::fs::utils::{Dentry, InodeMode, InodeType, IoEvents, Pollee, Poller};
use crate::fs::utils::{Dentry, InodeMode, InodeType};
use crate::net::socket::unix::addr::{UnixSocketAddr, UnixSocketAddrBound};
use crate::prelude::*;
use crate::process::signal::{Pollee, Poller};
use super::connected::Connected;
use super::endpoint::Endpoint;

View File

@ -1,9 +1,11 @@
use super::{connected::Connected, endpoint::Endpoint, UnixStreamSocket};
use crate::events::IoEvents;
use crate::fs::file_handle::FileLike;
use crate::fs::utils::{Dentry, Inode, IoEvents, Pollee, Poller};
use crate::fs::utils::{Dentry, Inode};
use crate::net::socket::unix::addr::{UnixSocketAddr, UnixSocketAddrBound};
use crate::net::socket::SocketAddr;
use crate::prelude::*;
use crate::process::signal::{Pollee, Poller};
use core::sync::atomic::{AtomicBool, Ordering};
use keyable_arc::KeyableWeak;
@ -133,7 +135,7 @@ impl BacklogTable {
// FIXME: deal with accept timeout
if events.is_empty() {
poller.wait_interruptible(None)?;
poller.wait()?;
}
}
}

View File

@ -1,12 +1,14 @@
use crate::events::IoEvents;
use crate::fs::file_handle::FileLike;
use crate::fs::fs_resolver::FsPath;
use crate::fs::utils::{Dentry, InodeType, IoEvents, Poller, StatusFlags};
use crate::fs::utils::{Dentry, InodeType, StatusFlags};
use crate::net::socket::unix::addr::UnixSocketAddrBound;
use crate::net::socket::unix::UnixSocketAddr;
use crate::net::socket::util::send_recv_flags::SendRecvFlags;
use crate::net::socket::util::sockaddr::SocketAddr;
use crate::net::socket::{SockShutdownCmd, Socket};
use crate::prelude::*;
use crate::process::signal::Poller;
use super::connected::Connected;
use super::endpoint::Endpoint;

View File

@ -48,7 +48,7 @@ pub fn do_exit_group(term_status: TermStatus) {
// Notify parent
let signal = Box::new(KernelSignal::new(SIGCHLD));
parent.enqueue_signal(signal);
parent.waiting_children().wake_all();
parent.children_pauser().resume_all();
}
}

View File

@ -75,7 +75,7 @@ impl PosixThread {
}
pub fn has_pending_signal(&self) -> bool {
self.sig_queues.lock().is_empty()
!self.sig_queues.lock().is_empty()
}
pub fn enqueue_signal(&self, signal: Box<dyn Signal>) {

View File

@ -5,11 +5,12 @@ use super::process_group::ProcessGroup;
use super::process_vm::user_heap::UserHeap;
use super::process_vm::ProcessVm;
use super::rlimit::ResourceLimits;
use super::signal::constants::SIGCHLD;
use super::signal::sig_disposition::SigDispositions;
use super::signal::sig_mask::SigMask;
use super::signal::sig_queues::SigQueues;
use super::signal::signals::Signal;
use super::signal::{SigEvents, SigEventsFilter};
use super::signal::{Pauser, SigEvents, SigEventsFilter};
use super::status::ProcessStatus;
use super::{process_table, TermStatus};
use crate::device::tty::get_n_tty;
@ -20,7 +21,6 @@ use crate::fs::utils::FileCreationMask;
use crate::prelude::*;
use crate::thread::{allocate_tid, Thread};
use crate::vm::vmar::Vmar;
use jinux_frame::sync::WaitQueue;
use jinux_rights::Full;
pub use builder::ProcessBuilder;
@ -35,8 +35,8 @@ pub struct Process {
pid: Pid,
process_vm: ProcessVm,
/// wait for child status changed
waiting_children: WaitQueue,
/// Wait for child status changed
children_pauser: Arc<Pauser>,
// Mutable Part
/// The executable path.
@ -82,12 +82,20 @@ impl Process {
sig_dispositions: Arc<Mutex<SigDispositions>>,
resource_limits: ResourceLimits,
) -> Self {
let children_pauser = {
let mut sigset = SigMask::new_full();
// SIGCHID does not interrupt pauser. Child process will
// resume paused parent when doing exit.
sigset.remove_signal(SIGCHLD);
Pauser::new_with_sigset(sigset)
};
Self {
pid,
threads: Mutex::new(threads),
executable_path: RwLock::new(executable_path),
process_vm,
waiting_children: WaitQueue::new(),
children_pauser,
status: Mutex::new(ProcessStatus::Uninit),
parent: Mutex::new(parent),
children: Mutex::new(BTreeMap::new()),
@ -190,8 +198,8 @@ impl Process {
&self.children
}
pub fn waiting_children(&self) -> &WaitQueue {
&self.waiting_children
pub fn children_pauser(&self) -> &Arc<Pauser> {
&self.children_pauser
}
// *********** Process group ***********
@ -252,7 +260,7 @@ impl Process {
}
pub fn has_pending_signal(&self) -> bool {
self.sig_queues.lock().is_empty()
!self.sig_queues.lock().is_empty()
}
pub fn enqueue_signal(&self, signal: Box<dyn Signal>) {

View File

@ -1,11 +1,5 @@
use core::sync::atomic::{AtomicBool, Ordering};
use core::time::Duration;
use jinux_frame::sync::WaitQueue;
use crate::events::{Events, EventsFilter, Observer};
use crate::events::{Events, EventsFilter};
use crate::prelude::*;
use crate::process::posix_thread::PosixThreadExt;
use super::sig_mask::SigMask;
use super::sig_num::SigNum;
@ -35,101 +29,3 @@ impl EventsFilter<SigEvents> for SigEventsFilter {
self.0.contains(event.0)
}
}
pub struct SigQueueObserver {
wait_queue: WaitQueue,
mask: SigMask,
is_interrupted: AtomicBool,
}
impl SigQueueObserver {
pub fn new(mask: SigMask) -> Arc<Self> {
let wait_queue = WaitQueue::new();
Arc::new(Self {
wait_queue,
mask,
is_interrupted: AtomicBool::new(false),
})
}
/// Wait until cond() returns Some(_).
///
/// If some signal is caught before cond() returns Some(_), it will returns EINTR.
pub fn wait_until_interruptible<F, R>(
self: &Arc<Self>,
mut cond: F,
timeout: Option<&Duration>,
) -> Result<R>
where
F: FnMut() -> Option<R>,
{
self.is_interrupted.store(false, Ordering::Release);
// Register observers on sigqueues
let observer = Arc::downgrade(self) as Weak<dyn Observer<SigEvents>>;
let filter = SigEventsFilter::new(self.mask);
let current = current!();
current.register_sigqueue_observer(observer.clone(), filter);
let current_thread = current_thread!();
let posix_thread = current_thread.as_posix_thread().unwrap();
posix_thread.register_sigqueue_observer(observer.clone(), filter);
// Some signal may come before we register observer, so we do another check here.
if posix_thread.has_pending_signal() || current.has_pending_signal() {
self.is_interrupted.store(true, Ordering::Release);
}
enum Res<R> {
Ok(R),
Interrupted,
}
let res = self.wait_queue.wait_until(
|| {
if let Some(res) = cond() {
return Some(Res::Ok(res));
}
if self.is_interrupted.load(Ordering::Acquire) {
return Some(Res::Interrupted);
}
None
},
timeout,
)?;
current.unregiser_sigqueue_observer(&observer);
posix_thread.unregiser_sigqueue_observer(&observer);
match res {
Res::Ok(r) => Ok(r),
Res::Interrupted => return_errno_with_message!(Errno::EINTR, "interrupted by signal"),
}
}
pub fn wait_until_uninterruptible<F, R>(&self, cond: F, timeout: Option<&Duration>) -> Result<R>
where
F: FnMut() -> Option<R>,
{
Ok(self.wait_queue.wait_until(cond, timeout)?)
}
pub fn wake_all(&self) {
self.wait_queue.wake_all();
}
pub fn wake_one(&self) {
self.wait_queue.wake_one();
}
}
impl Observer<SigEvents> for SigQueueObserver {
fn on_events(&self, events: &SigEvents) {
self.is_interrupted.store(true, Ordering::Release);
self.wait_queue.wake_all();
}
}

View File

@ -1,6 +1,8 @@
pub mod c_types;
pub mod constants;
mod events;
mod pauser;
mod poll;
pub mod sig_action;
pub mod sig_disposition;
pub mod sig_mask;
@ -8,7 +10,9 @@ pub mod sig_num;
pub mod sig_queues;
pub mod signals;
pub use events::{SigEvents, SigEventsFilter, SigQueueObserver};
pub use events::{SigEvents, SigEventsFilter};
pub use pauser::Pauser;
pub use poll::{Pollee, Poller};
use core::mem;

View File

@ -0,0 +1,176 @@
use core::sync::atomic::{AtomicBool, Ordering};
use core::time::Duration;
use jinux_frame::sync::WaitQueue;
use crate::events::Observer;
use crate::prelude::*;
use crate::process::posix_thread::PosixThreadExt;
use super::sig_mask::SigMask;
use super::{SigEvents, SigEventsFilter};
/// A `Pauser` allows pausing the execution of the current thread until certain conditions are reached.
///
/// Behind the scene, `Pauser` is implemented with `Waiter` and `WaiterQueue`.
/// But unlike its `Waiter` relatives, `Pauser` is aware of POSIX signals:
/// if a thread paused by a `Pauser` receives a signal, then the thread will resume its execution.
///
/// Another key difference is that `Pauser` combines the two roles of `Waiter` and `WaiterQueue`
/// into one. Both putting the current thread to sleep and waking it up can be done through the
/// same `Pauser` object, using its `pause`- and `resume`-family methods.
///
/// # Example
///
/// Here is how the current thread can be put to sleep with a `Pauser`.
///
/// ```rust
/// let pauser = Pauser::new(SigMask::new_full());
/// // Pause the execution of the current thread until a user-given condition is met
/// // or the current thread is interrupted by a signal.
/// let res = pauser.pause_until(|| {
/// if cond() {
/// Some(())
/// } else {
/// None
/// }
/// });
/// match res {
/// Ok(_) => {
/// // The user-given condition is met...
/// }
/// Err(EINTR) => {
/// // A signal is received...
/// }
/// _ => unreachable!()
/// }
/// ```
///
/// Let's assume that another thread has access to the same object of `Arc<Pauser>`.
/// Then, this second thread can resume the execution of the first thread
/// even when `cond()` does not return `true`.
///
/// ```
/// pauser.resume_all();
/// ```
pub struct Pauser {
wait_queue: WaitQueue,
sigset: SigMask,
is_interrupted: AtomicBool,
}
impl Pauser {
/// Create a new `Pauser`. The `Pauser` can be interrupted by all signals.
pub fn new() -> Arc<Self> {
Self::new_with_sigset(SigMask::new_full())
}
/// Create a new `Pauser`, the `Pauser` can only be interrupted by signals
/// in `sigset`.
pub fn new_with_sigset(sigset: SigMask) -> Arc<Self> {
let wait_queue = WaitQueue::new();
Arc::new(Self {
wait_queue,
sigset,
is_interrupted: AtomicBool::new(false),
})
}
/// Pause the execution of current thread until the `cond` is met ( i.e., `cond()`
/// returns `Some(_)` ), or some signal is received by current thread or process.
///
/// If some signal is received before `cond` is met, this method will returns `Err(EINTR)`.
pub fn pause_until<F, R>(self: &Arc<Self>, cond: F) -> Result<R>
where
F: FnMut() -> Option<R>,
{
self.do_pause(cond, None)
}
/// Pause the execution of current thread until the `cond` is met ( i.e., `cond()` returns
/// `Some(_)` ), or some signal is received by current thread or process, or the given
/// `timeout` is expired.
///
/// If `timeout` is expired before the `cond` is met or some signal is received,
/// it will returns `Err(ETIME)`.
pub fn pause_until_or_timeout<F, R>(self: &Arc<Self>, cond: F, timeout: &Duration) -> Result<R>
where
F: FnMut() -> Option<R>,
{
self.do_pause(cond, Some(timeout))
}
fn do_pause<F, R>(self: &Arc<Self>, mut cond: F, timeout: Option<&Duration>) -> Result<R>
where
F: FnMut() -> Option<R>,
{
self.is_interrupted.store(false, Ordering::Release);
// Register observers on sigqueues
let observer = Arc::downgrade(self) as Weak<dyn Observer<SigEvents>>;
let filter = SigEventsFilter::new(self.sigset);
let current = current!();
current.register_sigqueue_observer(observer.clone(), filter);
let current_thread = current_thread!();
let posix_thread = current_thread.as_posix_thread().unwrap();
posix_thread.register_sigqueue_observer(observer.clone(), filter);
// Some signal may come before we register observer, so we do another check here.
if posix_thread.has_pending_signal() || current.has_pending_signal() {
self.is_interrupted.store(true, Ordering::Release);
}
enum Res<R> {
Ok(R),
Interrupted,
}
let cond = || {
if let Some(res) = cond() {
return Some(Res::Ok(res));
}
if self.is_interrupted.load(Ordering::Acquire) {
return Some(Res::Interrupted);
}
None
};
let res = if let Some(timeout) = timeout {
self.wait_queue
.wait_until_or_timeout(cond, timeout)
.ok_or_else(|| Error::with_message(Errno::ETIME, "timeout is reached"))?
} else {
self.wait_queue.wait_until(cond)
};
current.unregiser_sigqueue_observer(&observer);
posix_thread.unregiser_sigqueue_observer(&observer);
match res {
Res::Ok(r) => Ok(r),
Res::Interrupted => return_errno_with_message!(Errno::EINTR, "interrupted by signal"),
}
}
/// Resume all paused threads on this pauser.
pub fn resume_all(&self) {
self.wait_queue.wake_all();
}
/// Resume one paused thread on this pauser.
pub fn resume_one(&self) {
self.wait_queue.wake_one();
}
}
impl Observer<SigEvents> for Pauser {
fn on_events(&self, events: &SigEvents) {
self.is_interrupted.store(true, Ordering::Release);
self.wait_queue.wake_all();
}
}

View File

@ -1,8 +1,7 @@
use super::IoEvents;
use crate::events::IoEvents;
use crate::events::{Observer, Subject};
use crate::prelude::*;
use crate::process::signal::sig_mask::SigMask;
use crate::process::signal::SigQueueObserver;
use crate::process::signal::Pauser;
use core::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
use core::time::Duration;
@ -160,13 +159,15 @@ impl Poller {
/// Wait until there are any interesting events happen since last `wait`. The `wait`
/// can be interrupted by signal.
pub fn wait_interruptible(&self, timeout: Option<&Duration>) -> Result<()> {
self.inner.event_counter.read_interruptible(timeout)?;
pub fn wait(&self) -> Result<()> {
self.inner.event_counter.read(None)?;
Ok(())
}
pub fn wait_uninterruptible(&self, timeout: Option<&Duration>) -> Result<()> {
self.inner.event_counter.read_uninterruptible(timeout)?;
/// Wait until there are any interesting events happen since last `wait` or a given timeout
/// is expired. This method can be interrupted by signal.
pub fn wait_timeout(&self, timeout: &Duration) -> Result<()> {
self.inner.event_counter.read(Some(timeout))?;
Ok(())
}
@ -200,53 +201,38 @@ impl Drop for Poller {
/// A counter for wait and wakeup.
struct EventCounter {
counter: AtomicUsize,
observer: Arc<SigQueueObserver>,
pauser: Arc<Pauser>,
}
impl EventCounter {
pub fn new() -> Self {
let observer = {
// FIXME: choose the suitable mask
let mask = SigMask::new_full();
SigQueueObserver::new(mask)
};
let pauser = Pauser::new();
Self {
counter: AtomicUsize::new(0),
observer,
pauser,
}
}
pub fn read_interruptible(&self, timeout: Option<&Duration>) -> Result<usize> {
self.observer.wait_until_interruptible(
|| {
let val = self.counter.swap(0, Ordering::Relaxed);
if val > 0 {
Some(val)
} else {
None
}
},
timeout,
)
}
pub fn read(&self, timeout: Option<&Duration>) -> Result<usize> {
let cond = || {
let val = self.counter.swap(0, Ordering::Relaxed);
if val > 0 {
Some(val)
} else {
None
}
};
pub fn read_uninterruptible(&self, timeout: Option<&Duration>) -> Result<usize> {
self.observer.wait_until_uninterruptible(
|| {
let val = self.counter.swap(0, Ordering::Relaxed);
if val > 0 {
Some(val)
} else {
None
}
},
timeout,
)
if let Some(timeout) = timeout {
self.pauser.pause_until_or_timeout(cond, timeout)
} else {
self.pauser.pause_until(cond)
}
}
pub fn write(&self) {
self.counter.fetch_add(1, Ordering::Relaxed);
self.observer.wake_one();
self.pauser.resume_one();
}
}

View File

@ -26,51 +26,48 @@ pub fn wait_child_exit(
wait_options: WaitOptions,
) -> Result<(Pid, ExitCode)> {
let current = current!();
let (pid, exit_code) = current.waiting_children().wait_until(
|| {
let unwaited_children = current
.children()
.lock()
.values()
.filter(|child| match child_filter {
ProcessFilter::Any => true,
ProcessFilter::WithPid(pid) => child.pid() == pid,
ProcessFilter::WithPgid(pgid) => child.pgid() == pgid,
})
.cloned()
.collect::<Vec<_>>();
let (pid, exit_code) = current.children_pauser().pause_until(|| {
let unwaited_children = current
.children()
.lock()
.values()
.filter(|child| match child_filter {
ProcessFilter::Any => true,
ProcessFilter::WithPid(pid) => child.pid() == pid,
ProcessFilter::WithPgid(pgid) => child.pgid() == pgid,
})
.cloned()
.collect::<Vec<_>>();
if unwaited_children.is_empty() {
return Some(Err(Error::with_message(
Errno::ECHILD,
"the process has no child to wait",
)));
if unwaited_children.is_empty() {
return Some(Err(Error::with_message(
Errno::ECHILD,
"the process has no child to wait",
)));
}
// return immediately if we find a zombie child
let zombie_child = unwaited_children.iter().find(|child| child.is_zombie());
if let Some(zombie_child) = zombie_child {
let zombie_pid = zombie_child.pid();
let exit_code = zombie_child.exit_code().unwrap();
if wait_options.contains(WaitOptions::WNOWAIT) {
// does not reap child, directly return
return Some(Ok((zombie_pid, exit_code)));
} else {
let exit_code = reap_zombie_child(&current, zombie_pid);
return Some(Ok((zombie_pid, exit_code)));
}
}
// return immediately if we find a zombie child
let zombie_child = unwaited_children.iter().find(|child| child.is_zombie());
if wait_options.contains(WaitOptions::WNOHANG) {
return Some(Ok((0, 0)));
}
if let Some(zombie_child) = zombie_child {
let zombie_pid = zombie_child.pid();
let exit_code = zombie_child.exit_code().unwrap();
if wait_options.contains(WaitOptions::WNOWAIT) {
// does not reap child, directly return
return Some(Ok((zombie_pid, exit_code)));
} else {
let exit_code = reap_zombie_child(&current, zombie_pid);
return Some(Ok((zombie_pid, exit_code)));
}
}
if wait_options.contains(WaitOptions::WNOHANG) {
return Some(Ok((0, 0)));
}
// wait
None
},
None,
)??;
// wait
None
})??;
Ok((pid, exit_code as _))
}

View File

@ -4,8 +4,7 @@ use super::SyscallReturn;
use super::SYS_CLOCK_NANOSLEEP;
use crate::log_syscall_entry;
use crate::prelude::*;
use crate::process::signal::sig_mask::SigMask;
use crate::process::signal::SigQueueObserver;
use crate::process::signal::Pauser;
use crate::time::{clockid_t, now_as_duration, timespec_t, ClockID, TIMER_ABSTIME};
use crate::util::{read_val_from_user, write_val_to_user};
@ -40,14 +39,11 @@ pub fn sys_clock_nanosleep(
let start_time = now_as_duration(&clock_id)?;
let sigqueue_observer = {
// FIXME: sleeping thread can only be interrupted by signals that will call signal handler or terminate
// current process. i.e., the signals that should be ignored will not interrupt sleeping thread.
let sigmask = SigMask::new_full();
SigQueueObserver::new(sigmask)
};
// FIXME: sleeping thread can only be interrupted by signals that will call signal handler or terminate
// current process. i.e., the signals that should be ignored will not interrupt sleeping thread.
let pauser = Pauser::new();
let res = sigqueue_observer.wait_until_interruptible(|| None, Some(&duration));
let res = pauser.pause_until_or_timeout(|| None, &duration);
match res {
Err(e) if e.error() == Errno::ETIME => Ok(SyscallReturn::Return(0)),
Err(e) if e.error() == Errno::EINTR => {

View File

@ -1,8 +1,9 @@
use core::time::Duration;
use crate::events::IoEvents;
use crate::fs::epoll::{EpollCtl, EpollEvent, EpollFile, EpollFlags};
use crate::fs::file_table::FileDescripter;
use crate::fs::utils::{CreationFlags, IoEvents};
use crate::fs::utils::CreationFlags;
use crate::log_syscall_entry;
use crate::prelude::*;
use crate::util::{read_val_from_user, write_val_to_user};

View File

@ -1,21 +1,17 @@
use crate::log_syscall_entry;
use crate::prelude::*;
use crate::process::signal::sig_mask::SigMask;
use crate::process::signal::SigQueueObserver;
use crate::process::signal::Pauser;
use super::{SyscallReturn, SYS_PAUSE};
pub fn sys_pause() -> Result<SyscallReturn> {
log_syscall_entry!(SYS_PAUSE);
let sigqueue_observer = {
// FIXME: like sleep, paused thread can only be interrupted by signals that will call signal
// handler or terminate current process
let sigmask = SigMask::new_full();
SigQueueObserver::new(sigmask)
};
// FIXME: like sleep, paused thread can only be interrupted by signals that will call signal
// handler or terminate current process
let pauser = Pauser::new();
sigqueue_observer.wait_until_interruptible(|| None, None)?;
pauser.pause_until(|| None)?;
unreachable!("[Internal Error] pause should always return EINTR");
}

View File

@ -1,10 +1,11 @@
use core::cell::Cell;
use core::time::Duration;
use crate::events::IoEvents;
use crate::fs::file_table::FileDescripter;
use crate::fs::utils::{IoEvents, Poller};
use crate::log_syscall_entry;
use crate::prelude::*;
use crate::process::signal::Poller;
use crate::util::{read_val_from_user, write_val_to_user};
use super::SyscallReturn;
@ -91,7 +92,11 @@ pub fn do_poll(poll_fds: &[PollFd], timeout: Option<Duration>) -> Result<usize>
return Ok(0);
}
poller.wait_interruptible(timeout.as_ref())?;
if let Some(timeout) = timeout.as_ref() {
poller.wait_timeout(timeout)?;
} else {
poller.wait()?;
}
}
}

View File

@ -1,7 +1,7 @@
use core::time::Duration;
use crate::events::IoEvents;
use crate::fs::file_table::FileDescripter;
use crate::fs::utils::IoEvents;
use crate::log_syscall_entry;
use crate::prelude::*;
use crate::time::timeval_t;