From 0d6f6f001c353f40ca90373ae2820fb62c317549 Mon Sep 17 00:00:00 2001 From: Jianfeng Jiang Date: Sun, 8 Oct 2023 17:40:58 +0800 Subject: [PATCH] Refactor the implementation --- Cargo.lock | 7 + framework/jinux-frame/Cargo.toml | 1 + .../jinux-frame/src/arch/x86/timer/mod.rs | 48 ++--- framework/jinux-frame/src/error.rs | 1 - framework/jinux-frame/src/lib.rs | 2 + framework/jinux-frame/src/sync/mutex.rs | 2 +- framework/jinux-frame/src/sync/rwmutex.rs | 4 +- framework/jinux-frame/src/sync/wait.rs | 36 ++-- framework/jinux-frame/src/timer.rs | 4 +- services/libs/jinux-std/src/device/pty/pty.rs | 6 +- .../src/device/tty/line_discipline.rs | 5 +- services/libs/jinux-std/src/device/tty/mod.rs | 4 +- services/libs/jinux-std/src/error.rs | 1 - .../src/{fs/utils => events}/io_events.rs | 2 +- services/libs/jinux-std/src/events/mod.rs | 2 + services/libs/jinux-std/src/fs/device.rs | 4 +- .../libs/jinux-std/src/fs/devpts/master.rs | 5 +- services/libs/jinux-std/src/fs/devpts/mod.rs | 4 +- .../libs/jinux-std/src/fs/devpts/slave.rs | 2 + .../libs/jinux-std/src/fs/epoll/epoll_file.rs | 11 +- services/libs/jinux-std/src/fs/epoll/mod.rs | 2 +- services/libs/jinux-std/src/fs/file_handle.rs | 5 +- .../jinux-std/src/fs/inode_handle/dyn_cap.rs | 2 + .../libs/jinux-std/src/fs/inode_handle/mod.rs | 3 +- services/libs/jinux-std/src/fs/pipe.rs | 7 +- services/libs/jinux-std/src/fs/ramfs/fs.rs | 6 +- .../libs/jinux-std/src/fs/utils/channel.rs | 8 +- services/libs/jinux-std/src/fs/utils/inode.rs | 4 +- services/libs/jinux-std/src/fs/utils/mod.rs | 4 - services/libs/jinux-std/src/fs/utils/vnode.rs | 5 +- .../jinux-std/src/net/iface/any_socket.rs | 7 +- .../jinux-std/src/net/socket/ip/datagram.rs | 9 +- .../src/net/socket/ip/stream/connected.rs | 5 +- .../src/net/socket/ip/stream/init.rs | 5 +- .../src/net/socket/ip/stream/listen.rs | 5 +- .../jinux-std/src/net/socket/ip/stream/mod.rs | 7 +- .../src/net/socket/unix/stream/connected.rs | 3 +- .../src/net/socket/unix/stream/endpoint.rs | 4 +- .../src/net/socket/unix/stream/init.rs | 4 +- .../src/net/socket/unix/stream/listener.rs | 6 +- .../src/net/socket/unix/stream/socket.rs | 4 +- services/libs/jinux-std/src/process/exit.rs | 2 +- .../jinux-std/src/process/posix_thread/mod.rs | 2 +- .../libs/jinux-std/src/process/process/mod.rs | 24 ++- .../jinux-std/src/process/signal/events.rs | 106 +---------- .../libs/jinux-std/src/process/signal/mod.rs | 6 +- .../jinux-std/src/process/signal/pauser.rs | 176 ++++++++++++++++++ .../src/{fs/utils => process/signal}/poll.rs | 66 +++---- services/libs/jinux-std/src/process/wait.rs | 79 ++++---- .../jinux-std/src/syscall/clock_nanosleep.rs | 14 +- services/libs/jinux-std/src/syscall/epoll.rs | 3 +- services/libs/jinux-std/src/syscall/pause.rs | 14 +- services/libs/jinux-std/src/syscall/poll.rs | 9 +- services/libs/jinux-std/src/syscall/select.rs | 2 +- 54 files changed, 433 insertions(+), 326 deletions(-) rename services/libs/jinux-std/src/{fs/utils => events}/io_events.rs (92%) create mode 100644 services/libs/jinux-std/src/process/signal/pauser.rs rename services/libs/jinux-std/src/{fs/utils => process/signal}/poll.rs (81%) diff --git a/Cargo.lock b/Cargo.lock index 4b6c21d57..aed6c8df8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/framework/jinux-frame/Cargo.toml b/framework/jinux-frame/Cargo.toml index 65c990a5f..ca17e207b 100644 --- a/framework/jinux-frame/Cargo.toml +++ b/framework/jinux-frame/Cargo.toml @@ -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" diff --git a/framework/jinux-frame/src/arch/x86/timer/mod.rs b/framework/jinux-frame/src/arch/x86/timer/mod.rs index 1195d8c75..a3464143e 100644 --- a/framework/jinux-frame/src/arch/x86/timer/mod.rs +++ b/framework/jinux-frame/src/arch/x86/timer/mod.rs @@ -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> = 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, callback: Box, - 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); diff --git a/framework/jinux-frame/src/error.rs b/framework/jinux-frame/src/error.rs index 3e535d556..fa6676d10 100644 --- a/framework/jinux-frame/src/error.rs +++ b/framework/jinux-frame/src/error.rs @@ -7,5 +7,4 @@ pub enum Error { AccessDenied, IoError, NotEnoughResources, - TimeOut, } diff --git a/framework/jinux-frame/src/lib.rs b/framework/jinux-frame/src/lib.rs index b02750954..5d5871924 100644 --- a/framework/jinux-frame/src/lib.rs +++ b/framework/jinux-frame/src/lib.rs @@ -17,6 +17,8 @@ #![feature(let_chains)] extern crate alloc; +#[macro_use] +extern crate static_assertions; pub mod arch; pub mod boot; diff --git a/framework/jinux-frame/src/sync/mutex.rs b/framework/jinux-frame/src/sync/mutex.rs index 4157b77da..799a5ccc2 100644 --- a/framework/jinux-frame/src/sync/mutex.rs +++ b/framework/jinux-frame/src/sync/mutex.rs @@ -26,7 +26,7 @@ impl Mutex { /// /// This method runs in a block way until the mutex can be acquired. pub fn lock(&self) -> MutexGuard { - self.queue.wait_until(|| self.try_lock(), None).unwrap() + self.queue.wait_until(|| self.try_lock()) } /// Try Acquire the mutex immedidately. diff --git a/framework/jinux-frame/src/sync/rwmutex.rs b/framework/jinux-frame/src/sync/rwmutex.rs index 4a6e91c09..789a5fa05 100644 --- a/framework/jinux-frame/src/sync/rwmutex.rs +++ b/framework/jinux-frame/src/sync/rwmutex.rs @@ -35,12 +35,12 @@ impl RwMutex { /// Acquire a read mutex, and if there is a writer, this thread will sleep in the wait queue. pub fn read(&self) -> RwMutexReadGuard { - 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 { - 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. diff --git a/framework/jinux-frame/src/sync/wait.rs b/framework/jinux-frame/src/sync/wait.rs index 66bf22ae3..66b3ff3ff 100644 --- a/framework/jinux-frame/src/sync/wait.rs +++ b/framework/jinux-frame/src/sync/wait.rs @@ -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(&self, mut cond: F, timeout: Option<&Duration>) -> Result + pub fn wait_until(&self, cond: F) -> R + where + F: FnMut() -> Option, + { + 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(&self, cond: F, timeout: &Duration) -> Option + where + F: FnMut() -> Option, + { + self.do_wait(cond, Some(timeout)) + } + + fn do_wait(&self, mut cond: F, timeout: Option<&Duration>) -> Option where F: FnMut() -> Option, { 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(); diff --git a/framework/jinux-frame/src/timer.rs b/framework/jinux-frame/src/timer.rs index 019424f6e..551528d7d 100644 --- a/framework/jinux-frame/src/timer.rs +++ b/framework/jinux-frame/src/timer.rs @@ -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; diff --git a/services/libs/jinux-std/src/device/pty/pty.rs b/services/libs/jinux-std/src/device/pty/pty.rs index 3a47dd7bb..34ca3044a 100644 --- a/services/libs/jinux-std/src/device/pty/pty.rs +++ b/services/libs/jinux-std/src/device/pty/pty.rs @@ -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; } diff --git a/services/libs/jinux-std/src/device/tty/line_discipline.rs b/services/libs/jinux-std/src/device/tty/line_discipline.rs index b8b516825..f0e498769 100644 --- a/services/libs/jinux-std/src/device/tty/line_discipline.rs +++ b/services/libs/jinux-std/src/device/tty/line_discipline.rs @@ -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()?; } } } diff --git a/services/libs/jinux-std/src/device/tty/mod.rs b/services/libs/jinux-std/src/device/tty/mod.rs index a71749244..395ca0f75 100644 --- a/services/libs/jinux-std/src/device/tty/mod.rs +++ b/services/libs/jinux-std/src/device/tty/mod.rs @@ -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}; diff --git a/services/libs/jinux-std/src/error.rs b/services/libs/jinux-std/src/error.rs index 18de95739..2827c5afa 100644 --- a/services/libs/jinux-std/src/error.rs +++ b/services/libs/jinux-std/src/error.rs @@ -187,7 +187,6 @@ impl From 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), } } } diff --git a/services/libs/jinux-std/src/fs/utils/io_events.rs b/services/libs/jinux-std/src/events/io_events.rs similarity index 92% rename from services/libs/jinux-std/src/fs/utils/io_events.rs rename to services/libs/jinux-std/src/events/io_events.rs index 7d5ed3c43..7f8111f34 100644 --- a/services/libs/jinux-std/src/fs/utils/io_events.rs +++ b/services/libs/jinux-std/src/events/io_events.rs @@ -1,4 +1,4 @@ -use crate::events::{Events, EventsFilter}; +use super::{Events, EventsFilter}; crate::bitflags! { pub struct IoEvents: u32 { diff --git a/services/libs/jinux-std/src/events/mod.rs b/services/libs/jinux-std/src/events/mod.rs index f5c035236..b977e5f87 100644 --- a/services/libs/jinux-std/src/events/mod.rs +++ b/services/libs/jinux-std/src/events/mod.rs @@ -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; diff --git a/services/libs/jinux-std/src/fs/device.rs b/services/libs/jinux-std/src/fs/device.rs index dc5fb9f7e..c85c74eb8 100644 --- a/services/libs/jinux-std/src/fs/device.rs +++ b/services/libs/jinux-std/src/fs/device.rs @@ -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 { diff --git a/services/libs/jinux-std/src/fs/devpts/master.rs b/services/libs/jinux-std/src/fs/devpts/master.rs index 88a97cd0e..324d35b83 100644 --- a/services/libs/jinux-std/src/fs/devpts/master.rs +++ b/services/libs/jinux-std/src/fs/devpts/master.rs @@ -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::*; diff --git a/services/libs/jinux-std/src/fs/devpts/mod.rs b/services/libs/jinux-std/src/fs/devpts/mod.rs index 024c782b9..e07d8be5b 100644 --- a/services/libs/jinux-std/src/fs/devpts/mod.rs +++ b/services/libs/jinux-std/src/fs/devpts/mod.rs @@ -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::*; diff --git a/services/libs/jinux-std/src/fs/devpts/slave.rs b/services/libs/jinux-std/src/fs/devpts/slave.rs index 027e243eb..125dcf5c3 100644 --- a/services/libs/jinux-std/src/fs/devpts/slave.rs +++ b/services/libs/jinux-std/src/fs/devpts/slave.rs @@ -1,4 +1,6 @@ +use crate::events::IoEvents; use crate::prelude::*; +use crate::process::signal::Poller; use super::*; diff --git a/services/libs/jinux-std/src/fs/epoll/epoll_file.rs b/services/libs/jinux-std/src/fs/epoll/epoll_file.rs index 5b51879aa..6206d1bc2 100644 --- a/services/libs/jinux-std/src/fs/epoll/epoll_file.rs +++ b/services/libs/jinux-std/src/fs/epoll/epoll_file.rs @@ -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()?; + } } } diff --git a/services/libs/jinux-std/src/fs/epoll/mod.rs b/services/libs/jinux-std/src/fs/epoll/mod.rs index c994af3e2..66ae3bfc9 100644 --- a/services/libs/jinux-std/src/fs/epoll/mod.rs +++ b/services/libs/jinux-std/src/fs/epoll/mod.rs @@ -1,5 +1,5 @@ use super::file_table::FileDescripter; -use super::utils::IoEvents; +use crate::events::IoEvents; use crate::prelude::*; mod epoll_file; diff --git a/services/libs/jinux-std/src/fs/file_handle.rs b/services/libs/jinux-std/src/fs/file_handle.rs index a6dd1a30a..2036d7557 100644 --- a/services/libs/jinux-std/src/fs/file_handle.rs +++ b/services/libs/jinux-std/src/fs/file_handle.rs @@ -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; diff --git a/services/libs/jinux-std/src/fs/inode_handle/dyn_cap.rs b/services/libs/jinux-std/src/fs/inode_handle/dyn_cap.rs index a60ea1a2f..0042194f2 100644 --- a/services/libs/jinux-std/src/fs/inode_handle/dyn_cap.rs +++ b/services/libs/jinux-std/src/fs/inode_handle/dyn_cap.rs @@ -1,4 +1,6 @@ +use crate::events::IoEvents; use crate::prelude::*; +use crate::process::signal::Poller; use jinux_rights::{Rights, TRights}; use super::*; diff --git a/services/libs/jinux-std/src/fs/inode_handle/mod.rs b/services/libs/jinux-std/src/fs/inode_handle/mod.rs index d1903b306..2608c36c9 100644 --- a/services/libs/jinux-std/src/fs/inode_handle/mod.rs +++ b/services/libs/jinux-std/src/fs/inode_handle/mod.rs @@ -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; diff --git a/services/libs/jinux-std/src/fs/pipe.rs b/services/libs/jinux-std/src/fs/pipe.rs index ee1bba7f3..d7992ca49 100644 --- a/services/libs/jinux-std/src/fs/pipe.rs +++ b/services/libs/jinux-std/src/fs/pipe.rs @@ -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, diff --git a/services/libs/jinux-std/src/fs/ramfs/fs.rs b/services/libs/jinux-std/src/fs/ramfs/fs.rs index 06ec9a3aa..132d0a7f7 100644 --- a/services/libs/jinux-std/src/fs/ramfs/fs.rs +++ b/services/libs/jinux-std/src/fs/ramfs/fs.rs @@ -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. diff --git a/services/libs/jinux-std/src/fs/utils/channel.rs b/services/libs/jinux-std/src/fs/utils/channel.rs index b482b3f2a..605096c07 100644 --- a/services/libs/jinux-std/src/fs/utils/channel.rs +++ b/services/libs/jinux-std/src/fs/utils/channel.rs @@ -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 Producer { 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 Consumer { let events = self.poll(mask, Some(&poller)); if events.is_empty() { // FIXME: should channel have timeout? - poller.wait_interruptible(None)?; + poller.wait()?; } } } diff --git a/services/libs/jinux-std/src/fs/utils/inode.rs b/services/libs/jinux-std/src/fs/utils/inode.rs index 5bf42d0ae..a27c62131 100644 --- a/services/libs/jinux-std/src/fs/utils/inode.rs +++ b/services/libs/jinux-std/src/fs/utils/inode.rs @@ -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)] diff --git a/services/libs/jinux-std/src/fs/utils/mod.rs b/services/libs/jinux-std/src/fs/utils/mod.rs index ff9d7a202..b8f9e9839 100644 --- a/services/libs/jinux-std/src/fs/utils/mod.rs +++ b/services/libs/jinux-std/src/fs/utils/mod.rs @@ -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; diff --git a/services/libs/jinux-std/src/fs/utils/vnode.rs b/services/libs/jinux-std/src/fs/utils/vnode.rs index 6e387e40e..c064445e0 100644 --- a/services/libs/jinux-std/src/fs/utils/vnode.rs +++ b/services/libs/jinux-std/src/fs/utils/vnode.rs @@ -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; diff --git a/services/libs/jinux-std/src/net/iface/any_socket.rs b/services/libs/jinux-std/src/net/iface/any_socket.rs index f43f9d606..020fe5692 100644 --- a/services/libs/jinux-std/src/net/iface/any_socket.rs +++ b/services/libs/jinux-std/src/net/iface/any_socket.rs @@ -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}; diff --git a/services/libs/jinux-std/src/net/socket/ip/datagram.rs b/services/libs/jinux-std/src/net/socket/ip/datagram.rs index c0fadab75..f393fe858 100644 --- a/services/libs/jinux-std/src/net/socket/ip/datagram.rs +++ b/services/libs/jinux-std/src/net/socket/ip/datagram.rs @@ -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()?; } } } diff --git a/services/libs/jinux-std/src/net/socket/ip/stream/connected.rs b/services/libs/jinux-std/src/net/socket/ip/stream/connected.rs index f53f146f0..14d21d762 100644 --- a/services/libs/jinux-std/src/net/socket/ip/stream/connected.rs +++ b/services/libs/jinux-std/src/net/socket/ip/stream/connected.rs @@ -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()?; } } } diff --git a/services/libs/jinux-std/src/net/socket/ip/stream/init.rs b/services/libs/jinux-std/src/net/socket/ip/stream/init.rs index b8a2a7d73..f184ae220 100644 --- a/services/libs/jinux-std/src/net/socket/ip/stream/init.rs +++ b/services/libs/jinux-std/src/net/socket/ip/stream/init.rs @@ -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, @@ -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()?; } } } diff --git a/services/libs/jinux-std/src/net/socket/ip/stream/listen.rs b/services/libs/jinux-std/src/net/socket/ip/stream/listen.rs index 94c4588ec..ff73d4bc5 100644 --- a/services/libs/jinux-std/src/net/socket/ip/stream/listen.rs +++ b/services/libs/jinux-std/src/net/socket/ip/stream/listen.rs @@ -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; }; diff --git a/services/libs/jinux-std/src/net/socket/ip/stream/mod.rs b/services/libs/jinux-std/src/net/socket/ip/stream/mod.rs index b250a961a..2abb76fa2 100644 --- a/services/libs/jinux-std/src/net/socket/ip/stream/mod.rs +++ b/services/libs/jinux-std/src/net/socket/ip/stream/mod.rs @@ -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}; diff --git a/services/libs/jinux-std/src/net/socket/unix/stream/connected.rs b/services/libs/jinux-std/src/net/socket/unix/stream/connected.rs index 859e5b35f..f4d611b3f 100644 --- a/services/libs/jinux-std/src/net/socket/unix/stream/connected.rs +++ b/services/libs/jinux-std/src/net/socket/unix/stream/connected.rs @@ -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, diff --git a/services/libs/jinux-std/src/net/socket/unix/stream/endpoint.rs b/services/libs/jinux-std/src/net/socket/unix/stream/endpoint.rs index 88d8d780a..9071fd378 100644 --- a/services/libs/jinux-std/src/net/socket/unix/stream/endpoint.rs +++ b/services/libs/jinux-std/src/net/socket/unix/stream/endpoint.rs @@ -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::*, }; diff --git a/services/libs/jinux-std/src/net/socket/unix/stream/init.rs b/services/libs/jinux-std/src/net/socket/unix/stream/init.rs index 1ae3e05ab..cc6c34124 100644 --- a/services/libs/jinux-std/src/net/socket/unix/stream/init.rs +++ b/services/libs/jinux-std/src/net/socket/unix/stream/init.rs @@ -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; diff --git a/services/libs/jinux-std/src/net/socket/unix/stream/listener.rs b/services/libs/jinux-std/src/net/socket/unix/stream/listener.rs index 752f70655..d143c3b0d 100644 --- a/services/libs/jinux-std/src/net/socket/unix/stream/listener.rs +++ b/services/libs/jinux-std/src/net/socket/unix/stream/listener.rs @@ -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()?; } } } diff --git a/services/libs/jinux-std/src/net/socket/unix/stream/socket.rs b/services/libs/jinux-std/src/net/socket/unix/stream/socket.rs index ba41c3591..5112904fc 100644 --- a/services/libs/jinux-std/src/net/socket/unix/stream/socket.rs +++ b/services/libs/jinux-std/src/net/socket/unix/stream/socket.rs @@ -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; diff --git a/services/libs/jinux-std/src/process/exit.rs b/services/libs/jinux-std/src/process/exit.rs index d82d4c142..8857923f9 100644 --- a/services/libs/jinux-std/src/process/exit.rs +++ b/services/libs/jinux-std/src/process/exit.rs @@ -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(); } } diff --git a/services/libs/jinux-std/src/process/posix_thread/mod.rs b/services/libs/jinux-std/src/process/posix_thread/mod.rs index a135dd79c..d7cc85fc3 100644 --- a/services/libs/jinux-std/src/process/posix_thread/mod.rs +++ b/services/libs/jinux-std/src/process/posix_thread/mod.rs @@ -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) { diff --git a/services/libs/jinux-std/src/process/process/mod.rs b/services/libs/jinux-std/src/process/process/mod.rs index f3ce41671..476786124 100644 --- a/services/libs/jinux-std/src/process/process/mod.rs +++ b/services/libs/jinux-std/src/process/process/mod.rs @@ -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, // Mutable Part /// The executable path. @@ -82,12 +82,20 @@ impl Process { sig_dispositions: Arc>, 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 { + &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) { diff --git a/services/libs/jinux-std/src/process/signal/events.rs b/services/libs/jinux-std/src/process/signal/events.rs index c7da9352f..0a0f5ad5d 100644 --- a/services/libs/jinux-std/src/process/signal/events.rs +++ b/services/libs/jinux-std/src/process/signal/events.rs @@ -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 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 { - 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( - self: &Arc, - mut cond: F, - timeout: Option<&Duration>, - ) -> Result - where - F: FnMut() -> Option, - { - self.is_interrupted.store(false, Ordering::Release); - - // Register observers on sigqueues - - let observer = Arc::downgrade(self) as Weak>; - 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 { - 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(&self, cond: F, timeout: Option<&Duration>) -> Result - where - F: FnMut() -> Option, - { - 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 for SigQueueObserver { - fn on_events(&self, events: &SigEvents) { - self.is_interrupted.store(true, Ordering::Release); - self.wait_queue.wake_all(); - } -} diff --git a/services/libs/jinux-std/src/process/signal/mod.rs b/services/libs/jinux-std/src/process/signal/mod.rs index 2f9baa08e..c9b966bc6 100644 --- a/services/libs/jinux-std/src/process/signal/mod.rs +++ b/services/libs/jinux-std/src/process/signal/mod.rs @@ -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; diff --git a/services/libs/jinux-std/src/process/signal/pauser.rs b/services/libs/jinux-std/src/process/signal/pauser.rs new file mode 100644 index 000000000..57432f1bf --- /dev/null +++ b/services/libs/jinux-std/src/process/signal/pauser.rs @@ -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`. +/// 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::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 { + 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(self: &Arc, cond: F) -> Result + where + F: FnMut() -> Option, + { + 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(self: &Arc, cond: F, timeout: &Duration) -> Result + where + F: FnMut() -> Option, + { + self.do_pause(cond, Some(timeout)) + } + + fn do_pause(self: &Arc, mut cond: F, timeout: Option<&Duration>) -> Result + where + F: FnMut() -> Option, + { + self.is_interrupted.store(false, Ordering::Release); + + // Register observers on sigqueues + + let observer = Arc::downgrade(self) as Weak>; + 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 { + 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 for Pauser { + fn on_events(&self, events: &SigEvents) { + self.is_interrupted.store(true, Ordering::Release); + self.wait_queue.wake_all(); + } +} diff --git a/services/libs/jinux-std/src/fs/utils/poll.rs b/services/libs/jinux-std/src/process/signal/poll.rs similarity index 81% rename from services/libs/jinux-std/src/fs/utils/poll.rs rename to services/libs/jinux-std/src/process/signal/poll.rs index 34a8d358a..6cb0f075b 100644 --- a/services/libs/jinux-std/src/fs/utils/poll.rs +++ b/services/libs/jinux-std/src/process/signal/poll.rs @@ -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, + pauser: Arc, } 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 { - 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 { + 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 { - 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(); } } diff --git a/services/libs/jinux-std/src/process/wait.rs b/services/libs/jinux-std/src/process/wait.rs index 7004b8c1a..4732be621 100644 --- a/services/libs/jinux-std/src/process/wait.rs +++ b/services/libs/jinux-std/src/process/wait.rs @@ -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::>(); + 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::>(); - 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(¤t, 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(¤t, 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 _)) } diff --git a/services/libs/jinux-std/src/syscall/clock_nanosleep.rs b/services/libs/jinux-std/src/syscall/clock_nanosleep.rs index 75f2e33f0..c94f0336d 100644 --- a/services/libs/jinux-std/src/syscall/clock_nanosleep.rs +++ b/services/libs/jinux-std/src/syscall/clock_nanosleep.rs @@ -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 => { diff --git a/services/libs/jinux-std/src/syscall/epoll.rs b/services/libs/jinux-std/src/syscall/epoll.rs index bbb403e67..553597356 100644 --- a/services/libs/jinux-std/src/syscall/epoll.rs +++ b/services/libs/jinux-std/src/syscall/epoll.rs @@ -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}; diff --git a/services/libs/jinux-std/src/syscall/pause.rs b/services/libs/jinux-std/src/syscall/pause.rs index c11ddc6f8..8f5701221 100644 --- a/services/libs/jinux-std/src/syscall/pause.rs +++ b/services/libs/jinux-std/src/syscall/pause.rs @@ -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 { 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"); } diff --git a/services/libs/jinux-std/src/syscall/poll.rs b/services/libs/jinux-std/src/syscall/poll.rs index 42351fe0f..4833cc042 100644 --- a/services/libs/jinux-std/src/syscall/poll.rs +++ b/services/libs/jinux-std/src/syscall/poll.rs @@ -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) -> Result return Ok(0); } - poller.wait_interruptible(timeout.as_ref())?; + if let Some(timeout) = timeout.as_ref() { + poller.wait_timeout(timeout)?; + } else { + poller.wait()?; + } } } diff --git a/services/libs/jinux-std/src/syscall/select.rs b/services/libs/jinux-std/src/syscall/select.rs index 9ab34ba75..48171d640 100644 --- a/services/libs/jinux-std/src/syscall/select.rs +++ b/services/libs/jinux-std/src/syscall/select.rs @@ -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;