Refactor the implementation
This commit is contained in:
parent
50761a5cc5
commit
0d6f6f001c
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -36,22 +36,28 @@ pub fn init() {
|
|||
|
||||
fn timer_callback(trap_frame: &TrapFrame) {
|
||||
let current_ticks = TICK.fetch_add(1, Ordering::SeqCst);
|
||||
let mut timeout_list = TIMEOUT_LIST.get().unwrap().lock();
|
||||
let mut callbacks: Vec<Arc<TimerCallback>> = Vec::new();
|
||||
while let Some(t) = timeout_list.peek() {
|
||||
if t.is_cancelled() {
|
||||
// Just ignore the cancelled callback
|
||||
timeout_list.pop();
|
||||
} else if t.expire_ticks <= current_ticks && t.is_enable() {
|
||||
callbacks.push(timeout_list.pop().unwrap());
|
||||
} else {
|
||||
break;
|
||||
|
||||
let callbacks = {
|
||||
let mut callbacks = Vec::new();
|
||||
let mut timeout_list = TIMEOUT_LIST.get().unwrap().lock();
|
||||
|
||||
while let Some(t) = timeout_list.peek() {
|
||||
if t.is_cancelled() {
|
||||
// Just ignore the cancelled callback
|
||||
timeout_list.pop();
|
||||
} else if t.expire_ticks <= current_ticks {
|
||||
callbacks.push(timeout_list.pop().unwrap());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(timeout_list);
|
||||
callbacks
|
||||
};
|
||||
|
||||
for callback in callbacks {
|
||||
callback.callback.call((&callback,));
|
||||
(callback.callback)(&callback);
|
||||
}
|
||||
|
||||
if APIC_TIMER_CALLBACK.is_completed() {
|
||||
APIC_TIMER_CALLBACK.get().unwrap().call(());
|
||||
}
|
||||
|
@ -63,7 +69,6 @@ pub struct TimerCallback {
|
|||
expire_ticks: u64,
|
||||
data: Arc<dyn Any + Send + Sync>,
|
||||
callback: Box<dyn Fn(&TimerCallback) + Send + Sync>,
|
||||
enable: AtomicBool,
|
||||
is_cancelled: AtomicBool,
|
||||
}
|
||||
|
||||
|
@ -77,7 +82,6 @@ impl TimerCallback {
|
|||
expire_ticks: timeout_ticks,
|
||||
data,
|
||||
callback,
|
||||
enable: AtomicBool::new(true),
|
||||
is_cancelled: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
@ -86,20 +90,6 @@ impl TimerCallback {
|
|||
&self.data
|
||||
}
|
||||
|
||||
/// disable this timeout
|
||||
pub fn disable(&self) {
|
||||
self.enable.store(false, Ordering::Release)
|
||||
}
|
||||
|
||||
/// enable this timeout
|
||||
pub fn enable(&self) {
|
||||
self.enable.store(false, Ordering::Release)
|
||||
}
|
||||
|
||||
pub fn is_enable(&self) -> bool {
|
||||
self.enable.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
/// Whether the set timeout is reached
|
||||
pub fn is_expired(&self) -> bool {
|
||||
let current_tick = TICK.load(Ordering::Acquire);
|
||||
|
|
|
@ -7,5 +7,4 @@ pub enum Error {
|
|||
AccessDenied,
|
||||
IoError,
|
||||
NotEnoughResources,
|
||||
TimeOut,
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#![feature(let_chains)]
|
||||
|
||||
extern crate alloc;
|
||||
#[macro_use]
|
||||
extern crate static_assertions;
|
||||
|
||||
pub mod arch;
|
||||
pub mod boot;
|
||||
|
|
|
@ -26,7 +26,7 @@ impl<T> Mutex<T> {
|
|||
///
|
||||
/// This method runs in a block way until the mutex can be acquired.
|
||||
pub fn lock(&self) -> MutexGuard<T> {
|
||||
self.queue.wait_until(|| self.try_lock(), None).unwrap()
|
||||
self.queue.wait_until(|| self.try_lock())
|
||||
}
|
||||
|
||||
/// Try Acquire the mutex immedidately.
|
||||
|
|
|
@ -35,12 +35,12 @@ impl<T> RwMutex<T> {
|
|||
|
||||
/// Acquire a read mutex, and if there is a writer, this thread will sleep in the wait queue.
|
||||
pub fn read(&self) -> RwMutexReadGuard<T> {
|
||||
self.queue.wait_until(|| self.try_read(), None).unwrap()
|
||||
self.queue.wait_until(|| self.try_read())
|
||||
}
|
||||
|
||||
/// Acquire a write mutex, and if there is another writer or other readers, this thread will sleep in the wait queue.
|
||||
pub fn write(&self) -> RwMutexWriteGuard<T> {
|
||||
self.queue.wait_until(|| self.try_write(), None).unwrap()
|
||||
self.queue.wait_until(|| self.try_write())
|
||||
}
|
||||
|
||||
/// Try acquire a read mutex and return immediately if it fails.
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use super::SpinLock;
|
||||
use crate::arch::timer::add_timeout_list;
|
||||
use crate::config::TIMER_FREQ;
|
||||
use crate::error::Error;
|
||||
use crate::prelude::*;
|
||||
use alloc::{collections::VecDeque, sync::Arc};
|
||||
use bitflags::bitflags;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
@ -37,15 +35,29 @@ impl WaitQueue {
|
|||
///
|
||||
/// By taking a condition closure, his wait-wakeup mechanism becomes
|
||||
/// more efficient and robust.
|
||||
///
|
||||
/// The only error result is Error::TIMEOUT, which means the timeout is readched
|
||||
/// and the condition returns false.
|
||||
pub fn wait_until<F, R>(&self, mut cond: F, timeout: Option<&Duration>) -> Result<R>
|
||||
pub fn wait_until<F, R>(&self, cond: F) -> R
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
self.do_wait(cond, None).unwrap()
|
||||
}
|
||||
|
||||
/// Wait until some condition returns Some(_), or a given timeout is reached. If
|
||||
/// the condition does not becomes Some(_) before the timeout is reached, the
|
||||
/// function will return None.
|
||||
pub fn wait_until_or_timeout<F, R>(&self, cond: F, timeout: &Duration) -> Option<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
self.do_wait(cond, Some(timeout))
|
||||
}
|
||||
|
||||
fn do_wait<F, R>(&self, mut cond: F, timeout: Option<&Duration>) -> Option<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
if let Some(res) = cond() {
|
||||
return Ok(res);
|
||||
return Some(res);
|
||||
}
|
||||
|
||||
let waiter = Arc::new(Waiter::new());
|
||||
|
@ -53,12 +65,12 @@ impl WaitQueue {
|
|||
|
||||
let timer_callback = timeout.map(|timeout| {
|
||||
let remaining_ticks = {
|
||||
let ms_per_tick = 1000 / TIMER_FREQ;
|
||||
|
||||
// FIXME: We currently require 1000 to be a multiple of TIMER_FREQ, but
|
||||
// this may not hold true in the future, because TIMER_FREQ can be greater
|
||||
// than 1000. Then, the code need to be refactored.
|
||||
debug_assert!(ms_per_tick * TIMER_FREQ == 1000);
|
||||
const_assert!(1000 % TIMER_FREQ == 0);
|
||||
|
||||
let ms_per_tick = 1000 / TIMER_FREQ;
|
||||
|
||||
// The ticks should be equal to or greater than timeout
|
||||
(timeout.as_millis() as u64 + ms_per_tick - 1) / ms_per_tick
|
||||
|
@ -81,11 +93,11 @@ impl WaitQueue {
|
|||
timer_callback.cancel();
|
||||
}
|
||||
|
||||
return Ok(res);
|
||||
return Some(res);
|
||||
};
|
||||
|
||||
if let Some(ref timer_callback) = timer_callback && timer_callback.is_expired() {
|
||||
return Err(Error::TimeOut);
|
||||
return None;
|
||||
}
|
||||
|
||||
waiter.wait();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -187,7 +187,6 @@ impl From<jinux_frame::Error> for Error {
|
|||
jinux_frame::Error::IoError => Error::new(Errno::EIO),
|
||||
jinux_frame::Error::NotEnoughResources => Error::new(Errno::EBUSY),
|
||||
jinux_frame::Error::PageFault => Error::new(Errno::EFAULT),
|
||||
jinux_frame::Error::TimeOut => Error::new(Errno::ETIME),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::events::{Events, EventsFilter};
|
||||
use super::{Events, EventsFilter};
|
||||
|
||||
crate::bitflags! {
|
||||
pub struct IoEvents: u32 {
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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::*;
|
||||
|
||||
|
|
|
@ -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::*;
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::events::IoEvents;
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::Poller;
|
||||
|
||||
use super::*;
|
||||
|
||||
|
|
|
@ -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()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::file_table::FileDescripter;
|
||||
use super::utils::IoEvents;
|
||||
use crate::events::IoEvents;
|
||||
use crate::prelude::*;
|
||||
|
||||
mod epoll_file;
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
//! Opend File Handle
|
||||
|
||||
use crate::events::Observer;
|
||||
use crate::fs::utils::{AccessMode, IoEvents, IoctlCmd, Metadata, Poller, SeekFrom, StatusFlags};
|
||||
use crate::events::{IoEvents, Observer};
|
||||
use crate::fs::utils::{AccessMode, IoctlCmd, Metadata, SeekFrom, StatusFlags};
|
||||
use crate::net::socket::Socket;
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::Poller;
|
||||
|
||||
use core::any::Any;
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::events::IoEvents;
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::Poller;
|
||||
use jinux_rights::{Rights, TRights};
|
||||
|
||||
use super::*;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use crate::events::Observer;
|
||||
use crate::events::{IoEvents, Observer};
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::Poller;
|
||||
|
||||
use super::file_handle::FileLike;
|
||||
use super::utils::{
|
||||
AccessMode, Consumer, InodeMode, InodeType, IoEvents, Metadata, Poller, Producer, StatusFlags,
|
||||
};
|
||||
use super::utils::{AccessMode, Consumer, InodeMode, InodeType, Metadata, Producer, StatusFlags};
|
||||
|
||||
pub struct PipeReader {
|
||||
consumer: Consumer<u8>,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -2,11 +2,13 @@ use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
|||
use jinux_rights_proc::require;
|
||||
use ringbuf::{HeapConsumer as HeapRbConsumer, HeapProducer as HeapRbProducer, HeapRb};
|
||||
|
||||
use crate::events::IoEvents;
|
||||
use crate::events::Observer;
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::{Pollee, Poller};
|
||||
use jinux_rights::{Read, ReadOp, TRights, Write, WriteOp};
|
||||
|
||||
use super::{IoEvents, Pollee, Poller, StatusFlags};
|
||||
use super::StatusFlags;
|
||||
|
||||
/// A unidirectional communication channel, intended to implement IPC, e.g., pipe,
|
||||
/// unix domain sockets, etc.
|
||||
|
@ -153,7 +155,7 @@ impl<T: Copy> Producer<T> {
|
|||
let events = self.poll(mask, Some(&poller));
|
||||
if events.is_empty() {
|
||||
// FIXME: should channel deal with timeout?
|
||||
poller.wait_interruptible(None)?;
|
||||
poller.wait()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -242,7 +244,7 @@ impl<T: Copy> Consumer<T> {
|
|||
let events = self.poll(mask, Some(&poller));
|
||||
if events.is_empty() {
|
||||
// FIXME: should channel have timeout?
|
||||
poller.wait_interruptible(None)?;
|
||||
poller.wait()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use crate::fs::utils::{IoEvents, Poller};
|
||||
use crate::events::IoEvents;
|
||||
use crate::net::iface::Iface;
|
||||
use crate::net::iface::IpEndpoint;
|
||||
use crate::net::iface::{AnyBoundSocket, AnyUnboundSocket};
|
||||
|
@ -8,6 +8,7 @@ use crate::net::poll_ifaces;
|
|||
use crate::net::socket::ip::always_some::AlwaysSome;
|
||||
use crate::net::socket::ip::common::{bind_socket, get_ephemeral_endpoint};
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::Poller;
|
||||
|
||||
pub struct InitStream {
|
||||
inner: RwLock<Inner>,
|
||||
|
@ -152,7 +153,7 @@ impl InitStream {
|
|||
return_errno_with_message!(Errno::EAGAIN, "try connect again");
|
||||
} else {
|
||||
// FIXME: deal with connecting timeout
|
||||
poller.wait_interruptible(None)?;
|
||||
poller.wait()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use super::endpoint::Endpoint;
|
||||
use crate::fs::utils::{IoEvents, Poller};
|
||||
use crate::events::IoEvents;
|
||||
use crate::net::socket::{unix::addr::UnixSocketAddrBound, SockShutdownCmd};
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::Poller;
|
||||
|
||||
pub(super) struct Connected {
|
||||
local_endpoint: Arc<Endpoint>,
|
||||
|
|
|
@ -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::*,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ impl PosixThread {
|
|||
}
|
||||
|
||||
pub fn has_pending_signal(&self) -> bool {
|
||||
self.sig_queues.lock().is_empty()
|
||||
!self.sig_queues.lock().is_empty()
|
||||
}
|
||||
|
||||
pub fn enqueue_signal(&self, signal: Box<dyn Signal>) {
|
||||
|
|
|
@ -5,11 +5,12 @@ use super::process_group::ProcessGroup;
|
|||
use super::process_vm::user_heap::UserHeap;
|
||||
use super::process_vm::ProcessVm;
|
||||
use super::rlimit::ResourceLimits;
|
||||
use super::signal::constants::SIGCHLD;
|
||||
use super::signal::sig_disposition::SigDispositions;
|
||||
use super::signal::sig_mask::SigMask;
|
||||
use super::signal::sig_queues::SigQueues;
|
||||
use super::signal::signals::Signal;
|
||||
use super::signal::{SigEvents, SigEventsFilter};
|
||||
use super::signal::{Pauser, SigEvents, SigEventsFilter};
|
||||
use super::status::ProcessStatus;
|
||||
use super::{process_table, TermStatus};
|
||||
use crate::device::tty::get_n_tty;
|
||||
|
@ -20,7 +21,6 @@ use crate::fs::utils::FileCreationMask;
|
|||
use crate::prelude::*;
|
||||
use crate::thread::{allocate_tid, Thread};
|
||||
use crate::vm::vmar::Vmar;
|
||||
use jinux_frame::sync::WaitQueue;
|
||||
use jinux_rights::Full;
|
||||
|
||||
pub use builder::ProcessBuilder;
|
||||
|
@ -35,8 +35,8 @@ pub struct Process {
|
|||
pid: Pid,
|
||||
|
||||
process_vm: ProcessVm,
|
||||
/// wait for child status changed
|
||||
waiting_children: WaitQueue,
|
||||
/// Wait for child status changed
|
||||
children_pauser: Arc<Pauser>,
|
||||
|
||||
// Mutable Part
|
||||
/// The executable path.
|
||||
|
@ -82,12 +82,20 @@ impl Process {
|
|||
sig_dispositions: Arc<Mutex<SigDispositions>>,
|
||||
resource_limits: ResourceLimits,
|
||||
) -> Self {
|
||||
let children_pauser = {
|
||||
let mut sigset = SigMask::new_full();
|
||||
// SIGCHID does not interrupt pauser. Child process will
|
||||
// resume paused parent when doing exit.
|
||||
sigset.remove_signal(SIGCHLD);
|
||||
Pauser::new_with_sigset(sigset)
|
||||
};
|
||||
|
||||
Self {
|
||||
pid,
|
||||
threads: Mutex::new(threads),
|
||||
executable_path: RwLock::new(executable_path),
|
||||
process_vm,
|
||||
waiting_children: WaitQueue::new(),
|
||||
children_pauser,
|
||||
status: Mutex::new(ProcessStatus::Uninit),
|
||||
parent: Mutex::new(parent),
|
||||
children: Mutex::new(BTreeMap::new()),
|
||||
|
@ -190,8 +198,8 @@ impl Process {
|
|||
&self.children
|
||||
}
|
||||
|
||||
pub fn waiting_children(&self) -> &WaitQueue {
|
||||
&self.waiting_children
|
||||
pub fn children_pauser(&self) -> &Arc<Pauser> {
|
||||
&self.children_pauser
|
||||
}
|
||||
|
||||
// *********** Process group ***********
|
||||
|
@ -252,7 +260,7 @@ impl Process {
|
|||
}
|
||||
|
||||
pub fn has_pending_signal(&self) -> bool {
|
||||
self.sig_queues.lock().is_empty()
|
||||
!self.sig_queues.lock().is_empty()
|
||||
}
|
||||
|
||||
pub fn enqueue_signal(&self, signal: Box<dyn Signal>) {
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use core::time::Duration;
|
||||
|
||||
use jinux_frame::sync::WaitQueue;
|
||||
|
||||
use crate::events::{Events, EventsFilter, Observer};
|
||||
use crate::events::{Events, EventsFilter};
|
||||
use crate::prelude::*;
|
||||
use crate::process::posix_thread::PosixThreadExt;
|
||||
|
||||
use super::sig_mask::SigMask;
|
||||
use super::sig_num::SigNum;
|
||||
|
@ -35,101 +29,3 @@ impl EventsFilter<SigEvents> for SigEventsFilter {
|
|||
self.0.contains(event.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SigQueueObserver {
|
||||
wait_queue: WaitQueue,
|
||||
mask: SigMask,
|
||||
is_interrupted: AtomicBool,
|
||||
}
|
||||
|
||||
impl SigQueueObserver {
|
||||
pub fn new(mask: SigMask) -> Arc<Self> {
|
||||
let wait_queue = WaitQueue::new();
|
||||
Arc::new(Self {
|
||||
wait_queue,
|
||||
mask,
|
||||
is_interrupted: AtomicBool::new(false),
|
||||
})
|
||||
}
|
||||
|
||||
/// Wait until cond() returns Some(_).
|
||||
///
|
||||
/// If some signal is caught before cond() returns Some(_), it will returns EINTR.
|
||||
pub fn wait_until_interruptible<F, R>(
|
||||
self: &Arc<Self>,
|
||||
mut cond: F,
|
||||
timeout: Option<&Duration>,
|
||||
) -> Result<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
self.is_interrupted.store(false, Ordering::Release);
|
||||
|
||||
// Register observers on sigqueues
|
||||
|
||||
let observer = Arc::downgrade(self) as Weak<dyn Observer<SigEvents>>;
|
||||
let filter = SigEventsFilter::new(self.mask);
|
||||
|
||||
let current = current!();
|
||||
current.register_sigqueue_observer(observer.clone(), filter);
|
||||
|
||||
let current_thread = current_thread!();
|
||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||
posix_thread.register_sigqueue_observer(observer.clone(), filter);
|
||||
|
||||
// Some signal may come before we register observer, so we do another check here.
|
||||
if posix_thread.has_pending_signal() || current.has_pending_signal() {
|
||||
self.is_interrupted.store(true, Ordering::Release);
|
||||
}
|
||||
|
||||
enum Res<R> {
|
||||
Ok(R),
|
||||
Interrupted,
|
||||
}
|
||||
|
||||
let res = self.wait_queue.wait_until(
|
||||
|| {
|
||||
if let Some(res) = cond() {
|
||||
return Some(Res::Ok(res));
|
||||
}
|
||||
|
||||
if self.is_interrupted.load(Ordering::Acquire) {
|
||||
return Some(Res::Interrupted);
|
||||
}
|
||||
|
||||
None
|
||||
},
|
||||
timeout,
|
||||
)?;
|
||||
|
||||
current.unregiser_sigqueue_observer(&observer);
|
||||
posix_thread.unregiser_sigqueue_observer(&observer);
|
||||
|
||||
match res {
|
||||
Res::Ok(r) => Ok(r),
|
||||
Res::Interrupted => return_errno_with_message!(Errno::EINTR, "interrupted by signal"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait_until_uninterruptible<F, R>(&self, cond: F, timeout: Option<&Duration>) -> Result<R>
|
||||
where
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
Ok(self.wait_queue.wait_until(cond, timeout)?)
|
||||
}
|
||||
|
||||
pub fn wake_all(&self) {
|
||||
self.wait_queue.wake_all();
|
||||
}
|
||||
|
||||
pub fn wake_one(&self) {
|
||||
self.wait_queue.wake_one();
|
||||
}
|
||||
}
|
||||
|
||||
impl Observer<SigEvents> for SigQueueObserver {
|
||||
fn on_events(&self, events: &SigEvents) {
|
||||
self.is_interrupted.store(true, Ordering::Release);
|
||||
self.wait_queue.wake_all();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
use super::IoEvents;
|
||||
use crate::events::IoEvents;
|
||||
use crate::events::{Observer, Subject};
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::sig_mask::SigMask;
|
||||
use crate::process::signal::SigQueueObserver;
|
||||
use crate::process::signal::Pauser;
|
||||
|
||||
use core::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
|
||||
use core::time::Duration;
|
||||
|
@ -160,13 +159,15 @@ impl Poller {
|
|||
|
||||
/// Wait until there are any interesting events happen since last `wait`. The `wait`
|
||||
/// can be interrupted by signal.
|
||||
pub fn wait_interruptible(&self, timeout: Option<&Duration>) -> Result<()> {
|
||||
self.inner.event_counter.read_interruptible(timeout)?;
|
||||
pub fn wait(&self) -> Result<()> {
|
||||
self.inner.event_counter.read(None)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn wait_uninterruptible(&self, timeout: Option<&Duration>) -> Result<()> {
|
||||
self.inner.event_counter.read_uninterruptible(timeout)?;
|
||||
/// Wait until there are any interesting events happen since last `wait` or a given timeout
|
||||
/// is expired. This method can be interrupted by signal.
|
||||
pub fn wait_timeout(&self, timeout: &Duration) -> Result<()> {
|
||||
self.inner.event_counter.read(Some(timeout))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -200,53 +201,38 @@ impl Drop for Poller {
|
|||
/// A counter for wait and wakeup.
|
||||
struct EventCounter {
|
||||
counter: AtomicUsize,
|
||||
observer: Arc<SigQueueObserver>,
|
||||
pauser: Arc<Pauser>,
|
||||
}
|
||||
|
||||
impl EventCounter {
|
||||
pub fn new() -> Self {
|
||||
let observer = {
|
||||
// FIXME: choose the suitable mask
|
||||
let mask = SigMask::new_full();
|
||||
SigQueueObserver::new(mask)
|
||||
};
|
||||
let pauser = Pauser::new();
|
||||
|
||||
Self {
|
||||
counter: AtomicUsize::new(0),
|
||||
observer,
|
||||
pauser,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_interruptible(&self, timeout: Option<&Duration>) -> Result<usize> {
|
||||
self.observer.wait_until_interruptible(
|
||||
|| {
|
||||
let val = self.counter.swap(0, Ordering::Relaxed);
|
||||
if val > 0 {
|
||||
Some(val)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
timeout,
|
||||
)
|
||||
}
|
||||
pub fn read(&self, timeout: Option<&Duration>) -> Result<usize> {
|
||||
let cond = || {
|
||||
let val = self.counter.swap(0, Ordering::Relaxed);
|
||||
if val > 0 {
|
||||
Some(val)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
pub fn read_uninterruptible(&self, timeout: Option<&Duration>) -> Result<usize> {
|
||||
self.observer.wait_until_uninterruptible(
|
||||
|| {
|
||||
let val = self.counter.swap(0, Ordering::Relaxed);
|
||||
if val > 0 {
|
||||
Some(val)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
timeout,
|
||||
)
|
||||
if let Some(timeout) = timeout {
|
||||
self.pauser.pause_until_or_timeout(cond, timeout)
|
||||
} else {
|
||||
self.pauser.pause_until(cond)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self) {
|
||||
self.counter.fetch_add(1, Ordering::Relaxed);
|
||||
self.observer.wake_one();
|
||||
self.pauser.resume_one();
|
||||
}
|
||||
}
|
|
@ -26,51 +26,48 @@ pub fn wait_child_exit(
|
|||
wait_options: WaitOptions,
|
||||
) -> Result<(Pid, ExitCode)> {
|
||||
let current = current!();
|
||||
let (pid, exit_code) = current.waiting_children().wait_until(
|
||||
|| {
|
||||
let unwaited_children = current
|
||||
.children()
|
||||
.lock()
|
||||
.values()
|
||||
.filter(|child| match child_filter {
|
||||
ProcessFilter::Any => true,
|
||||
ProcessFilter::WithPid(pid) => child.pid() == pid,
|
||||
ProcessFilter::WithPgid(pgid) => child.pgid() == pgid,
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
let (pid, exit_code) = current.children_pauser().pause_until(|| {
|
||||
let unwaited_children = current
|
||||
.children()
|
||||
.lock()
|
||||
.values()
|
||||
.filter(|child| match child_filter {
|
||||
ProcessFilter::Any => true,
|
||||
ProcessFilter::WithPid(pid) => child.pid() == pid,
|
||||
ProcessFilter::WithPgid(pgid) => child.pgid() == pgid,
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if unwaited_children.is_empty() {
|
||||
return Some(Err(Error::with_message(
|
||||
Errno::ECHILD,
|
||||
"the process has no child to wait",
|
||||
)));
|
||||
if unwaited_children.is_empty() {
|
||||
return Some(Err(Error::with_message(
|
||||
Errno::ECHILD,
|
||||
"the process has no child to wait",
|
||||
)));
|
||||
}
|
||||
|
||||
// return immediately if we find a zombie child
|
||||
let zombie_child = unwaited_children.iter().find(|child| child.is_zombie());
|
||||
|
||||
if let Some(zombie_child) = zombie_child {
|
||||
let zombie_pid = zombie_child.pid();
|
||||
let exit_code = zombie_child.exit_code().unwrap();
|
||||
if wait_options.contains(WaitOptions::WNOWAIT) {
|
||||
// does not reap child, directly return
|
||||
return Some(Ok((zombie_pid, exit_code)));
|
||||
} else {
|
||||
let exit_code = reap_zombie_child(¤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 _))
|
||||
}
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
use crate::log_syscall_entry;
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::sig_mask::SigMask;
|
||||
use crate::process::signal::SigQueueObserver;
|
||||
use crate::process::signal::Pauser;
|
||||
|
||||
use super::{SyscallReturn, SYS_PAUSE};
|
||||
|
||||
pub fn sys_pause() -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_PAUSE);
|
||||
|
||||
let sigqueue_observer = {
|
||||
// FIXME: like sleep, paused thread can only be interrupted by signals that will call signal
|
||||
// handler or terminate current process
|
||||
let sigmask = SigMask::new_full();
|
||||
SigQueueObserver::new(sigmask)
|
||||
};
|
||||
// FIXME: like sleep, paused thread can only be interrupted by signals that will call signal
|
||||
// handler or terminate current process
|
||||
let pauser = Pauser::new();
|
||||
|
||||
sigqueue_observer.wait_until_interruptible(|| None, None)?;
|
||||
pauser.pause_until(|| None)?;
|
||||
|
||||
unreachable!("[Internal Error] pause should always return EINTR");
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use core::cell::Cell;
|
||||
use core::time::Duration;
|
||||
|
||||
use crate::events::IoEvents;
|
||||
use crate::fs::file_table::FileDescripter;
|
||||
use crate::fs::utils::{IoEvents, Poller};
|
||||
use crate::log_syscall_entry;
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::Poller;
|
||||
use crate::util::{read_val_from_user, write_val_to_user};
|
||||
|
||||
use super::SyscallReturn;
|
||||
|
@ -91,7 +92,11 @@ pub fn do_poll(poll_fds: &[PollFd], timeout: Option<Duration>) -> Result<usize>
|
|||
return Ok(0);
|
||||
}
|
||||
|
||||
poller.wait_interruptible(timeout.as_ref())?;
|
||||
if let Some(timeout) = timeout.as_ref() {
|
||||
poller.wait_timeout(timeout)?;
|
||||
} else {
|
||||
poller.wait()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue