From ab9941263b6896f5d0e5900da51a406d657630b6 Mon Sep 17 00:00:00 2001 From: Ruihan Li Date: Sun, 30 Jun 2024 22:38:28 +0800 Subject: [PATCH] Avoid duplicate `wait_events` methods --- kernel/aster-nix/src/fs/epoll/epoll_file.rs | 12 +++-- kernel/aster-nix/src/fs/file_handle.rs | 8 +-- .../aster-nix/src/fs/inode_handle/dyn_cap.rs | 8 ++- kernel/aster-nix/src/fs/pipe.rs | 25 +++++---- .../src/net/socket/ip/datagram/mod.rs | 34 +++--------- .../aster-nix/src/net/socket/ip/stream/mod.rs | 34 +++--------- .../src/net/socket/unix/stream/socket.rs | 22 ++++---- .../src/net/socket/vsock/stream/socket.rs | 53 ++++--------------- kernel/aster-nix/src/process/signal/mod.rs | 2 +- kernel/aster-nix/src/process/signal/poll.rs | 50 +++++++++++++++++ kernel/aster-nix/src/syscall/eventfd.rs | 12 +++-- 11 files changed, 126 insertions(+), 134 deletions(-) diff --git a/kernel/aster-nix/src/fs/epoll/epoll_file.rs b/kernel/aster-nix/src/fs/epoll/epoll_file.rs index 7e56900d6..d1b1ff6cf 100644 --- a/kernel/aster-nix/src/fs/epoll/epoll_file.rs +++ b/kernel/aster-nix/src/fs/epoll/epoll_file.rs @@ -12,7 +12,7 @@ use super::*; use crate::{ events::Observer, fs::{file_handle::FileLike, file_table::FdEvents, utils::IoctlCmd}, - process::signal::{Pollee, Poller}, + process::signal::{Pollable, Pollee, Poller}, }; /// A file-like object that provides epoll API. @@ -321,6 +321,12 @@ impl Drop for EpollFile { } } +impl Pollable for EpollFile { + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + self.pollee.poll(mask, poller) + } +} + // Implement the common methods required by FileHandle impl FileLike for EpollFile { fn read(&self, buf: &mut [u8]) -> Result { @@ -335,10 +341,6 @@ impl FileLike for EpollFile { return_errno_with_message!(Errno::EINVAL, "epoll files do not support ioctl"); } - fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - self.pollee.poll(mask, poller) - } - fn register_observer( &self, observer: Weak>, diff --git a/kernel/aster-nix/src/fs/file_handle.rs b/kernel/aster-nix/src/fs/file_handle.rs index 2c95e1b25..f7eb600e5 100644 --- a/kernel/aster-nix/src/fs/file_handle.rs +++ b/kernel/aster-nix/src/fs/file_handle.rs @@ -12,11 +12,11 @@ use crate::{ }, net::socket::Socket, prelude::*, - process::{signal::Poller, Gid, Uid}, + process::{signal::Pollable, Gid, Uid}, }; /// The basic operations defined on a file -pub trait FileLike: Send + Sync + Any { +pub trait FileLike: Pollable + Send + Sync + Any { fn read(&self, buf: &mut [u8]) -> Result { return_errno_with_message!(Errno::EINVAL, "read is not supported"); } @@ -50,10 +50,6 @@ pub trait FileLike: Send + Sync + Any { return_errno_with_message!(Errno::EINVAL, "ioctl is not supported"); } - fn poll(&self, _mask: IoEvents, _poller: Option<&Poller>) -> IoEvents { - IoEvents::empty() - } - fn resize(&self, new_size: usize) -> Result<()> { return_errno_with_message!(Errno::EINVAL, "resize is not supported"); } diff --git a/kernel/aster-nix/src/fs/inode_handle/dyn_cap.rs b/kernel/aster-nix/src/fs/inode_handle/dyn_cap.rs index 2d872da65..a55eaa75f 100644 --- a/kernel/aster-nix/src/fs/inode_handle/dyn_cap.rs +++ b/kernel/aster-nix/src/fs/inode_handle/dyn_cap.rs @@ -4,7 +4,7 @@ use aster_rights::TRights; use inherit_methods_macro::inherit_methods; use super::*; -use crate::prelude::*; +use crate::{prelude::*, process::signal::Pollable}; impl InodeHandle { pub fn new( @@ -80,8 +80,12 @@ impl Clone for InodeHandle { } #[inherit_methods(from = "self.0")] -impl FileLike for InodeHandle { +impl Pollable for InodeHandle { fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents; +} + +#[inherit_methods(from = "self.0")] +impl FileLike for InodeHandle { fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result; fn status_flags(&self) -> StatusFlags; fn access_mode(&self) -> AccessMode; diff --git a/kernel/aster-nix/src/fs/pipe.rs b/kernel/aster-nix/src/fs/pipe.rs index a6c018b1c..8450a973a 100644 --- a/kernel/aster-nix/src/fs/pipe.rs +++ b/kernel/aster-nix/src/fs/pipe.rs @@ -9,7 +9,10 @@ use super::{ use crate::{ events::{IoEvents, Observer}, prelude::*, - process::{signal::Poller, Gid, Uid}, + process::{ + signal::{Pollable, Poller}, + Gid, Uid, + }, time::clocks::RealTimeCoarseClock, }; @@ -23,15 +26,17 @@ impl PipeReader { } } +impl Pollable for PipeReader { + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + self.consumer.poll(mask, poller) + } +} + impl FileLike for PipeReader { fn read(&self, buf: &mut [u8]) -> Result { self.consumer.read(buf) } - fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - self.consumer.poll(mask, poller) - } - fn status_flags(&self) -> StatusFlags { self.consumer.status_flags() } @@ -90,15 +95,17 @@ impl PipeWriter { } } +impl Pollable for PipeWriter { + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + self.producer.poll(mask, poller) + } +} + impl FileLike for PipeWriter { fn write(&self, buf: &[u8]) -> Result { self.producer.write(buf) } - fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - self.producer.poll(mask, poller) - } - fn status_flags(&self) -> StatusFlags { self.producer.status_flags() } diff --git a/kernel/aster-nix/src/net/socket/ip/datagram/mod.rs b/kernel/aster-nix/src/net/socket/ip/datagram/mod.rs index 5ffd09535..226cba514 100644 --- a/kernel/aster-nix/src/net/socket/ip/datagram/mod.rs +++ b/kernel/aster-nix/src/net/socket/ip/datagram/mod.rs @@ -21,7 +21,7 @@ use crate::{ }, }, prelude::*, - process::signal::{Pollee, Poller}, + process::signal::{Pollable, Pollee, Poller}, util::IoVec, }; @@ -170,28 +170,6 @@ impl DatagramSocket { sent_bytes } - // TODO: Support timeout - fn wait_events(&self, mask: IoEvents, mut cond: F) -> Result - where - F: FnMut() -> Result, - { - let poller = Poller::new(); - - loop { - match cond() { - Err(err) if err.error() == Errno::EAGAIN => (), - result => return result, - }; - - let events = self.poll(mask, Some(&poller)); - if !events.is_empty() { - continue; - } - - poller.wait()?; - } - } - fn update_io_events(&self) { let inner = self.inner.read(); let Inner::Bound(bound_datagram) = inner.as_ref() else { @@ -201,6 +179,12 @@ impl DatagramSocket { } } +impl Pollable for DatagramSocket { + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + self.pollee.poll(mask, poller) + } +} + impl FileLike for DatagramSocket { fn read(&self, buf: &mut [u8]) -> Result { // TODO: set correct flags @@ -223,10 +207,6 @@ impl FileLike for DatagramSocket { self.try_send(buf, &remote, flags) } - fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - self.pollee.poll(mask, poller) - } - fn as_socket(self: Arc) -> Option> { Some(self) } diff --git a/kernel/aster-nix/src/net/socket/ip/stream/mod.rs b/kernel/aster-nix/src/net/socket/ip/stream/mod.rs index 1fa831eea..878a8158c 100644 --- a/kernel/aster-nix/src/net/socket/ip/stream/mod.rs +++ b/kernel/aster-nix/src/net/socket/ip/stream/mod.rs @@ -34,7 +34,7 @@ use crate::{ }, }, prelude::*, - process::signal::{Pollee, Poller}, + process::signal::{Pollable, Pollee, Poller}, util::IoVec, }; @@ -319,28 +319,6 @@ impl StreamSocket { } } - // TODO: Support timeout - fn wait_events(&self, mask: IoEvents, mut cond: F) -> Result - where - F: FnMut() -> Result, - { - let poller = Poller::new(); - - loop { - match cond() { - Err(err) if err.error() == Errno::EAGAIN => (), - result => return result, - }; - - let events = self.poll(mask, Some(&poller)); - if !events.is_empty() { - continue; - } - - poller.wait()?; - } - } - #[must_use] fn update_io_events(&self) -> bool { let state = self.state.read(); @@ -359,6 +337,12 @@ impl StreamSocket { } } +impl Pollable for StreamSocket { + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + self.pollee.poll(mask, poller) + } +} + impl FileLike for StreamSocket { fn read(&self, buf: &mut [u8]) -> Result { // TODO: Set correct flags @@ -372,10 +356,6 @@ impl FileLike for StreamSocket { self.send(buf, flags) } - fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - self.pollee.poll(mask, poller) - } - fn status_flags(&self) -> StatusFlags { // TODO: when we fully support O_ASYNC, return the flag if self.is_nonblocking() { diff --git a/kernel/aster-nix/src/net/socket/unix/stream/socket.rs b/kernel/aster-nix/src/net/socket/unix/stream/socket.rs index 05dd3f04b..acf39ce43 100644 --- a/kernel/aster-nix/src/net/socket/unix/stream/socket.rs +++ b/kernel/aster-nix/src/net/socket/unix/stream/socket.rs @@ -23,7 +23,7 @@ use crate::{ SockShutdownCmd, Socket, }, prelude::*, - process::signal::Poller, + process::signal::{Pollable, Poller}, util::IoVec, }; @@ -103,6 +103,17 @@ impl UnixStreamSocket { } } +impl Pollable for UnixStreamSocket { + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + let inner = self.0.read(); + match &*inner { + State::Init(init) => init.poll(mask, poller), + State::Listen(listen) => listen.poll(mask, poller), + State::Connected(connected) => connected.poll(mask, poller), + } + } +} + impl FileLike for UnixStreamSocket { fn as_socket(self: Arc) -> Option> { Some(self) @@ -120,15 +131,6 @@ impl FileLike for UnixStreamSocket { self.send(buf, flags) } - fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - let inner = self.0.read(); - match &*inner { - State::Init(init) => init.poll(mask, poller), - State::Listen(listen) => listen.poll(mask, poller), - State::Connected(connected) => connected.poll(mask, poller), - } - } - fn status_flags(&self) -> StatusFlags { let inner = self.0.read(); let is_nonblocking = match &*inner { diff --git a/kernel/aster-nix/src/net/socket/vsock/stream/socket.rs b/kernel/aster-nix/src/net/socket/vsock/stream/socket.rs index 37e72f4d5..dfcc82b57 100644 --- a/kernel/aster-nix/src/net/socket/vsock/stream/socket.rs +++ b/kernel/aster-nix/src/net/socket/vsock/stream/socket.rs @@ -14,7 +14,7 @@ use crate::{ MessageHeader, SendRecvFlags, SockShutdownCmd, Socket, SocketAddr, }, prelude::*, - process::signal::Poller, + process::signal::{Pollable, Poller}, util::IoVec, }; @@ -53,39 +53,6 @@ impl VsockStreamSocket { self.is_nonblocking.store(nonblocking, Ordering::Relaxed); } - // TODO: Support timeout - fn wait_events(&self, mask: IoEvents, mut cond: F) -> Result - where - F: FnMut() -> Result, - { - let poller = Poller::new(); - - loop { - match cond() { - Err(err) if err.error() == Errno::EAGAIN => (), - result => { - if let Err(e) = result { - debug!("The result of cond() is Error: {:?}", e); - } - return result; - } - }; - - let events = match &*self.status.read() { - Status::Init(init) => init.poll(mask, Some(&poller)), - Status::Listen(listen) => listen.poll(mask, Some(&poller)), - Status::Connected(connected) => connected.poll(mask, Some(&poller)), - }; - - debug!("events: {:?}", events); - if !events.is_empty() { - continue; - } - - poller.wait()?; - } - } - fn try_accept(&self) -> Result<(Arc, SocketAddr)> { let listen = match &*self.status.read() { Status::Listen(listen) => listen.clone(), @@ -155,6 +122,16 @@ impl VsockStreamSocket { } } +impl Pollable for VsockStreamSocket { + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + match &*self.status.read() { + Status::Init(init) => init.poll(mask, poller), + Status::Listen(listen) => listen.poll(mask, poller), + Status::Connected(connected) => connected.poll(mask, poller), + } + } +} + impl FileLike for VsockStreamSocket { fn as_socket(self: Arc) -> Option> { Some(self) @@ -170,14 +147,6 @@ impl FileLike for VsockStreamSocket { self.send(buf, SendRecvFlags::empty()) } - fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - match &*self.status.read() { - Status::Init(init) => init.poll(mask, poller), - Status::Listen(listen) => listen.poll(mask, poller), - Status::Connected(connected) => connected.poll(mask, poller), - } - } - fn status_flags(&self) -> StatusFlags { if self.is_nonblocking() { StatusFlags::O_NONBLOCK diff --git a/kernel/aster-nix/src/process/signal/mod.rs b/kernel/aster-nix/src/process/signal/mod.rs index 38a727a35..400ba3632 100644 --- a/kernel/aster-nix/src/process/signal/mod.rs +++ b/kernel/aster-nix/src/process/signal/mod.rs @@ -20,7 +20,7 @@ use c_types::{siginfo_t, ucontext_t}; pub use events::{SigEvents, SigEventsFilter}; use ostd::{cpu::UserContext, user::UserContextApi}; pub use pauser::Pauser; -pub use poll::{Pollee, Poller}; +pub use poll::{Pollable, Pollee, Poller}; use sig_action::{SigAction, SigActionFlags, SigDefaultAction}; use sig_mask::SigMask; use sig_num::SigNum; diff --git a/kernel/aster-nix/src/process/signal/poll.rs b/kernel/aster-nix/src/process/signal/poll.rs index f14a1c313..1696211bb 100644 --- a/kernel/aster-nix/src/process/signal/poll.rs +++ b/kernel/aster-nix/src/process/signal/poll.rs @@ -242,3 +242,53 @@ impl EventCounter { self.pauser.resume_one(); } } + +/// The `Pollable` trait allows for waiting for events and performing event-based operations. +/// +/// Implementors are required to provide a method, [`Pollable::poll`], which is usually implemented +/// by simply calling [`Pollee::poll`] on the internal [`Pollee`]. This trait provides another +/// method, [`Pollable::wait_events`], to allow waiting for events and performing operations +/// according to the events. +/// +/// This trait is added instead of creating a new method in [`Pollee`] because sometimes we do not +/// have access to the internal [`Pollee`], but there is a method that provides the same sematics +/// as [`Pollee::poll`] and we need to perform event-based operations using that method. +pub trait Pollable { + /// Returns the interesting events if there are any, or waits for them to happen if there are + /// none. + /// + /// This method has the same semantics as [`Pollee::poll`]. + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents; + + /// Waits for events and performs event-based operations. + /// + /// If a call to `cond()` succeeds or fails with an error code other than `EAGAIN`, the method + /// will return whatever the call to `cond()` returns. Otherwise, the method will wait for some + /// interesting events specified in `mask` to happen and try again. + /// + /// The user must ensure that a call to `cond()` does not fail with `EAGAIN` when the + /// interesting events occur. However, it is allowed to have spurious `EAGAIN` failures due to + /// race conditions where the events are consumed by another thread. + fn wait_events(&self, mask: IoEvents, mut cond: F) -> Result + where + Self: Sized, + F: FnMut() -> Result, + { + let poller = Poller::new(); + + loop { + match cond() { + Err(err) if err.error() == Errno::EAGAIN => (), + result => return result, + }; + + let events = self.poll(mask, Some(&poller)); + if !events.is_empty() { + continue; + } + + // TODO: Support timeout + poller.wait()?; + } + } +} diff --git a/kernel/aster-nix/src/syscall/eventfd.rs b/kernel/aster-nix/src/syscall/eventfd.rs index f4225f0e1..37404ed22 100644 --- a/kernel/aster-nix/src/syscall/eventfd.rs +++ b/kernel/aster-nix/src/syscall/eventfd.rs @@ -24,7 +24,7 @@ use crate::{ }, prelude::*, process::{ - signal::{Pauser, Pollee, Poller}, + signal::{Pauser, Pollable, Pollee, Poller}, Gid, Uid, }, time::clocks::RealTimeClock, @@ -150,6 +150,12 @@ impl EventFile { } } +impl Pollable for EventFile { + fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { + self.pollee.poll(mask, poller) + } +} + impl FileLike for EventFile { fn read(&self, buf: &mut [u8]) -> Result { let read_len = core::mem::size_of::(); @@ -216,10 +222,6 @@ impl FileLike for EventFile { Ok(write_len) } - fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents { - self.pollee.poll(mask, poller) - } - fn status_flags(&self) -> StatusFlags { if self.is_nonblocking() { StatusFlags::O_NONBLOCK