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", "pod",
"rsdp", "rsdp",
"spin 0.9.8", "spin 0.9.8",
"static_assertions",
"tdx-guest", "tdx-guest",
"trapframe", "trapframe",
"volatile", "volatile",
@ -1265,6 +1266,12 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.10.0" 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" } inherit-methods-macro = { git = "https://github.com/jinzhao-dev/inherit-methods-macro", rev = "98f7e3e" }
tdx-guest = { path = "../libs/tdx-guest", optional = true } tdx-guest = { path = "../libs/tdx-guest", optional = true }
bitvec = { version = "1.0", default-features = false, features = ["alloc"] } bitvec = { version = "1.0", default-features = false, features = ["alloc"] }
static_assertions = "1.1.0"
[target.x86_64-custom.dependencies] [target.x86_64-custom.dependencies]
x86_64 = "0.14.2" x86_64 = "0.14.2"

View File

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

View File

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

View File

@ -17,6 +17,8 @@
#![feature(let_chains)] #![feature(let_chains)]
extern crate alloc; extern crate alloc;
#[macro_use]
extern crate static_assertions;
pub mod arch; pub mod arch;
pub mod boot; 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. /// This method runs in a block way until the mutex can be acquired.
pub fn lock(&self) -> MutexGuard<T> { 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. /// 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. /// Acquire a read mutex, and if there is a writer, this thread will sleep in the wait queue.
pub fn read(&self) -> RwMutexReadGuard<T> { 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. /// 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> { 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. /// Try acquire a read mutex and return immediately if it fails.

View File

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

View File

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

View File

@ -2,11 +2,13 @@ use alloc::format;
use ringbuf::{ring_buffer::RbBase, HeapRb, Rb}; use ringbuf::{ring_buffer::RbBase, HeapRb, Rb};
use crate::device::tty::line_discipline::LineDiscipline; use crate::device::tty::line_discipline::LineDiscipline;
use crate::events::IoEvents;
use crate::fs::device::{Device, DeviceId, DeviceType}; use crate::fs::device::{Device, DeviceId, DeviceType};
use crate::fs::file_handle::FileLike; use crate::fs::file_handle::FileLike;
use crate::fs::fs_resolver::FsPath; 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::prelude::*;
use crate::process::signal::{Pollee, Poller};
use crate::util::{read_val_from_user, write_val_to_user}; use crate::util::{read_val_from_user, write_val_to_user};
const PTS_DIR: &str = "/dev/pts"; const PTS_DIR: &str = "/dev/pts";
@ -106,7 +108,7 @@ impl FileLike for PtyMaster {
if events.is_empty() { if events.is_empty() {
drop(input); drop(input);
// FIXME: deal with pty read timeout // FIXME: deal with pty read timeout
poller.wait_interruptible(None)?; poller.wait()?;
} }
continue; 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::constants::{SIGINT, SIGQUIT};
use crate::process::signal::{Pollee, Poller};
use crate::process::ProcessGroup; use crate::process::ProcessGroup;
use crate::thread::work_queue::work_item::WorkItem; use crate::thread::work_queue::work_item::WorkItem;
use crate::thread::work_queue::{submit_work_item, WorkPriority}; use crate::thread::work_queue::{submit_work_item, WorkPriority};
@ -253,7 +254,7 @@ impl LineDiscipline {
let revents = self.pollee.poll(IoEvents::IN, need_poller); let revents = self.pollee.poll(IoEvents::IN, need_poller);
if revents.is_empty() { if revents.is_empty() {
// FIXME: deal with ldisc read timeout // 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::driver::TtyDriver;
use self::line_discipline::LineDiscipline; use self::line_discipline::LineDiscipline;
use super::*; use super::*;
use crate::fs::utils::{IoEvents, IoctlCmd, Poller}; use crate::events::IoEvents;
use crate::fs::utils::IoctlCmd;
use crate::prelude::*; use crate::prelude::*;
use crate::process::signal::Poller;
use crate::process::{process_table, ProcessGroup}; use crate::process::{process_table, ProcessGroup};
use crate::util::{read_val_from_user, write_val_to_user}; 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::IoError => Error::new(Errno::EIO),
jinux_frame::Error::NotEnoughResources => Error::new(Errno::EBUSY), jinux_frame::Error::NotEnoughResources => Error::new(Errno::EBUSY),
jinux_frame::Error::PageFault => Error::new(Errno::EFAULT), 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! { crate::bitflags! {
pub struct IoEvents: u32 { pub struct IoEvents: u32 {

View File

@ -1,8 +1,10 @@
#[allow(clippy::module_inception)] #[allow(clippy::module_inception)]
mod events; mod events;
mod io_events;
mod observer; mod observer;
mod subject; mod subject;
pub use self::events::{Events, EventsFilter}; pub use self::events::{Events, EventsFilter};
pub use self::observer::Observer; pub use self::observer::Observer;
pub use self::subject::Subject; 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::fs_resolver::{FsPath, FsResolver};
use crate::fs::utils::Dentry; 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::prelude::*;
use crate::process::signal::Poller;
/// The abstract of device /// The abstract of device
pub trait Device: Sync + Send { 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::*; use super::*;

View File

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

View File

@ -1,4 +1,6 @@
use crate::events::IoEvents;
use crate::prelude::*; use crate::prelude::*;
use crate::process::signal::Poller;
use super::*; 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_handle::FileLike;
use crate::fs::file_table::{FdEvents, FileDescripter}; 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::sync::atomic::{AtomicBool, Ordering};
use core::time::Duration; 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::file_table::FileDescripter;
use super::utils::IoEvents; use crate::events::IoEvents;
use crate::prelude::*; use crate::prelude::*;
mod epoll_file; mod epoll_file;

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,6 @@
use crate::events::IoEvents;
use crate::prelude::*; use crate::prelude::*;
use crate::process::signal::Poller;
use alloc::str; use alloc::str;
use alloc::string::String; use alloc::string::String;
use core::sync::atomic::{AtomicUsize, Ordering}; use core::sync::atomic::{AtomicUsize, Ordering};
@ -10,8 +12,8 @@ use jinux_util::slot_vec::SlotVec;
use super::*; use super::*;
use crate::fs::device::Device; use crate::fs::device::Device;
use crate::fs::utils::{ use crate::fs::utils::{
DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoEvents, IoctlCmd, Metadata, DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType, IoctlCmd, Metadata,
Poller, SuperBlock, NAME_MAX, SuperBlock, NAME_MAX,
}; };
/// A volatile file system whose data and metadata exists only in memory. /// 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 jinux_rights_proc::require;
use ringbuf::{HeapConsumer as HeapRbConsumer, HeapProducer as HeapRbProducer, HeapRb}; use ringbuf::{HeapConsumer as HeapRbConsumer, HeapProducer as HeapRbProducer, HeapRb};
use crate::events::IoEvents;
use crate::events::Observer; use crate::events::Observer;
use crate::prelude::*; use crate::prelude::*;
use crate::process::signal::{Pollee, Poller};
use jinux_rights::{Read, ReadOp, TRights, Write, WriteOp}; 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, /// A unidirectional communication channel, intended to implement IPC, e.g., pipe,
/// unix domain sockets, etc. /// unix domain sockets, etc.
@ -153,7 +155,7 @@ impl<T: Copy> Producer<T> {
let events = self.poll(mask, Some(&poller)); let events = self.poll(mask, Some(&poller));
if events.is_empty() { if events.is_empty() {
// FIXME: should channel deal with timeout? // 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)); let events = self.poll(mask, Some(&poller));
if events.is_empty() { if events.is_empty() {
// FIXME: should channel have timeout? // 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 core::time::Duration;
use jinux_frame::vm::VmFrame; 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::fs::device::{Device, DeviceType};
use crate::prelude::*; use crate::prelude::*;
use crate::process::signal::Poller;
#[repr(u32)] #[repr(u32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[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 file_creation_mask::FileCreationMask;
pub use fs::{FileSystem, FsFlags, SuperBlock}; pub use fs::{FileSystem, FsFlags, SuperBlock};
pub use inode::{Inode, InodeMode, InodeType, Metadata}; pub use inode::{Inode, InodeMode, InodeType, Metadata};
pub use io_events::IoEvents;
pub use ioctl::IoctlCmd; pub use ioctl::IoctlCmd;
pub use mount::MountNode; pub use mount::MountNode;
pub use page_cache::PageCache; pub use page_cache::PageCache;
pub use poll::{Pollee, Poller};
pub use status_flags::StatusFlags; pub use status_flags::StatusFlags;
pub use vnode::{Vnode, VnodeWriter}; pub use vnode::{Vnode, VnodeWriter};
@ -26,11 +24,9 @@ mod direntry_vec;
mod file_creation_mask; mod file_creation_mask;
mod fs; mod fs;
mod inode; mod inode;
mod io_events;
mod ioctl; mod ioctl;
mod mount; mod mount;
mod page_cache; mod page_cache;
mod poll;
mod status_flags; mod status_flags;
mod vnode; mod vnode;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,11 @@
use core::sync::atomic::{AtomicBool, Ordering}; use core::sync::atomic::{AtomicBool, Ordering};
use crate::events::IoEvents;
use crate::fs::fs_resolver::{split_path, FsPath}; 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::net::socket::unix::addr::{UnixSocketAddr, UnixSocketAddrBound};
use crate::prelude::*; use crate::prelude::*;
use crate::process::signal::{Pollee, Poller};
use super::connected::Connected; use super::connected::Connected;
use super::endpoint::Endpoint; use super::endpoint::Endpoint;

View File

@ -1,9 +1,11 @@
use super::{connected::Connected, endpoint::Endpoint, UnixStreamSocket}; use super::{connected::Connected, endpoint::Endpoint, UnixStreamSocket};
use crate::events::IoEvents;
use crate::fs::file_handle::FileLike; 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::unix::addr::{UnixSocketAddr, UnixSocketAddrBound};
use crate::net::socket::SocketAddr; use crate::net::socket::SocketAddr;
use crate::prelude::*; use crate::prelude::*;
use crate::process::signal::{Pollee, Poller};
use core::sync::atomic::{AtomicBool, Ordering}; use core::sync::atomic::{AtomicBool, Ordering};
use keyable_arc::KeyableWeak; use keyable_arc::KeyableWeak;
@ -133,7 +135,7 @@ impl BacklogTable {
// FIXME: deal with accept timeout // FIXME: deal with accept timeout
if events.is_empty() { 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::file_handle::FileLike;
use crate::fs::fs_resolver::FsPath; 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::addr::UnixSocketAddrBound;
use crate::net::socket::unix::UnixSocketAddr; use crate::net::socket::unix::UnixSocketAddr;
use crate::net::socket::util::send_recv_flags::SendRecvFlags; use crate::net::socket::util::send_recv_flags::SendRecvFlags;
use crate::net::socket::util::sockaddr::SocketAddr; use crate::net::socket::util::sockaddr::SocketAddr;
use crate::net::socket::{SockShutdownCmd, Socket}; use crate::net::socket::{SockShutdownCmd, Socket};
use crate::prelude::*; use crate::prelude::*;
use crate::process::signal::Poller;
use super::connected::Connected; use super::connected::Connected;
use super::endpoint::Endpoint; use super::endpoint::Endpoint;

View File

@ -48,7 +48,7 @@ pub fn do_exit_group(term_status: TermStatus) {
// Notify parent // Notify parent
let signal = Box::new(KernelSignal::new(SIGCHLD)); let signal = Box::new(KernelSignal::new(SIGCHLD));
parent.enqueue_signal(signal); 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 { 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>) { 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::user_heap::UserHeap;
use super::process_vm::ProcessVm; use super::process_vm::ProcessVm;
use super::rlimit::ResourceLimits; use super::rlimit::ResourceLimits;
use super::signal::constants::SIGCHLD;
use super::signal::sig_disposition::SigDispositions; use super::signal::sig_disposition::SigDispositions;
use super::signal::sig_mask::SigMask; use super::signal::sig_mask::SigMask;
use super::signal::sig_queues::SigQueues; use super::signal::sig_queues::SigQueues;
use super::signal::signals::Signal; use super::signal::signals::Signal;
use super::signal::{SigEvents, SigEventsFilter}; use super::signal::{Pauser, SigEvents, SigEventsFilter};
use super::status::ProcessStatus; use super::status::ProcessStatus;
use super::{process_table, TermStatus}; use super::{process_table, TermStatus};
use crate::device::tty::get_n_tty; use crate::device::tty::get_n_tty;
@ -20,7 +21,6 @@ use crate::fs::utils::FileCreationMask;
use crate::prelude::*; use crate::prelude::*;
use crate::thread::{allocate_tid, Thread}; use crate::thread::{allocate_tid, Thread};
use crate::vm::vmar::Vmar; use crate::vm::vmar::Vmar;
use jinux_frame::sync::WaitQueue;
use jinux_rights::Full; use jinux_rights::Full;
pub use builder::ProcessBuilder; pub use builder::ProcessBuilder;
@ -35,8 +35,8 @@ pub struct Process {
pid: Pid, pid: Pid,
process_vm: ProcessVm, process_vm: ProcessVm,
/// wait for child status changed /// Wait for child status changed
waiting_children: WaitQueue, children_pauser: Arc<Pauser>,
// Mutable Part // Mutable Part
/// The executable path. /// The executable path.
@ -82,12 +82,20 @@ impl Process {
sig_dispositions: Arc<Mutex<SigDispositions>>, sig_dispositions: Arc<Mutex<SigDispositions>>,
resource_limits: ResourceLimits, resource_limits: ResourceLimits,
) -> Self { ) -> 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 { Self {
pid, pid,
threads: Mutex::new(threads), threads: Mutex::new(threads),
executable_path: RwLock::new(executable_path), executable_path: RwLock::new(executable_path),
process_vm, process_vm,
waiting_children: WaitQueue::new(), children_pauser,
status: Mutex::new(ProcessStatus::Uninit), status: Mutex::new(ProcessStatus::Uninit),
parent: Mutex::new(parent), parent: Mutex::new(parent),
children: Mutex::new(BTreeMap::new()), children: Mutex::new(BTreeMap::new()),
@ -190,8 +198,8 @@ impl Process {
&self.children &self.children
} }
pub fn waiting_children(&self) -> &WaitQueue { pub fn children_pauser(&self) -> &Arc<Pauser> {
&self.waiting_children &self.children_pauser
} }
// *********** Process group *********** // *********** Process group ***********
@ -252,7 +260,7 @@ impl Process {
} }
pub fn has_pending_signal(&self) -> bool { 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>) { pub fn enqueue_signal(&self, signal: Box<dyn Signal>) {

View File

@ -1,11 +1,5 @@
use core::sync::atomic::{AtomicBool, Ordering}; use crate::events::{Events, EventsFilter};
use core::time::Duration;
use jinux_frame::sync::WaitQueue;
use crate::events::{Events, EventsFilter, Observer};
use crate::prelude::*; use crate::prelude::*;
use crate::process::posix_thread::PosixThreadExt;
use super::sig_mask::SigMask; use super::sig_mask::SigMask;
use super::sig_num::SigNum; use super::sig_num::SigNum;
@ -35,101 +29,3 @@ impl EventsFilter<SigEvents> for SigEventsFilter {
self.0.contains(event.0) 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 c_types;
pub mod constants; pub mod constants;
mod events; mod events;
mod pauser;
mod poll;
pub mod sig_action; pub mod sig_action;
pub mod sig_disposition; pub mod sig_disposition;
pub mod sig_mask; pub mod sig_mask;
@ -8,7 +10,9 @@ pub mod sig_num;
pub mod sig_queues; pub mod sig_queues;
pub mod signals; 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; 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::events::{Observer, Subject};
use crate::prelude::*; use crate::prelude::*;
use crate::process::signal::sig_mask::SigMask; use crate::process::signal::Pauser;
use crate::process::signal::SigQueueObserver;
use core::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; use core::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
use core::time::Duration; use core::time::Duration;
@ -160,13 +159,15 @@ impl Poller {
/// Wait until there are any interesting events happen since last `wait`. The `wait` /// Wait until there are any interesting events happen since last `wait`. The `wait`
/// can be interrupted by signal. /// can be interrupted by signal.
pub fn wait_interruptible(&self, timeout: Option<&Duration>) -> Result<()> { pub fn wait(&self) -> Result<()> {
self.inner.event_counter.read_interruptible(timeout)?; self.inner.event_counter.read(None)?;
Ok(()) Ok(())
} }
pub fn wait_uninterruptible(&self, timeout: Option<&Duration>) -> Result<()> { /// Wait until there are any interesting events happen since last `wait` or a given timeout
self.inner.event_counter.read_uninterruptible(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(()) Ok(())
} }
@ -200,53 +201,38 @@ impl Drop for Poller {
/// A counter for wait and wakeup. /// A counter for wait and wakeup.
struct EventCounter { struct EventCounter {
counter: AtomicUsize, counter: AtomicUsize,
observer: Arc<SigQueueObserver>, pauser: Arc<Pauser>,
} }
impl EventCounter { impl EventCounter {
pub fn new() -> Self { pub fn new() -> Self {
let observer = { let pauser = Pauser::new();
// FIXME: choose the suitable mask
let mask = SigMask::new_full();
SigQueueObserver::new(mask)
};
Self { Self {
counter: AtomicUsize::new(0), counter: AtomicUsize::new(0),
observer, pauser,
} }
} }
pub fn read_interruptible(&self, timeout: Option<&Duration>) -> Result<usize> { pub fn read(&self, timeout: Option<&Duration>) -> Result<usize> {
self.observer.wait_until_interruptible( let cond = || {
|| {
let val = self.counter.swap(0, Ordering::Relaxed); let val = self.counter.swap(0, Ordering::Relaxed);
if val > 0 { if val > 0 {
Some(val) Some(val)
} else { } else {
None None
} }
}, };
timeout,
)
}
pub fn read_uninterruptible(&self, timeout: Option<&Duration>) -> Result<usize> { if let Some(timeout) = timeout {
self.observer.wait_until_uninterruptible( self.pauser.pause_until_or_timeout(cond, timeout)
|| {
let val = self.counter.swap(0, Ordering::Relaxed);
if val > 0 {
Some(val)
} else { } else {
None self.pauser.pause_until(cond)
} }
},
timeout,
)
} }
pub fn write(&self) { pub fn write(&self) {
self.counter.fetch_add(1, Ordering::Relaxed); self.counter.fetch_add(1, Ordering::Relaxed);
self.observer.wake_one(); self.pauser.resume_one();
} }
} }

View File

@ -26,8 +26,7 @@ pub fn wait_child_exit(
wait_options: WaitOptions, wait_options: WaitOptions,
) -> Result<(Pid, ExitCode)> { ) -> Result<(Pid, ExitCode)> {
let current = current!(); let current = current!();
let (pid, exit_code) = current.waiting_children().wait_until( let (pid, exit_code) = current.children_pauser().pause_until(|| {
|| {
let unwaited_children = current let unwaited_children = current
.children() .children()
.lock() .lock()
@ -68,9 +67,7 @@ pub fn wait_child_exit(
// wait // wait
None None
}, })??;
None,
)??;
Ok((pid, exit_code as _)) Ok((pid, exit_code as _))
} }

View File

@ -4,8 +4,7 @@ use super::SyscallReturn;
use super::SYS_CLOCK_NANOSLEEP; use super::SYS_CLOCK_NANOSLEEP;
use crate::log_syscall_entry; use crate::log_syscall_entry;
use crate::prelude::*; use crate::prelude::*;
use crate::process::signal::sig_mask::SigMask; use crate::process::signal::Pauser;
use crate::process::signal::SigQueueObserver;
use crate::time::{clockid_t, now_as_duration, timespec_t, ClockID, TIMER_ABSTIME}; use crate::time::{clockid_t, now_as_duration, timespec_t, ClockID, TIMER_ABSTIME};
use crate::util::{read_val_from_user, write_val_to_user}; 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 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 // 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. // current process. i.e., the signals that should be ignored will not interrupt sleeping thread.
let sigmask = SigMask::new_full(); let pauser = Pauser::new();
SigQueueObserver::new(sigmask)
};
let res = sigqueue_observer.wait_until_interruptible(|| None, Some(&duration)); let res = pauser.pause_until_or_timeout(|| None, &duration);
match res { match res {
Err(e) if e.error() == Errno::ETIME => Ok(SyscallReturn::Return(0)), Err(e) if e.error() == Errno::ETIME => Ok(SyscallReturn::Return(0)),
Err(e) if e.error() == Errno::EINTR => { Err(e) if e.error() == Errno::EINTR => {

View File

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

View File

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

View File

@ -1,10 +1,11 @@
use core::cell::Cell; use core::cell::Cell;
use core::time::Duration; use core::time::Duration;
use crate::events::IoEvents;
use crate::fs::file_table::FileDescripter; use crate::fs::file_table::FileDescripter;
use crate::fs::utils::{IoEvents, Poller};
use crate::log_syscall_entry; use crate::log_syscall_entry;
use crate::prelude::*; use crate::prelude::*;
use crate::process::signal::Poller;
use crate::util::{read_val_from_user, write_val_to_user}; use crate::util::{read_val_from_user, write_val_to_user};
use super::SyscallReturn; use super::SyscallReturn;
@ -91,7 +92,11 @@ pub fn do_poll(poll_fds: &[PollFd], timeout: Option<Duration>) -> Result<usize>
return Ok(0); 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 core::time::Duration;
use crate::events::IoEvents;
use crate::fs::file_table::FileDescripter; use crate::fs::file_table::FileDescripter;
use crate::fs::utils::IoEvents;
use crate::log_syscall_entry; use crate::log_syscall_entry;
use crate::prelude::*; use crate::prelude::*;
use crate::time::timeval_t; use crate::time::timeval_t;