diff --git a/litebox/src/fs/errors.rs b/litebox/src/fs/errors.rs index e74b331c3..459caaea2 100644 --- a/litebox/src/fs/errors.rs +++ b/litebox/src/fs/errors.rs @@ -1,20 +1,20 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -//! Possible errors from [`FileSystem`] +//! Possible errors from [`Resolver`] #[expect( unused_imports, reason = "used for doc string links to work out, but not for code" )] -use super::FileSystem; +use super::resolver::Resolver; use thiserror::Error; // XXX(jayb): We probably need to introduce a notion of `Stale` to many/most of these errors, in // order to more correctly support network-attached file systems. -/// Possible errors from [`FileSystem::open`] +/// Possible errors from [`Resolver::open`] #[non_exhaustive] #[derive(Error, Debug)] pub enum OpenError { @@ -34,12 +34,12 @@ pub enum OpenError { PathError(#[from] PathError), } -/// Possible errors from [`FileSystem::close`] +/// Possible errors from [`Resolver::close`] #[non_exhaustive] #[derive(Error, Debug)] pub enum CloseError {} -/// Possible errors from [`FileSystem::read`] +/// Possible errors from [`Resolver::read`] #[non_exhaustive] #[derive(Error, Debug)] pub enum ReadError { @@ -53,7 +53,7 @@ pub enum ReadError { Io, } -/// Possible errors from [`FileSystem::write`] +/// Possible errors from [`Resolver::write`] #[non_exhaustive] #[derive(Error, Debug)] pub enum WriteError { @@ -67,7 +67,7 @@ pub enum WriteError { Io, } -/// Possible errors from [`FileSystem::seek`] +/// Possible errors from [`Resolver::seek`] #[non_exhaustive] #[derive(Error, Debug)] pub enum SeekError { @@ -83,7 +83,7 @@ pub enum SeekError { Io, } -/// Possible errors from [`FileSystem::truncate`] +/// Possible errors from [`Resolver::truncate`] #[derive(Error, Debug)] pub enum TruncateError { #[error("fd has been closed already")] @@ -98,7 +98,7 @@ pub enum TruncateError { Io, } -/// Possible errors from [`FileSystem::chmod`] +/// Possible errors from [`Resolver::chmod`] #[non_exhaustive] #[derive(Error, Debug)] pub enum ChmodError { @@ -115,7 +115,7 @@ pub enum ChmodError { PathError(#[from] PathError), } -/// Possible errors from [`FileSystem::chown`] +/// Possible errors from [`Resolver::chown`] #[non_exhaustive] #[derive(Error, Debug)] pub enum ChownError { @@ -132,7 +132,7 @@ pub enum ChownError { PathError(#[from] PathError), } -/// Possible errors from [`FileSystem::unlink`] +/// Possible errors from [`Resolver::unlink`] #[non_exhaustive] #[derive(Error, Debug)] pub enum UnlinkError { @@ -148,7 +148,7 @@ pub enum UnlinkError { PathError(#[from] PathError), } -/// Possible errors from [`FileSystem::mkdir`] +/// Possible errors from [`Resolver::mkdir`] #[non_exhaustive] #[derive(Error, Debug)] pub enum MkdirError { @@ -164,7 +164,7 @@ pub enum MkdirError { PathError(#[from] PathError), } -/// Possible errors from [`FileSystem::rmdir`] +/// Possible errors from [`Resolver::rmdir`] #[non_exhaustive] #[derive(Error, Debug)] pub enum RmdirError { @@ -186,7 +186,7 @@ pub enum RmdirError { PathError(#[from] PathError), } -/// Possible errors from [`FileSystem::read_dir`] +/// Possible errors from [`Resolver::read_dir`] #[non_exhaustive] #[derive(Error, Debug)] pub enum ReadDirError { @@ -198,7 +198,7 @@ pub enum ReadDirError { Io, } -/// Possible errors from [`FileSystem::file_status`] +/// Possible errors from [`Resolver::file_status`] #[non_exhaustive] #[derive(Error, Debug)] pub enum FileStatusError { diff --git a/litebox/src/fs/mod.rs b/litebox/src/fs/mod.rs index fdeabced2..285363b17 100644 --- a/litebox/src/fs/mod.rs +++ b/litebox/src/fs/mod.rs @@ -2,11 +2,12 @@ // Licensed under the MIT license. //! File-system related functionality +//! +//! A file-system consists of a [`Resolver`](resolver::Resolver) that works alongside one or more +//! [`Backend`](backend::Backend)s. Such backends can be composed together: mounted at distinct +//! paths via the [`Composer`](composer::Composer), or stacked as a writable upper over immutable +//! lowers via the [`Overlay`](overlay::Overlay). -use crate::fd::{FdEnabledSubsystem, TypedFd}; -use crate::path; - -use alloc::vec::Vec; use bitflags::bitflags; use core::ffi::c_uint; @@ -26,134 +27,6 @@ pub mod tar_ro; #[cfg(test)] mod tests; -use errors::{ - ChmodError, ChownError, CloseError, FileStatusError, MkdirError, OpenError, ReadDirError, - ReadError, RmdirError, SeekError, TruncateError, UnlinkError, WriteError, -}; - -/// A private module, to help support writing sealed traits. This module should _itself_ never be -/// made public. -mod private { - /// A trait to help seal the main `FileSystem` trait. - /// - /// This trait is explicitly public, but unnameable, thereby preventing code outside this crate - /// from implementing this trait. - pub trait Sealed {} -} - -/// A `FileSystem` provides access to all file-system related functionality provided by LiteBox. -/// -/// The design of the file-system is chosen by the specific underlying implementation of this trait -/// (e.g., [`resolver::Resolver`] over a [`backend::Backend`]), each of which are parametric in the -/// platform they run on. -/// However, users of any of these file systems might find benefit in having most of their code -/// depend on this trait, rather than on any individual file system. -pub trait FileSystem: private::Sealed + FdEnabledSubsystem { - /// Opens a file - /// - /// The `mode` is only significant when creating a file - fn open( - &self, - path: impl path::Arg, - flags: OFlags, - mode: Mode, - ) -> Result, OpenError>; - - /// Close the file at `fd`. - /// - /// Future operations on the `fd` will start to return `ClosedFd` errors. - fn close(&self, fd: &TypedFd) -> Result<(), CloseError>; - - /// Read from a file descriptor at `offset` into a buffer - /// - /// If `offset` is None, the read will start at the current file offset and update the file offset - /// to the end of the read. - /// If `offset` is Some, the file offset is not changed. - fn read( - &self, - fd: &TypedFd, - buf: &mut [u8], - offset: Option, - ) -> Result; - - /// Write from a buffer to a file descriptor at `offset` - /// - /// If `offset` is None, the write will start at the current file offset and update the file offset - /// to the end of the write. - /// If `offset` is Some, the file offset is not changed. - fn write( - &self, - fd: &TypedFd, - buf: &[u8], - offset: Option, - ) -> Result; - - /// Reposition read/write file offset, by changing it to `offset` relative to `whence`. - /// - /// Returns the resulting offset (in bytes from start of file) on success. - fn seek( - &self, - fd: &TypedFd, - offset: isize, - whence: SeekWhence, - ) -> Result; - - /// Truncate the file to the specified length. - /// - /// If shorter than existing size, extra data is lost. If longer than existing size, resize by - /// adding `\0`s. - /// - /// If `reset_offset` is true, the offset is reset to zero; otherwise, it remains unchanged. - fn truncate( - &self, - fd: &TypedFd, - length: usize, - reset_offset: bool, - ) -> Result<(), TruncateError>; - - /// Change the permissions of a file - fn chmod(&self, path: impl path::Arg, mode: Mode) -> Result<(), ChmodError>; - - /// Change the owner of a file - fn chown( - &self, - path: impl path::Arg, - user: Option, - group: Option, - ) -> Result<(), ChownError>; - - /// Unlink a file - fn unlink(&self, path: impl path::Arg) -> Result<(), UnlinkError>; - - /// Create a new directory - fn mkdir(&self, path: impl path::Arg, mode: Mode) -> Result<(), MkdirError>; - - /// Remove a directory - fn rmdir(&self, path: impl path::Arg) -> Result<(), RmdirError>; - - /// Read directory entries from a directory file descriptor. - /// - /// Returns a list of file/directory names (explicitly _not_ including `.` or `..`). - fn read_dir(&self, fd: &TypedFd) -> Result, ReadDirError>; - - /// Obtain the status of a file/directory/... on the file-system. - fn file_status(&self, path: impl path::Arg) -> Result; - - /// Equivalent to [`Self::file_status`], but open an open `fd` instead. - fn fd_file_status(&self, fd: &TypedFd) -> Result; - - /// Get static backing data for a file, if available and supported. - /// - /// This method returns the (entire) underlying static byte slice if the file's contents are - /// backed by borrowed static data (e.g., set up via [`in_mem::InitialNode::File`]). - /// - /// Returns `None` if indicating no static backing data is available/supported. - #[expect(unused_variables, reason = "default body, non-underscored param names")] - fn get_static_backing_data(&self, fd: &TypedFd) -> Option<&'static [u8]> { - None - } -} - bitflags! { /// `S_I*` constants for open, ... #[repr(transparent)] @@ -196,7 +69,7 @@ bitflags! { /// Types of files on a file-system. /// -/// See [`FileSystem::file_status`]. +/// See [`resolver::Resolver::file_status`]. #[derive(Debug, PartialEq, Eq, Clone)] #[non_exhaustive] pub enum FileType { @@ -291,7 +164,7 @@ bitflags! { } } -/// The `whence` directive to [`FileSystem::seek`] +/// The `whence` directive to [`resolver::Resolver::seek`] #[derive(Copy, Clone)] pub enum SeekWhence { /// The file offset is set to `offset` bytes. @@ -344,7 +217,7 @@ pub struct NodeInfo { pub rdev: Option, } -/// Directory entries returned by [`FileSystem::read_dir`] +/// Directory entries returned by [`resolver::Resolver::read_dir`] #[derive(Debug)] #[non_exhaustive] pub struct DirEntry { diff --git a/litebox/src/fs/nine_p/tests.rs b/litebox/src/fs/nine_p/tests.rs index 191b126e9..58456aed6 100644 --- a/litebox/src/fs/nine_p/tests.rs +++ b/litebox/src/fs/nine_p/tests.rs @@ -14,7 +14,7 @@ use crate::fs::errors::{ }; use crate::fs::inode_allocator::InodeAllocator; use crate::fs::resolver::Resolver; -use crate::fs::{FileSystem as _, Mode, OFlags}; +use crate::fs::{Mode, OFlags}; use crate::platform::mock::MockPlatform; use super::{NineP, transport}; @@ -514,7 +514,7 @@ impl transport::Write for BrokenTransport { } } -/// Helper: connect to a diod server and build a `FileSystem` backed by +/// Helper: connect to a diod server and build a `Resolver` backed by /// `BrokenTransport` that will break after `allowed_writes` write calls. /// /// The version handshake and attach each consume one write, so diff --git a/litebox/src/fs/resolver.rs b/litebox/src/fs/resolver.rs index 9b6802e88..90bd37a8e 100644 --- a/litebox/src/fs/resolver.rs +++ b/litebox/src/fs/resolver.rs @@ -26,9 +26,9 @@ use super::{ /// The north-facing filesystem entry point, generic over a [`Backend`](super::backend::Backend). // NOTE(jayb): the `Context` separation is in preparation for multi-process support; specifically, -// each guest process would have their own `Context` but would share the resolver. Currently, since -// we are using the `FileSystem` trait for migration, the interfaces do not show the full actual -// separated context support (yet!). Nonetheless, future changes will separate this out. +// each guest process would have their own `Context` but would share the resolver. Currently, the +// interfaces do not show the full actual separated context support (yet!); instead, callers share +// the single `migration_context` below. Nonetheless, future changes will separate this out. pub struct Resolver< Platform: sync::RawSyncPrimitivesProvider, Backend: super::backend::Backend + 'static, @@ -192,11 +192,6 @@ enum SearchScope { AndReadableTarget, } -impl - super::private::Sealed for Resolver -{ -} - impl Resolver { @@ -435,9 +430,12 @@ impl - super::FileSystem for Resolver + Resolver { - fn open( + /// Opens a file + /// + /// The `mode` is only significant when creating a file + pub fn open( &self, path: impl Arg, mut flags: OFlags, @@ -581,7 +579,10 @@ impl) -> Result<(), CloseError> { + /// Close the file at `fd`. + /// + /// Future operations on the `fd` will start to return `ClosedFd` errors. + pub fn close(&self, fd: &TypedFd) -> Result<(), CloseError> { let mut dt = self.litebox.descriptor_table_mut(); let removed = dt.remove(fd); drop(dt); @@ -591,7 +592,16 @@ impl, buf: &mut [u8], @@ -630,7 +640,16 @@ impl, buf: &[u8], @@ -675,7 +694,10 @@ impl, offset: isize, @@ -724,7 +746,13 @@ impl, length: usize, @@ -755,7 +783,8 @@ impl Result<(), ChmodError> { + /// Change the permissions of a file + pub fn chmod(&self, path: impl Arg, mode: Mode) -> Result<(), ChmodError> { let context = self.context_pre_context_management_changes(); let path = context.resolve(path)?; let handle = self @@ -767,7 +796,8 @@ impl, @@ -784,7 +814,8 @@ impl Result<(), UnlinkError> { + /// Unlink a file + pub fn unlink(&self, path: impl Arg) -> Result<(), UnlinkError> { let context = self.context_pre_context_management_changes(); let path = context.resolve(path)?; let Some((parent, name)) = @@ -808,7 +839,8 @@ impl Result<(), MkdirError> { + /// Create a new directory + pub fn mkdir(&self, path: impl Arg, mode: Mode) -> Result<(), MkdirError> { let context = self.context_pre_context_management_changes(); let path = context.resolve(path)?; let Some((parent, name)) = @@ -832,7 +864,8 @@ impl Result<(), RmdirError> { + /// Remove a directory + pub fn rmdir(&self, path: impl Arg) -> Result<(), RmdirError> { let context = self.context_pre_context_management_changes(); let path = context.resolve(path)?; let Some((parent, name)) = @@ -856,7 +889,10 @@ impl) -> Result, ReadDirError> { + /// Read directory entries from a directory file descriptor. + /// + /// Returns a list of file/directory names (explicitly _not_ including `.` or `..`). + pub fn read_dir(&self, fd: &TypedFd) -> Result, ReadDirError> { let entry = self .litebox .descriptor_table() @@ -888,7 +924,12 @@ impl Result { + /// Obtain the status of a file/directory/... on the file-system. + #[expect( + clippy::missing_panics_doc, + reason = "`CloseError` is uninhabited, so the internal close cannot fail" + )] + pub fn file_status(&self, path: impl Arg) -> Result { let fd = self .open(path, OFlags::PATH, Mode::empty()) .map_err(|error| match error { @@ -905,7 +946,8 @@ impl) -> Result { + /// Equivalent to [`Self::file_status`], but on an open `fd` instead. + pub fn fd_file_status(&self, fd: &TypedFd) -> Result { let entry = self .litebox .descriptor_table() @@ -915,7 +957,13 @@ impl) -> Option<&'static [u8]> { + /// Get static backing data for a file, if available and supported. + /// + /// This method returns the (entire) underlying static byte slice if the file's contents are + /// backed by borrowed static data (e.g., set up via [`super::in_mem::InitialNode::File`]). + /// + /// Returns `None` if no static backing data is available/supported. + pub fn get_static_backing_data(&self, fd: &TypedFd) -> Option<&'static [u8]> { let entry = self.litebox.descriptor_table().entry_handle(fd)?; let entry = entry.get_entry(); match &entry.entry.handle { diff --git a/litebox/src/fs/tests.rs b/litebox/src/fs/tests.rs index 9b2d12143..6a5cbd707 100644 --- a/litebox/src/fs/tests.rs +++ b/litebox/src/fs/tests.rs @@ -54,7 +54,7 @@ fn overlay_fs( mod in_mem { use crate::LiteBox; use crate::fs::in_mem; - use crate::fs::{FileSystem as _, Mode, OFlags}; + use crate::fs::{Mode, OFlags}; use crate::platform::mock::MockPlatform; use alloc::vec; use alloc::vec::Vec; @@ -1020,7 +1020,7 @@ mod in_mem { mod tar_ro { use crate::LiteBox; - use crate::fs::{FileSystem as _, Mode, OFlags}; + use crate::fs::{Mode, OFlags}; use crate::platform::mock::MockPlatform; use alloc::vec; use alloc::vec::Vec; @@ -1191,7 +1191,7 @@ mod tar_ro { mod overlay { use crate::LiteBox; use crate::fs::in_mem::{InMem, InitialNode}; - use crate::fs::{FileSystem as _, FileType, Mode, OFlags, UserInfo}; + use crate::fs::{FileType, Mode, OFlags, UserInfo}; use crate::platform::mock::MockPlatform; use alloc::vec; use alloc::vec::Vec; @@ -1947,7 +1947,7 @@ mod stdio { use crate::LiteBox; use crate::fs::devices::Devices; use crate::fs::resolver::Resolver; - use crate::fs::{FileSystem as _, Mode, OFlags}; + use crate::fs::{Mode, OFlags}; use crate::platform::mock::MockPlatform; use alloc::vec; extern crate std; @@ -2032,7 +2032,7 @@ mod composed_stdio { use crate::fs::devices::Devices; use crate::fs::in_mem::{InMem, InitialNode}; use crate::fs::resolver::Resolver; - use crate::fs::{FileSystem as _, Mode, OFlags, UserInfo}; + use crate::fs::{Mode, OFlags, UserInfo}; use crate::platform::mock::MockPlatform; use alloc::vec; extern crate std; diff --git a/litebox_runner_linux_on_windows_userland/tests/common/mod.rs b/litebox_runner_linux_on_windows_userland/tests/common/mod.rs index 9be029823..aadd353a6 100644 --- a/litebox_runner_linux_on_windows_userland/tests/common/mod.rs +++ b/litebox_runner_linux_on_windows_userland/tests/common/mod.rs @@ -5,7 +5,7 @@ use std::ffi::CString; -use litebox::fs::{FileSystem as _, Mode, OFlags}; +use litebox::fs::{Mode, OFlags}; use litebox_platform_windows_userland::WindowsUserland as Platform; pub struct TestLauncher { diff --git a/litebox_runner_linux_userland/tests/loader.rs b/litebox_runner_linux_userland/tests/loader.rs index 28f0d7f30..c5a8a82ec 100644 --- a/litebox_runner_linux_userland/tests/loader.rs +++ b/litebox_runner_linux_userland/tests/loader.rs @@ -6,7 +6,7 @@ mod common; use std::ffi::CString; -use litebox::fs::{FileSystem as _, Mode, OFlags}; +use litebox::fs::{Mode, OFlags}; use litebox_platform_linux_userland::LinuxUserland as Platform; struct TestLauncher { diff --git a/litebox_runner_snp/src/main.rs b/litebox_runner_snp/src/main.rs index fd58d6acb..e81a29fb2 100644 --- a/litebox_runner_snp/src/main.rs +++ b/litebox_runner_snp/src/main.rs @@ -34,9 +34,7 @@ impl log::Log for HostLogger { static HOST_LOGGER: HostLogger = HostLogger; type Platform = litebox_platform_linux_kernel::host::snp::snp_impl::SnpLinuxKernel; -type DefaultFS = litebox::fs::resolver::Resolver; - -type Shim = litebox_shim_linux::LinuxShim; +type Shim = litebox_shim_linux::LinuxShim; // FUTURE: eliminate this entirely (ideal). static SHIM: once_cell::race::OnceBox = once_cell::race::OnceBox::new(); diff --git a/litebox_shim_linux/src/lib.rs b/litebox_shim_linux/src/lib.rs index c2808238a..6c3e3fec1 100644 --- a/litebox_shim_linux/src/lib.rs +++ b/litebox_shim_linux/src/lib.rs @@ -59,11 +59,7 @@ pub type DefaultFS = LinuxFS; pub(crate) type LinuxFS = litebox::fs::resolver::Resolver; -pub(crate) type FileFd = litebox::fd::TypedFd; - -/// A trait required for file systems to be used in the shim. -pub trait ShimFS: litebox::fs::FileSystem + Send + Sync + 'static {} -impl ShimFS for T {} +pub(crate) type FileFd = litebox::fd::TypedFd>; /// Aggregate bound capturing everything the shim requires of a platform. /// @@ -124,16 +120,14 @@ fn preadv_pwritev_offset(pos_l: usize, pos_h: usize) -> i64 { ((pos_h as u64) << 32 | pos_l as u64).reinterpret_as_signed() } -pub struct LinuxShimEntrypoints { - task: Task, +pub struct LinuxShimEntrypoints { + task: Task, // The task should not be moved once it's bound to a platform thread so that // we preserve the ability to use TLS in the future. _not_send: core::marker::PhantomData<*const ()>, } -impl litebox::shim::EnterShim - for LinuxShimEntrypoints -{ +impl litebox::shim::EnterShim for LinuxShimEntrypoints { type ExecutionContext = litebox_common_linux::PtRegs; fn init(&self, ctx: &mut Self::ExecutionContext) -> ContinueOperation { @@ -173,12 +167,12 @@ impl litebox::shim::EnterShim } } -impl LinuxShimEntrypoints { +impl LinuxShimEntrypoints { fn enter_shim( &self, is_init: bool, ctx: &mut litebox_common_linux::PtRegs, - f: impl FnOnce(&Task, &mut litebox_common_linux::PtRegs), + f: impl FnOnce(&Task, &mut litebox_common_linux::PtRegs), ) -> ContinueOperation { if !is_init { self.task.enter_from_guest(); @@ -222,7 +216,7 @@ impl LinuxShimBuilder { } /// Build the shim. - pub fn build(self) -> LinuxShim { + pub fn build(self) -> LinuxShim { let mut net = Network::new(&self.litebox); net.set_platform_interaction(litebox::net::PlatformInteraction::Manual); let global = Arc::new(GlobalState { @@ -241,24 +235,24 @@ impl LinuxShimBuilder { } } -pub struct LinuxShim(Arc>); -impl Clone for LinuxShim { +pub struct LinuxShim(Arc>); +impl Clone for LinuxShim { fn clone(&self) -> Self { Self(self.0.clone()) } } -impl LinuxShim { +impl LinuxShim { /// Loads the program at `path` as the shim's initial task, returning the /// initial register state. pub fn load_program( &self, - fs: alloc::sync::Arc, + fs: alloc::sync::Arc>, task: litebox_common_linux::TaskParams, path: &str, argv: Vec, envp: Vec, - ) -> Result, loader::elf::ElfLoaderError> { + ) -> Result, loader::elf::ElfLoaderError> { let litebox_common_linux::TaskParams { pid, ppid, @@ -348,8 +342,8 @@ impl LinuxShim { } } -pub struct LoadedProgram { - pub entrypoints: LinuxShimEntrypoints, +pub struct LoadedProgram { + pub entrypoints: LinuxShimEntrypoints, pub process: LinuxShimProcess, } @@ -398,8 +392,8 @@ fn default_fs( #[derive(Clone)] pub(crate) struct StdioStatusFlags(litebox::fs::OFlags); -impl syscalls::file::FilesState { - fn initialize_stdio_in_shared_descriptors_table(&self, global: &GlobalState) { +impl syscalls::file::FilesState { + fn initialize_stdio_in_shared_descriptors_table(&self, global: &GlobalState) { use litebox::fs::{Mode, OFlags}; let stdin = self .fs @@ -432,7 +426,7 @@ impl syscalls::file::FilesState Task { +impl Task { fn close_on_exec(&self) { let files = self.files.borrow(); let alive_fds: Vec = files.raw_descriptor_store.read().iter_alive().collect(); @@ -446,17 +440,17 @@ impl Task { } } -impl syscalls::file::FilesState { +impl syscalls::file::FilesState { #[expect(clippy::too_many_arguments)] pub(crate) fn run_on_raw_fd( &self, fd: usize, - fs: impl FnOnce(&TypedFd) -> R, + fs: impl FnOnce(&FileFd) -> R, net: impl FnOnce(&TypedFd>) -> R, pipes: impl FnOnce(&TypedFd>) -> R, eventfd: impl FnOnce(&TypedFd>) -> R, - epoll: impl FnOnce(&TypedFd>) -> R, - unix: impl FnOnce(&TypedFd>) -> R, + epoll: impl FnOnce(&TypedFd>) -> R, + unix: impl FnOnce(&TypedFd>) -> R, ) -> Result { let rds = self.raw_descriptor_store.read(); if let Ok(fd) = rds.fd_from_raw_integer(fd) { @@ -513,7 +507,7 @@ impl ToSyscallResult for Result { } } -impl Task { +impl Task { /// A wrapper function around `sys_pread64` that copies data in chunks to avoid OOMing. fn pread_with_user_buf( &self, @@ -1161,7 +1155,7 @@ impl Task { } /// Global shim state, shared across all tasks. -struct GlobalState { +struct GlobalState { /// The platform instance used throughout the shim. platform: &'static Platform, /// The LiteBox instance used throughout the shim. @@ -1180,13 +1174,13 @@ struct GlobalState { // TODO: better management of thread IDs next_thread_id: core::sync::atomic::AtomicI32, /// UNIX domain socket address table - unix_addr_table: litebox::sync::RwLock>, + unix_addr_table: litebox::sync::RwLock>, /// Per-process collection of ELF patching state for runtime syscall rewriting. elf_patch_cache: litebox::sync::Mutex, } -struct Task { - global: Arc>, +struct Task { + global: Arc>, wait_state: wait::WaitState, thread: syscalls::process::ThreadState, /// Process ID @@ -1203,12 +1197,12 @@ struct Task { /// Filesystem state. `RefCell` to support `unshare` in the future. fs: RefCell>>, /// File descriptors. `RefCell` to support `unshare` in the future. - files: RefCell>>, + files: RefCell>>, /// Signal state signals: syscalls::signal::SignalState, } -impl Drop for Task { +impl Drop for Task { fn drop(&mut self) { self.prepare_for_exit(); } @@ -1219,12 +1213,12 @@ mod test_utils { extern crate std; use super::*; - impl GlobalState { + impl GlobalState { /// Make a new task with default values for testing. pub(crate) fn new_test_task( self: Arc, - fs: alloc::sync::Arc, - ) -> Task { + fs: alloc::sync::Arc>, + ) -> Task { let pid = self .next_thread_id .fetch_add(1, core::sync::atomic::Ordering::Relaxed); @@ -1251,7 +1245,7 @@ mod test_utils { } } - impl Task { + impl Task { /// Returns a clone of this task with a new TID for testing. pub(crate) fn clone_for_test(&self) -> Option { let tid = self @@ -1281,7 +1275,7 @@ mod test_utils { #[must_use] pub(crate) fn spawn_clone_for_test( &self, - f: impl 'static + Send + FnOnce(Task) -> R, + f: impl 'static + Send + FnOnce(Task) -> R, ) -> std::thread::JoinHandle where R: 'static + Send, diff --git a/litebox_shim_linux/src/loader/auxv.rs b/litebox_shim_linux/src/loader/auxv.rs index d23b87953..7e344a0af 100644 --- a/litebox_shim_linux/src/loader/auxv.rs +++ b/litebox_shim_linux/src/loader/auxv.rs @@ -3,7 +3,7 @@ //! Auxiliary vector support. -use crate::{ShimFS, ShimPlatform, Task}; +use crate::{ShimPlatform, Task}; #[allow(non_camel_case_types)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -66,7 +66,7 @@ pub enum AuxKey { pub type AuxVec = alloc::collections::btree_map::BTreeMap; -impl Task { +impl Task { /// Initialize the auxiliary vector with user information and VDSO address. pub fn init_auxv(&self) -> AuxVec { let mut aux = AuxVec::new(); diff --git a/litebox_shim_linux/src/loader/elf.rs b/litebox_shim_linux/src/loader/elf.rs index b0449c25b..4f9a5933d 100644 --- a/litebox_shim_linux/src/loader/elf.rs +++ b/litebox_shim_linux/src/loader/elf.rs @@ -18,17 +18,17 @@ use crate::{ }; use super::stack::UserStack; -use crate::{ShimFS, ShimPlatform, Task}; +use crate::{ShimPlatform, Task}; // An opened elf file -struct ElfFile<'a, Platform: ShimPlatform, FS: ShimFS> { - task: &'a Task, +struct ElfFile<'a, Platform: ShimPlatform> { + task: &'a Task, fd: i32, load_high: bool, } -impl<'a, Platform: ShimPlatform, FS: ShimFS> ElfFile<'a, Platform, FS> { - fn new(task: &'a Task, path: impl litebox::path::Arg) -> Result { +impl<'a, Platform: ShimPlatform> ElfFile<'a, Platform> { + fn new(task: &'a Task, path: impl litebox::path::Arg) -> Result { let fd = task .sys_open(path, OFlags::RDONLY, Mode::empty())? .reinterpret_as_signed(); @@ -40,15 +40,13 @@ impl<'a, Platform: ShimPlatform, FS: ShimFS> ElfFile<'a, Platform, FS> { } } -impl Drop for ElfFile<'_, Platform, FS> { +impl Drop for ElfFile<'_, Platform> { fn drop(&mut self) { self.task.sys_close(self.fd).expect("failed to close fd"); } } -impl litebox_common_linux::loader::ReadAt - for &'_ ElfFile<'_, Platform, FS> -{ +impl litebox_common_linux::loader::ReadAt for &'_ ElfFile<'_, Platform> { type Error = Errno; fn read_at(&mut self, mut offset: u64, mut buf: &mut [u8]) -> Result<(), Self::Error> { @@ -74,9 +72,7 @@ impl litebox_common_linux::loader::ReadAt } } -impl litebox_common_linux::loader::MapMemory - for ElfFile<'_, Platform, FS> -{ +impl litebox_common_linux::loader::MapMemory for ElfFile<'_, Platform> { type Error = Errno; fn reserve(&mut self, len: usize, align: usize) -> Result { @@ -181,20 +177,20 @@ pub struct ElfLoadInfo { } /// Loader for ELF files -pub(crate) struct ElfLoader<'a, Platform: ShimPlatform, FS: ShimFS> { +pub(crate) struct ElfLoader<'a, Platform: ShimPlatform> { path: &'a str, - main: FileAndParsed<'a, Platform, FS>, - interp: Option>, + main: FileAndParsed<'a, Platform>, + interp: Option>, } -struct FileAndParsed<'a, Platform: ShimPlatform, FS: ShimFS> { - file: ElfFile<'a, Platform, FS>, +struct FileAndParsed<'a, Platform: ShimPlatform> { + file: ElfFile<'a, Platform>, parsed: ElfParsedFile, } -impl<'a, Platform: ShimPlatform, FS: ShimFS> FileAndParsed<'a, Platform, FS> { +impl<'a, Platform: ShimPlatform> FileAndParsed<'a, Platform> { fn new( - task: &'a Task, + task: &'a Task, path: impl litebox::path::Arg, ) -> Result { let file = ElfFile::new(task, path).map_err(ElfLoaderError::OpenError)?; @@ -239,9 +235,9 @@ impl<'a, Platform: ShimPlatform, FS: ShimFS> FileAndParsed<'a, Platform, FS> { } } -impl<'a, Platform: ShimPlatform, FS: ShimFS> ElfLoader<'a, Platform, FS> { +impl<'a, Platform: ShimPlatform> ElfLoader<'a, Platform> { /// Parses an ELF file from the given path. - pub fn new(task: &'a Task, path: &'a str) -> Result { + pub fn new(task: &'a Task, path: &'a str) -> Result { // Parse the main ELF file. let main = FileAndParsed::new(task, path)?; @@ -477,11 +473,7 @@ mod tests { buf } - fn write_file( - task: &Task>, - path: &str, - data: &[u8], - ) { + fn write_file(task: &Task, path: &str, data: &[u8]) { let fd = task .sys_open(path, OFlags::CREAT | OFlags::WRONLY, Mode::RWXU) .expect("failed to create test ELF"); diff --git a/litebox_shim_linux/src/syscalls/epoll.rs b/litebox_shim_linux/src/syscalls/epoll.rs index 37122005c..035eff02c 100644 --- a/litebox_shim_linux/src/syscalls/epoll.rs +++ b/litebox_shim_linux/src/syscalls/epoll.rs @@ -21,15 +21,13 @@ use litebox::{ use litebox_common_linux::{EpollEvent, EpollOp, errno::Errno}; use super::file::FilesState; -use crate::{GlobalState, ShimFS, ShimPlatform}; +use crate::{GlobalState, LinuxFS, ShimPlatform}; -pub(crate) struct EpollSubsystem( - core::marker::PhantomData<(Platform, FS)>, -); -impl FdEnabledSubsystem for EpollSubsystem { - type Entry = EpollFile; +pub(crate) struct EpollSubsystem(core::marker::PhantomData); +impl FdEnabledSubsystem for EpollSubsystem { + type Entry = EpollFile; } -impl FdEnabledSubsystemEntry for EpollFile {} +impl FdEnabledSubsystemEntry for EpollFile {} bitflags::bitflags! { /// Linux's epoll flags. @@ -42,19 +40,19 @@ bitflags::bitflags! { } } -pub(crate) enum EpollDescriptor { +pub(crate) enum EpollDescriptor { Eventfd(Arc>>), - Epoll(Arc>>), - File(Arc>), + Epoll(Arc>>), + File(Arc>), Socket(Arc>), Pipe(Arc>), - Unix(Arc>>), + Unix(Arc>>), } -impl EpollDescriptor { - pub fn try_from(files: &FilesState, raw_fd: usize) -> Result { +impl EpollDescriptor { + pub fn try_from(files: &FilesState, raw_fd: usize) -> Result { let rds = files.raw_descriptor_store.read(); - if let Ok(fd) = rds.fd_from_raw_integer::(raw_fd) { + if let Ok(fd) = rds.fd_from_raw_integer::>(raw_fd) { return Ok(EpollDescriptor::File(fd)); } if let Ok(fd) = rds.fd_from_raw_integer::>(raw_fd) { @@ -68,11 +66,11 @@ impl EpollDescriptor { { return Ok(EpollDescriptor::Eventfd(fd)); } - if let Ok(fd) = rds.fd_from_raw_integer::>(raw_fd) { + if let Ok(fd) = rds.fd_from_raw_integer::>(raw_fd) { return Ok(EpollDescriptor::Epoll(fd)); } if let Ok(fd) = - rds.fd_from_raw_integer::>(raw_fd) + rds.fd_from_raw_integer::>(raw_fd) { return Ok(EpollDescriptor::Unix(fd)); } @@ -80,17 +78,17 @@ impl EpollDescriptor { } } -enum DescriptorRef { +enum DescriptorRef { Eventfd(Weak>>), - Epoll(Weak>>), - File(Weak>), + Epoll(Weak>>), + File(Weak>), Socket(Weak>), Pipe(Weak>), - Unix(Weak>>), + Unix(Weak>>), } -impl DescriptorRef { - fn from(value: &EpollDescriptor) -> Self { +impl DescriptorRef { + fn from(value: &EpollDescriptor) -> Self { match value { EpollDescriptor::Eventfd(file) => Self::Eventfd(Arc::downgrade(file)), EpollDescriptor::Epoll(file) => Self::Epoll(Arc::downgrade(file)), @@ -101,7 +99,7 @@ impl DescriptorRef { } } - fn upgrade(&self) -> Option> { + fn upgrade(&self) -> Option> { match self { DescriptorRef::Eventfd(eventfd) => eventfd.upgrade().map(EpollDescriptor::Eventfd), DescriptorRef::Epoll(epoll) => epoll.upgrade().map(EpollDescriptor::Epoll), @@ -113,12 +111,12 @@ impl DescriptorRef { } } -impl EpollDescriptor { +impl EpollDescriptor { /// Returns the interesting events now and monitors their occurrence in the future if the /// observer is provided. fn poll( &self, - global: &GlobalState, + global: &GlobalState, mask: Events, observer: Option>>, ) -> Option { @@ -169,16 +167,16 @@ impl EpollDescriptor { } } -pub(crate) struct EpollFile { +pub(crate) struct EpollFile { interests: litebox::sync::Mutex< Platform, - BTreeMap>>, + BTreeMap>>, >, - ready: Arc>, + ready: Arc>, status: core::sync::atomic::AtomicU32, } -impl EpollFile { +impl EpollFile { pub(crate) fn new() -> Self { EpollFile { interests: litebox::sync::Mutex::new(BTreeMap::new()), @@ -189,7 +187,7 @@ impl EpollFile { pub(crate) fn wait( &self, - global: &GlobalState, + global: &GlobalState, cx: &WaitContext<'_, Platform>, maxevents: usize, ) -> Result, WaitError> { @@ -209,10 +207,10 @@ impl EpollFile { pub(crate) fn epoll_ctl( &self, - global: &GlobalState, + global: &GlobalState, op: EpollOp, fd: u32, - file: &EpollDescriptor, + file: &EpollDescriptor, event: Option, ) -> Result<(), Errno> { match op { @@ -233,9 +231,9 @@ impl EpollFile { fn add_interest( &self, - global: &GlobalState, + global: &GlobalState, fd: u32, - file: &EpollDescriptor, + file: &EpollDescriptor, event: EpollEvent, ) -> Result<(), Errno> { let mut interests = self.interests.lock(); @@ -270,9 +268,9 @@ impl EpollFile { #[expect(dead_code, reason = "currently unused, but might want to use soon")] fn mod_interest( &self, - global: &GlobalState, + global: &GlobalState, fd: u32, - file: &EpollDescriptor, + file: &EpollDescriptor, event: EpollEvent, ) -> Result<(), Errno> { // EPOLLEXCLUSIVE is not allowed for a EPOLL_CTL_MOD operation @@ -329,10 +327,7 @@ impl EpollFile { #[derive(PartialEq, Eq, PartialOrd, Ord)] struct EpollEntryKey(u32, usize); impl EpollEntryKey { - fn new( - fd: u32, - desc: &EpollDescriptor, - ) -> Self { + fn new(fd: u32, desc: &EpollDescriptor) -> Self { let ptr = match desc { EpollDescriptor::Eventfd(file) => Arc::as_ptr(file).addr(), EpollDescriptor::Epoll(file) => Arc::as_ptr(file).addr(), @@ -345,10 +340,10 @@ impl EpollEntryKey { } } -struct EpollEntry { - desc: DescriptorRef, +struct EpollEntry { + desc: DescriptorRef, inner: litebox::sync::Mutex, - ready: Arc>, + ready: Arc>, is_ready: AtomicBool, is_enabled: AtomicBool, weak_self: Weak, @@ -360,13 +355,13 @@ struct EpollEntryInner { data: u64, } -impl EpollEntry { +impl EpollEntry { fn new( - desc: DescriptorRef, + desc: DescriptorRef, mask: Events, flags: EpollFlags, data: u64, - ready: Arc>, + ready: Arc>, ) -> Arc { Arc::new_cyclic(|weak_self| EpollEntry { desc, @@ -378,7 +373,7 @@ impl EpollEntry { }) } - fn poll(&self, global: &GlobalState) -> Option<(Option, bool)> { + fn poll(&self, global: &GlobalState) -> Option<(Option, bool)> { let file = self.desc.upgrade()?; let inner = self.inner.lock(); @@ -413,18 +408,18 @@ impl EpollEntry { } } -impl Observer for EpollEntry { +impl Observer for EpollEntry { fn on_events(&self, _events: &Events) { self.ready.push(self); } } -struct ReadySet { - entries: litebox::sync::Mutex>>>, +struct ReadySet { + entries: litebox::sync::Mutex>>>, pollee: Pollee, } -impl ReadySet { +impl ReadySet { fn new() -> Self { Self { entries: litebox::sync::Mutex::new(VecDeque::new()), @@ -432,7 +427,7 @@ impl ReadySet { } } - fn push(&self, entry: &EpollEntry) { + fn push(&self, entry: &EpollEntry) { if !entry.is_enabled.load(core::sync::atomic::Ordering::Relaxed) { // the entry is disabled return; @@ -451,7 +446,7 @@ impl ReadySet { fn pop_multiple( &self, - global: &GlobalState, + global: &GlobalState, maxevents: usize, events: &mut Vec, ) { @@ -542,10 +537,10 @@ impl PollSet { }); } - fn scan_once( + fn scan_once( &mut self, - global: &GlobalState, - files: &FilesState, + global: &GlobalState, + files: &FilesState, waker: Option<&Waker>, ) -> bool { let mut is_ready = false; @@ -587,20 +582,16 @@ impl PollSet { } /// Scans the poll set for ready fds once. - pub fn scan( - &mut self, - global: &GlobalState, - files: &FilesState, - ) { + pub fn scan(&mut self, global: &GlobalState, files: &FilesState) { self.scan_once(global, files, None); } /// Waits for any of the fds in the poll set to become ready. - pub fn wait( + pub fn wait( &mut self, - global: &GlobalState, + global: &GlobalState, cx: &WaitContext<'_, Platform>, - files: &FilesState, + files: &FilesState, ) -> Result<(), WaitError> { if self.scan_once(global, files, None) { return Ok(()); @@ -655,10 +646,7 @@ mod test { crate::syscalls::tests::test_platform(None) } - fn setup_epoll() -> ( - crate::Task>, - EpollFile>, - ) { + fn setup_epoll() -> (crate::Task, EpollFile) { let task = crate::syscalls::tests::init_platform(None); let epoll = EpollFile::new(); diff --git a/litebox_shim_linux/src/syscalls/file.rs b/litebox_shim_linux/src/syscalls/file.rs index c64213265..3b1190331 100644 --- a/litebox_shim_linux/src/syscalls/file.rs +++ b/litebox_shim_linux/src/syscalls/file.rs @@ -24,7 +24,9 @@ use litebox_common_linux::{ }; use thiserror::Error; -use crate::{GlobalState, ShimFS, ShimPlatform, Task, UserPtr, UserPtrMut, syscalls::signal}; +use crate::{ + FileFd, GlobalState, LinuxFS, ShimPlatform, Task, UserPtr, UserPtrMut, syscalls::signal, +}; use core::sync::atomic::{AtomicUsize, Ordering}; #[derive(Clone, Copy)] @@ -74,16 +76,16 @@ impl FsState { } /// Task state shared by `CLONE_FILES`. -pub(crate) struct FilesState { +pub(crate) struct FilesState { /// The filesystem implementation, shared across tasks that share file system. - pub(crate) fs: alloc::sync::Arc, + pub(crate) fs: alloc::sync::Arc>, pub(crate) raw_descriptor_store: litebox::sync::RwLock, max_fd: AtomicUsize, } -impl FilesState { - pub(crate) fn new(fs: alloc::sync::Arc) -> Self { +impl FilesState { + pub(crate) fn new(fs: alloc::sync::Arc>) -> Self { Self { fs, raw_descriptor_store: litebox::sync::RwLock::new( @@ -185,7 +187,7 @@ impl FsPath { } } -impl Task { +impl Task { fn get_umask(&self) -> Mode { self.fs.borrow().umask() } @@ -226,7 +228,7 @@ impl Task { path: impl path::Arg, flags: OFlags, mode: Mode, - ) -> Result, Errno> { + ) -> Result, Errno> { let mode = mode & !self.get_umask(); self.files .borrow() @@ -241,12 +243,12 @@ impl Task { pathname: impl path::Arg, flags: OFlags, mode: Mode, - ) -> Result, Errno> { + ) -> Result, Errno> { let path = self.resolve_path_at(dirfd, pathname)?; self.do_open(path, flags, mode) } - fn insert_raw_file_fd(&self, file: TypedFd, flags: OFlags) -> Result { + fn insert_raw_file_fd(&self, file: FileFd, flags: OFlags) -> Result { if flags.contains(OFlags::CLOEXEC) { let None = self .global @@ -682,7 +684,7 @@ pub(crate) fn try_into_whence(value: i16) -> Result { } } -impl Task { +impl Task { /// Handle syscall `lseek` pub fn sys_lseek(&self, fd: i32, offset: isize, whence: SeekWhence) -> Result { let Ok(raw_fd) = u32::try_from(fd).and_then(usize::try_from) else { @@ -746,7 +748,7 @@ impl Task { } pub(crate) fn do_close(&self, raw_fd: usize) -> Result<(), Errno> { - self.do_close_and_replace::(raw_fd, None) + self.do_close_and_replace::>(raw_fd, None) } /// Close the file at `raw_fd` and optionally place a new file in the same slot. @@ -757,18 +759,20 @@ impl Task { raw_fd: usize, replace: Option>, ) -> Result<(), Errno> { - enum ConsumedFd { - Fs(alloc::sync::Arc>), + enum ConsumedFd { + Fs(alloc::sync::Arc>), Network(alloc::sync::Arc>>), Pipes(alloc::sync::Arc>>), Eventfd(alloc::sync::Arc>>), - Epoll(alloc::sync::Arc>>), - Unix(alloc::sync::Arc>>), + Epoll(alloc::sync::Arc>>), + Unix(alloc::sync::Arc>>), } let files = self.files.borrow(); let mut rds = files.raw_descriptor_store.write(); - let consumed: ConsumedFd = match rds.fd_consume_raw_integer::(raw_fd) { + let consumed: ConsumedFd = match rds + .fd_consume_raw_integer::>(raw_fd) + { Ok(fd) => ConsumedFd::Fs(fd), Err(litebox::fd::ErrRawIntFd::NotFound) => { if let Some(new_fd) = replace { @@ -791,13 +795,11 @@ impl Task { { ConsumedFd::Eventfd(fd) } else if let Ok(fd) = - rds.fd_consume_raw_integer::>(raw_fd) + rds.fd_consume_raw_integer::>(raw_fd) { ConsumedFd::Epoll(fd) - } else if let Ok(fd) = rds - .fd_consume_raw_integer::>( - raw_fd, - ) + } else if let Ok(fd) = + rds.fd_consume_raw_integer::>(raw_fd) { ConsumedFd::Unix(fd) } else { @@ -927,7 +929,7 @@ impl Task { } } -impl Task { +impl Task { fn check_raw_fd_exists(&self, fd: i32) -> Result<(), Errno> { let raw_fd = usize::try_from(fd).map_err(|_| Errno::EBADF)?; if self @@ -1065,7 +1067,7 @@ where Ok(total_written) } -impl Task { +impl Task { /// Handle syscall `writev` pub(crate) fn sys_writev( &self, @@ -1244,9 +1246,9 @@ impl Task { } } -fn descriptor_stat( +fn descriptor_stat( raw_fd: usize, - task: &Task, + task: &Task, ) -> Result where T: From + From, @@ -1293,15 +1295,15 @@ where .flatten() } -pub(crate) fn get_file_descriptor_flags( +pub(crate) fn get_file_descriptor_flags( raw_fd: usize, - global: &GlobalState, - files: &FilesState, + global: &GlobalState, + files: &FilesState, ) -> Result { // Currently, only one such flag is defined: FD_CLOEXEC, the close-on-exec flag. // See https://www.man7.org/linux/man-pages/man2/F_GETFD.2const.html - fn get_flags( - global: &GlobalState, + fn get_flags( + global: &GlobalState, fd: &TypedFd, ) -> FileDescriptorFlags { global @@ -1321,14 +1323,14 @@ pub(crate) fn get_file_descriptor_flags( ) } -fn set_file_descriptor_flags( +fn set_file_descriptor_flags( raw_fd: usize, - global: &GlobalState, - files: &FilesState, + global: &GlobalState, + files: &FilesState, flags: FileDescriptorFlags, ) -> Result<(), Errno> { - fn set_flags( - global: &GlobalState, + fn set_flags( + global: &GlobalState, fd: &TypedFd, flags: FileDescriptorFlags, ) { @@ -1350,7 +1352,7 @@ fn set_file_descriptor_flags( Ok(()) } -impl Task { +impl Task { /// Get the file status of `pathname`. /// /// The `pathname` must be absolute. @@ -1731,7 +1733,7 @@ impl Task { } } -impl Task { +impl Task { /// Handle syscall `pipe2` pub fn sys_pipe2(&self, flags: OFlags) -> Result<(u32, u32), Errno> { let super::pipe::LinuxPipeEnds { reader, writer } = self.global.create_linux_pipe(flags)?; @@ -1824,7 +1826,7 @@ impl Task { } } - fn is_stdio(&self, fs: &FS, fd: &TypedFd) -> Result { + fn is_stdio(&self, fs: &LinuxFS, fd: &FileFd) -> Result { match fs.fd_file_status(fd) { Ok(status) => { // See https://www.kernel.org/doc/Documentation/admin-guide/devices.txt @@ -2011,7 +2013,7 @@ impl Task { let epoll_file = super::epoll::EpollFile::new(); let mut dt = self.global.litebox.descriptor_table_mut(); - let typed = dt.insert::>(epoll_file); + let typed = dt.insert::>(epoll_file); if flags.contains(EpollCreateFlags::EPOLL_CLOEXEC) { let old = dt.set_fd_metadata(&typed, FileDescriptorFlags::FD_CLOEXEC); assert!(old.is_none()); @@ -2052,7 +2054,7 @@ impl Task { let epoll_fd = files .raw_descriptor_store .read() - .fd_from_raw_integer::>(epfd as usize) + .fd_from_raw_integer::>(epfd as usize) .map_err(|_| Errno::EBADF)?; let file_descriptor = super::epoll::EpollDescriptor::try_from(&files, fd as usize)?; @@ -2105,7 +2107,7 @@ impl Task { let Ok(fd) = files .raw_descriptor_store .read() - .fd_from_raw_integer::>( + .fd_from_raw_integer::>( raw_fd, ) else { return Err(Errno::EBADF); @@ -2373,9 +2375,9 @@ impl Task { flags: OFlags, target: DupFdRequest, ) -> Result { - fn dup( - task: &Task, - files: &FilesState, + fn dup( + task: &Task, + files: &FilesState, fd: &TypedFd, close_on_exec: bool, target: DupFdRequest, @@ -2519,7 +2521,7 @@ struct Diroff(usize); const DIRENT_STRUCT_BYTES_WITHOUT_NAME: usize = core::mem::offset_of!(litebox_common_linux::LinuxDirent64, __name); -impl Task { +impl Task { /// Handle syscall `getdents64` pub(crate) fn sys_getdirent64( &self, diff --git a/litebox_shim_linux/src/syscalls/misc.rs b/litebox_shim_linux/src/syscalls/misc.rs index ee546e53e..419d271e3 100644 --- a/litebox_shim_linux/src/syscalls/misc.rs +++ b/litebox_shim_linux/src/syscalls/misc.rs @@ -5,12 +5,12 @@ //! //! Examples of syscalls handled here include `getrandom`, `uname`, and similar operations. -use crate::{ShimFS, ShimPlatform, Task}; +use crate::{ShimPlatform, Task}; use litebox::{platform::Instant as _, utils::TruncateExt as _}; use litebox_common_linux::errno::Errno; use litebox_common_linux::user_pointers::UserPtrMut; -impl Task { +impl Task { /// Handle syscall `getrandom`. pub(crate) fn sys_getrandom( &self, @@ -64,7 +64,7 @@ const SYS_INFO: litebox_common_linux::Utsname = litebox_common_linux::Utsname { domainname: to_fixed_size_array::<65>(""), }; -impl Task { +impl Task { /// Handle syscall `uname`. pub(crate) fn sys_uname( &self, @@ -101,7 +101,7 @@ const _LINUX_CAPABILITY_VERSION_1: u32 = 0x19980330; const _LINUX_CAPABILITY_VERSION_2: u32 = 0x20071026; /* deprecated - use v3 */ const _LINUX_CAPABILITY_VERSION_3: u32 = 0x20080522; -impl Task { +impl Task { /// Handle syscall `capget`. /// /// Note we don't support capabilities in LiteBox, so this returns empty capabilities. diff --git a/litebox_shim_linux/src/syscalls/mm.rs b/litebox_shim_linux/src/syscalls/mm.rs index d62999b85..79c255c60 100644 --- a/litebox_shim_linux/src/syscalls/mm.rs +++ b/litebox_shim_linux/src/syscalls/mm.rs @@ -14,7 +14,6 @@ use litebox::{ }; use litebox_common_linux::{MRemapFlags, MapFlags, ProtFlags, errno::Errno}; -use crate::ShimFS; use crate::ShimPlatform; use crate::Task; use crate::UserPtrMut; @@ -74,7 +73,7 @@ fn align_down(addr: usize, align: usize) -> usize { addr & !(align - 1) } -impl Task { +impl Task { #[inline] fn do_mmap( &self, diff --git a/litebox_shim_linux/src/syscalls/net.rs b/litebox_shim_linux/src/syscalls/net.rs index a4bfc16a8..740676f37 100644 --- a/litebox_shim_linux/src/syscalls/net.rs +++ b/litebox_shim_linux/src/syscalls/net.rs @@ -34,7 +34,7 @@ use litebox_common_linux::{ use zerocopy::{FromBytes, Immutable, IntoBytes}; use crate::syscalls::unix::{CSockUnixAddr, UnixSocket, UnixSocketAddr}; -use crate::{GlobalState, ShimFS, ShimPlatform, Task}; +use crate::{GlobalState, ShimPlatform, Task}; use crate::{UserPtr, UserPtrMut, syscalls::signal}; /// Linux's hard cap on the number of iovecs per `*msg`-style call, and on the @@ -57,7 +57,7 @@ macro_rules! convert_flags { pub(crate) type SocketFd = litebox::net::SocketFd; -impl super::file::FilesState { +impl super::file::FilesState { /// Helper to dispatch socket operations based on socket type (INET vs Unix). /// /// This method handles the common pattern of: @@ -70,10 +70,10 @@ impl super::file::FilesState { /// For Unix sockets, the `unix_op` closure is called with a cloned Arc to the socket. fn with_socket( &self, - global: &GlobalState, + global: &GlobalState, sockfd: u32, inet_op: impl FnOnce(&SocketFd) -> Result, - unix_op: impl FnOnce(&UnixSocket) -> Result, + unix_op: impl FnOnce(&UnixSocket) -> Result, ) -> Result { let raw_fd = sockfd as usize; let inet_fd = { @@ -86,7 +86,7 @@ impl super::file::FilesState { let unix = self .raw_descriptor_store .read() - .fd_from_raw_integer::>(raw_fd) + .fd_from_raw_integer::>(raw_fd) .map_err(|err| match err { litebox::fd::ErrRawIntFd::NotFound => Errno::EBADF, litebox::fd::ErrRawIntFd::InvalidSubsystem => Errno::ENOTSOCK, @@ -192,7 +192,7 @@ pub(super) enum SocketOptionValue { /// so that they can access `net` and the litebox descriptor table. This might /// change if the nature of the litebox descriptor table changes, or if network /// namespaces are implemented. -impl GlobalState { +impl GlobalState { pub(crate) fn initialize_socket( &self, fd: &SocketFd, @@ -946,7 +946,7 @@ fn parse_type_and_flags(type_and_flags: u32) -> Result<(SockType, SockFlags), Er Ok((ty, flags)) } -impl Task { +impl Task { /// Handle syscall `socket` pub(crate) fn sys_socket( &self, @@ -1001,11 +1001,11 @@ impl Task { AddressFamily::UNIX => { let _ = UnixProtocol::try_from(protocol).map_err(|_| Errno::EPROTONOSUPPORT)?; let socket = UnixSocket::new(ty, flags).ok_or(Errno::ESOCKTNOSUPPORT)?; - let typed = - self.global - .litebox - .descriptor_table_mut() - .insert::>(socket); + let typed = self + .global + .litebox + .descriptor_table_mut() + .insert::>(socket); if flags.contains(SockFlags::CLOEXEC) { let old = self .global @@ -1062,9 +1062,9 @@ impl Task { let files = self.files.borrow(); let mut dt = self.global.litebox.descriptor_table_mut(); let typed1 = - dt.insert::>(sock1); + dt.insert::>(sock1); let typed2 = - dt.insert::>(sock2); + dt.insert::>(sock2); if flags.contains(SockFlags::CLOEXEC) { let old = dt.set_fd_metadata(&typed1, FileDescriptorFlags::FD_CLOEXEC); assert!(old.is_none()); @@ -1234,7 +1234,7 @@ fn copy_iovs_to_vec( Ok(data) } -impl Task { +impl Task { /// Handle syscall `accept` pub(crate) fn sys_accept( &self, @@ -1293,9 +1293,8 @@ impl Task { let accepted_file = file.accept(&self.wait_cx(), flags, socket_addr.as_mut())?; let peer_addr = socket_addr.map(SocketAddress::Unix); let mut dt = self.global.litebox.descriptor_table_mut(); - let typed = dt.insert::>( - accepted_file, - ); + let typed = dt + .insert::>(accepted_file); if flags.contains(SockFlags::CLOEXEC) { let old = dt.set_fd_metadata(&typed, FileDescriptorFlags::FD_CLOEXEC); assert!(old.is_none()); @@ -2087,10 +2086,7 @@ impl Task { mod tests { use core::net::SocketAddr; - type TestTask = crate::Task< - crate::syscalls::tests::TestPlatform, - crate::DefaultFS, - >; + type TestTask = crate::Task; use alloc::string::ToString as _; use litebox::utils::TruncateExt as _; @@ -2853,10 +2849,7 @@ mod tests { mod unix_tests { use core::time::Duration; - type TestTask = crate::Task< - crate::syscalls::tests::TestPlatform, - crate::DefaultFS, - >; + type TestTask = crate::Task; use alloc::{string::ToString, vec::Vec}; use litebox::event::Events; diff --git a/litebox_shim_linux/src/syscalls/pipe.rs b/litebox_shim_linux/src/syscalls/pipe.rs index 938f3ae9c..27192abf1 100644 --- a/litebox_shim_linux/src/syscalls/pipe.rs +++ b/litebox_shim_linux/src/syscalls/pipe.rs @@ -17,7 +17,7 @@ use litebox::{ }; use litebox_common_linux::{FileDescriptorFlags, InodeType, errno::Errno}; -use crate::{GlobalState, ShimFS, ShimPlatform}; +use crate::{GlobalState, ShimPlatform}; const DEFAULT_PIPE_BUF_SIZE: usize = 1024 * 1024; @@ -38,7 +38,7 @@ pub(crate) struct LinuxPipeEnds { pub(crate) writer: PipeFd, } -impl GlobalState { +impl GlobalState { pub(crate) fn create_linux_pipe( &self, flags: OFlags, diff --git a/litebox_shim_linux/src/syscalls/process.rs b/litebox_shim_linux/src/syscalls/process.rs index 0380b852f..9d473eedd 100644 --- a/litebox_shim_linux/src/syscalls/process.rs +++ b/litebox_shim_linux/src/syscalls/process.rs @@ -3,7 +3,7 @@ //! Process/thread related syscalls. -use crate::{ShimFS, ShimPlatform, Task, UserPtr, UserPtrMut}; +use crate::{ShimPlatform, Task, UserPtr, UserPtrMut}; use alloc::boxed::Box; use alloc::collections::btree_map::BTreeMap; use alloc::sync::Arc; @@ -250,7 +250,7 @@ impl Process { } } -impl Task { +impl Task { /// Updates the process exit status for a thread exit. fn exit_thread(&self, code: i8) { let mut inner = self.thread.process.inner.lock(); @@ -342,7 +342,7 @@ pub(crate) struct Credentials { pub egid: u32, } -impl Task { +impl Task { pub(crate) fn process(&self) -> &Arc> { &self.thread.process } @@ -482,7 +482,7 @@ fn wake_robust_list( Ok(()) } -impl Task { +impl Task { /// Called when the task is exiting. pub(crate) fn prepare_for_exit(&mut self) { self.thread.detach_from_process(); @@ -523,12 +523,12 @@ impl Task { #[cfg(target_arch = "x86_64")] type ThreadLocalDescriptor = UserPtrMut; -struct NewThreadArgs { +struct NewThreadArgs { /// Task struct that maintains all per-thread data - task: Task, + task: Task, } -impl litebox::shim::InitThread for NewThreadArgs { +impl litebox::shim::InitThread for NewThreadArgs { type ExecutionContext = litebox_common_linux::PtRegs; fn init( @@ -544,7 +544,7 @@ impl litebox::shim::InitThread for NewThread } } -impl Task { +impl Task { pub(crate) fn sys_clone( &self, ctx: &litebox_common_linux::PtRegs, @@ -787,7 +787,7 @@ impl ResourceLimits { } } -impl Task { +impl Task { /// Get resource limits, and optionally set new limits. pub(crate) fn do_prlimit( &self, @@ -1256,7 +1256,7 @@ impl CpuSet { } } -impl Task { +impl Task { /// Handle syscall `sched_getaffinity`. /// /// Note this is a dummy implementation that always returns the same CPU set @@ -1267,7 +1267,7 @@ impl Task { } } -impl Task { +impl Task { /// Handle syscall `futex` pub(crate) fn sys_futex(&self, arg: litebox_common_linux::FutexArgs) -> Result { /// Note our mutex implementation assumes futexes are private as we don't support shared memory yet. @@ -1376,7 +1376,7 @@ fn parse_shebang(buf: &[u8]) -> Option<(&str, Option<&str>)> { } } -impl Task { +impl Task { /// Resolve shebang (`#!`) chains for the given path and argv if the file starts with a shebang line. /// Otherwise, returns the original path and argv. pub(crate) fn resolve_shebang( @@ -1525,7 +1525,7 @@ impl Task { /// to start executing it. pub(crate) fn load_program( &self, - mut loader: crate::loader::elf::ElfLoader<'_, Platform, FS>, + mut loader: crate::loader::elf::ElfLoader<'_, Platform>, argv: Vec, envp: Vec, ) -> Result<(), crate::loader::elf::ElfLoaderError> { diff --git a/litebox_shim_linux/src/syscalls/signal/mod.rs b/litebox_shim_linux/src/syscalls/signal/mod.rs index fd849afac..afc8afc75 100644 --- a/litebox_shim_linux/src/syscalls/signal/mod.rs +++ b/litebox_shim_linux/src/syscalls/signal/mod.rs @@ -12,7 +12,7 @@ use x86_64 as arch; use zerocopy::FromZeros; use crate::syscalls::process::ExitStatus; -use crate::{ShimFS, ShimPlatform, Task, UserPtr, UserPtrMut}; +use crate::{ShimPlatform, Task, UserPtr, UserPtrMut}; use alloc::collections::vec_deque::VecDeque; use alloc::sync::Arc; use core::cell::{Cell, RefCell}; @@ -386,7 +386,7 @@ impl SignalState { /// A fault when delivering a signal. struct DeliverFault; -impl Task { +impl Task { pub(crate) fn with_temporary_signal_mask(&self, mask: SigSet, f: impl FnOnce() -> R) -> R { let old = self.signals.blocked.get(); self.signals.set_signal_mask(mask); diff --git a/litebox_shim_linux/src/syscalls/tests.rs b/litebox_shim_linux/src/syscalls/tests.rs index a371fb929..269174281 100644 --- a/litebox_shim_linux/src/syscalls/tests.rs +++ b/litebox_shim_linux/src/syscalls/tests.rs @@ -46,9 +46,7 @@ pub(crate) fn test_platform(tun_device_name: Option<&str>) -> &'static TestPlatf } #[must_use] -pub(crate) fn init_platform( - tun_device_name: Option<&str>, -) -> crate::Task> { +pub(crate) fn init_platform(tun_device_name: Option<&str>) -> crate::Task { let platform = test_platform(tun_device_name); let shim_builder = crate::LinuxShimBuilder::new(platform); diff --git a/litebox_shim_linux/src/syscalls/unix.rs b/litebox_shim_linux/src/syscalls/unix.rs index ca45f122a..ab91a0c42 100644 --- a/litebox_shim_linux/src/syscalls/unix.rs +++ b/litebox_shim_linux/src/syscalls/unix.rs @@ -31,19 +31,17 @@ use litebox_common_linux::{ }; use crate::{ - FileFd, GlobalState, ShimFS, ShimPlatform, Task, UserPtr, UserPtrMut, + FileFd, GlobalState, LinuxFS, ShimPlatform, Task, UserPtr, UserPtrMut, channel::{Channel, ReadEnd, WriteEnd}, syscalls::net::{SocketOptionValue, SocketOptions}, }; -pub(crate) struct UnixSocketSubsystem( - core::marker::PhantomData<(Platform, FS)>, -); -impl FdEnabledSubsystem for UnixSocketSubsystem { - type Entry = UnixSocket; +pub(crate) struct UnixSocketSubsystem(core::marker::PhantomData); +impl FdEnabledSubsystem for UnixSocketSubsystem { + type Entry = UnixSocket; } -impl FdEnabledSubsystemEntry for UnixSocket {} +impl FdEnabledSubsystemEntry for UnixSocket {} /// C-compatible structure for Unix socket addresses. const UNIX_PATH_MAX: usize = 108; @@ -71,8 +69,8 @@ pub(crate) enum UnixSocketAddr { /// For path-based sockets, this includes a file descriptor to ensure /// the socket file remains accessible. The file is automatically closed /// when this structure is dropped. -enum UnixBoundSocketAddr { - Path((String, FileFd, Arc)), +enum UnixBoundSocketAddr { + Path((String, FileFd, Arc>)), Abstract(Vec), } @@ -104,11 +102,11 @@ impl UnixSocketAddr { /// /// Returns an error if the address cannot be bound (e.g., file doesn't exist, /// permission denied). - fn bind( + fn bind( self, - task: &Task, + task: &Task, is_server: bool, - ) -> Result, Errno> { + ) -> Result, Errno> { match self { UnixSocketAddr::Path(path) => { let flags = if is_server { @@ -158,7 +156,7 @@ impl UnixSocketAddr { } } -impl UnixBoundSocketAddr { +impl UnixBoundSocketAddr { /// Converts this bound address to a key for the global address table. fn to_key(&self) -> UnixSocketAddrKey { match self { @@ -168,7 +166,7 @@ impl UnixBoundSocketAddr { } } -impl Drop for UnixBoundSocketAddr { +impl Drop for UnixBoundSocketAddr { fn drop(&mut self) { match self { Self::Path((_, file, fs)) => { @@ -179,8 +177,8 @@ impl Drop for UnixBoundSocketAddr { } } -impl From<&UnixBoundSocketAddr> for UnixSocketAddr { - fn from(addr: &UnixBoundSocketAddr) -> Self { +impl From<&UnixBoundSocketAddr> for UnixSocketAddr { + fn from(addr: &UnixBoundSocketAddr) -> Self { match addr { UnixBoundSocketAddr::Path((path, ..)) => UnixSocketAddr::Path(path.clone()), UnixBoundSocketAddr::Abstract(data) => UnixSocketAddr::Abstract(data.clone()), @@ -192,15 +190,15 @@ impl From<&UnixBoundSocketAddr> for UnixSocketAddr { /// /// This is the state immediately after socket creation, before the socket /// has been connected, or put into listening mode. -struct UnixInitStream { +struct UnixInitStream { /// Optional bound address for this socket - addr: Option>, + addr: Option>, pollee: Pollee, read_shutdown: AtomicBool, write_shutdown: AtomicBool, } -impl UnixInitStream { +impl UnixInitStream { fn new() -> Self { Self { addr: None, @@ -220,7 +218,7 @@ impl UnixInitStream { } /// Binds this socket to the given address. - fn bind(&mut self, task: &Task, addr: UnixSocketAddr) -> Result<(), Errno> { + fn bind(&mut self, task: &Task, addr: UnixSocketAddr) -> Result<(), Errno> { if self.addr.is_some() && !addr.is_unnamed() { return Err(Errno::EINVAL); } @@ -239,8 +237,8 @@ impl UnixInitStream { fn listen( self, backlog: u16, - global: &Arc>, - ) -> Result, (Self, Errno)> { + global: &Arc>, + ) -> Result, (Self, Errno)> { let Some(addr) = self.addr else { return Err((self, Errno::EINVAL)); }; @@ -259,11 +257,8 @@ impl UnixInitStream { /// Converts this initial socket into a connected stream pair. fn into_connected( self, - peer_addr: Arc>, - ) -> ( - UnixConnectedStream, - UnixConnectedStream, - ) { + peer_addr: Arc>, + ) -> (UnixConnectedStream, UnixConnectedStream) { let UnixInitStream { addr, pollee, @@ -283,22 +278,22 @@ impl UnixInitStream { /// Connection backlog for a listening Unix socket. /// /// Manages the queue of pending connections and the maximum backlog limit. -struct Backlog { +struct Backlog { /// The address this socket is listening on - addr: Arc>, - state: Mutex>, + addr: Arc>, + state: Mutex>, pollee: Pollee, } -struct BacklogState { - sockets: VecDeque>, +struct BacklogState { + sockets: VecDeque>, /// Maximum number of pending connections limit: u16, is_shutdown: bool, } -impl Backlog { - fn new(addr: UnixBoundSocketAddr, backlog: u16, pollee: Pollee) -> Self { +impl Backlog { + fn new(addr: UnixBoundSocketAddr, backlog: u16, pollee: Pollee) -> Self { Self { addr: Arc::new(addr), state: litebox::sync::Mutex::new(BacklogState { @@ -318,8 +313,8 @@ impl Backlog { /// Attempts to establish a connection without blocking. fn try_connect( &self, - init: UnixInitStream, - ) -> Result, (UnixInitStream, Errno)> { + init: UnixInitStream, + ) -> Result, (UnixInitStream, Errno)> { let mut state = self.state.lock(); if state.is_shutdown { return Err((init, Errno::ECONNREFUSED)); @@ -337,7 +332,7 @@ impl Backlog { } /// Attempts to accept a pending connection without blocking. - fn try_accept(&self) -> Result, TryOpError> { + fn try_accept(&self) -> Result, TryOpError> { let mut state = self.state.lock(); match state.sockets.pop_front() { Some(stream) => { @@ -376,12 +371,12 @@ impl Backlog { } /// Represents a Unix stream socket in listening state. -struct UnixListenStream { - backlog: Arc>, - global: Arc>, +struct UnixListenStream { + backlog: Arc>, + global: Arc>, } -impl UnixListenStream { +impl UnixListenStream { /// Updates the maximum backlog size for pending connections. fn listen(&self, backlog: u16) { self.backlog.set_backlog(backlog); @@ -396,12 +391,12 @@ impl UnixListenStream { } /// Returns the local address this socket is bound to. - fn get_local_addr(&self) -> &UnixBoundSocketAddr { + fn get_local_addr(&self) -> &UnixBoundSocketAddr { self.backlog.addr.as_ref() } } -impl Drop for UnixListenStream { +impl Drop for UnixListenStream { fn drop(&mut self) { self.backlog.shutdown(); @@ -417,18 +412,18 @@ impl Drop for UnixListenStream } /// Tracks the local and peer addresses for a connected socket. -struct AddrView { - addr: Option>>, - peer: Option>>, +struct AddrView { + addr: Option>>, + peer: Option>>, } -impl AddrView { +impl AddrView { /// Creates a pair of address views for two connected sockets. /// /// The local address of one becomes the peer address of the other. fn new_pair( - addr: Option>>, - peer: Option>>, + addr: Option>>, + peer: Option>>, ) -> (Self, Self) { let first = Self { addr: addr.clone(), @@ -442,12 +437,12 @@ impl AddrView { } /// Returns the local address, if available. - fn get_local_addr(&self) -> Option<&UnixBoundSocketAddr> { + fn get_local_addr(&self) -> Option<&UnixBoundSocketAddr> { self.addr.as_deref() } /// Returns the peer address, if available. - fn get_peer_addr(&self) -> Option<&UnixBoundSocketAddr> { + fn get_peer_addr(&self) -> Option<&UnixBoundSocketAddr> { self.peer.as_deref() } } @@ -460,8 +455,8 @@ struct Message { } /// Represents a connected Unix stream socket. -struct UnixConnectedStream { - addr: AddrView, +struct UnixConnectedStream { + addr: AddrView, /// The read end of the local socket's channel for receiving messages. recv_channel: crate::channel::ReadEnd, /// The write end of the connected peer socket for sending messages. @@ -470,16 +465,16 @@ struct UnixConnectedStream { } const UNIX_BUF_SIZE: usize = 65536; -impl UnixConnectedStream { +impl UnixConnectedStream { /// Creates a pair of connected Unix stream sockets. /// /// `read_shutdown` and `write_shutdown` half-close the corresponding sides of the /// *first* returned socket only (used to carry pre-connect shutdown flags from /// `UnixInitStream` across `connect(2)` into the connected state). fn new_pair( - addr: Option>>, + addr: Option>>, pollee: Option>>, - peer: Option>>, + peer: Option>>, read_shutdown: bool, write_shutdown: bool, ) -> (Self, Self) { @@ -592,20 +587,20 @@ impl UnixConnectedStream { } } -enum UnixStreamState { - Init(UnixInitStream), - Listen(UnixListenStream), - Connected(UnixConnectedStream), +enum UnixStreamState { + Init(UnixInitStream), + Listen(UnixListenStream), + Connected(UnixConnectedStream), } -impl UnixStreamState { - fn connected(&self) -> Option<&UnixConnectedStream> { +impl UnixStreamState { + fn connected(&self) -> Option<&UnixConnectedStream> { match self { UnixStreamState::Connected(conn) => Some(conn), _ => None, } } - fn listen(&self) -> Option<&UnixListenStream> { + fn listen(&self) -> Option<&UnixListenStream> { match self { UnixStreamState::Listen(listen) => Some(listen), _ => None, @@ -613,12 +608,12 @@ impl UnixStreamState { } } -struct UnixStream { - state: RwLock>>, +struct UnixStream { + state: RwLock>>, } -impl UnixStream { - fn new(state: UnixStreamState) -> Self { +impl UnixStream { + fn new(state: UnixStreamState) -> Self { Self { state: litebox::sync::RwLock::new(Some(state)), } @@ -626,7 +621,7 @@ impl UnixStream { fn with_state_ref(&self, f: F) -> R where - F: FnOnce(&UnixStreamState) -> R, + F: FnOnce(&UnixStreamState) -> R, { let old = self.state.read(); f(old.as_ref().expect("state should never be None")) @@ -634,7 +629,7 @@ impl UnixStream { fn with_state_mut_ref(&self, f: F) -> R where - F: FnOnce(&mut UnixStreamState) -> R, + F: FnOnce(&mut UnixStreamState) -> R, { let mut old = self.state.write(); f(old.as_mut().expect("state should never be None")) @@ -642,7 +637,7 @@ impl UnixStream { fn with_state(&self, f: F) -> R where - F: FnOnce(UnixStreamState) -> (UnixStreamState, R), + F: FnOnce(UnixStreamState) -> (UnixStreamState, R), { let mut old = self.state.write(); let (new, result) = f(old.take().expect("state should never be None")); @@ -650,7 +645,7 @@ impl UnixStream { result } - fn bind(&self, task: &Task, addr: UnixSocketAddr) -> Result<(), Errno> { + fn bind(&self, task: &Task, addr: UnixSocketAddr) -> Result<(), Errno> { self.with_state_mut_ref(|state| { match state { UnixStreamState::Init(init) => init.bind(task, addr), @@ -664,7 +659,7 @@ impl UnixStream { }) } - fn listen(&self, backlog: u16, global: &Arc>) -> Result<(), Errno> { + fn listen(&self, backlog: u16, global: &Arc>) -> Result<(), Errno> { self.with_state(|state| { let ret = match state { UnixStreamState::Init(init) => { @@ -685,9 +680,9 @@ impl UnixStream { fn lookup( &self, - task: &Task, + task: &Task, addr: &UnixSocketAddr, - ) -> Result>, Errno> { + ) -> Result>, Errno> { let guard = task.global.unix_addr_table.read(); let Some(key) = addr.to_key() else { return Err(Errno::EINVAL); @@ -700,7 +695,7 @@ impl UnixStream { UnixEntryInner::Datagram(_) => Err(Errno::EPROTOTYPE), } } - fn try_connect(&self, backlog: &Backlog) -> Result<(), TryOpError> { + fn try_connect(&self, backlog: &Backlog) -> Result<(), TryOpError> { self.with_state(|state| match state { UnixStreamState::Init(init) => match backlog.try_connect(init) { Ok(connected) => (UnixStreamState::Connected(connected), Ok(())), @@ -716,7 +711,7 @@ impl UnixStream { } fn connect( &self, - task: &Task, + task: &Task, addr: UnixSocketAddr, is_nonblocking: bool, ) -> Result<(), Errno> { @@ -741,12 +736,11 @@ impl UnixStream { cx: &WaitContext<'_, Platform>, mut peer: Option<&mut UnixSocketAddr>, is_nonblocking: bool, - ) -> Result, Errno> { - let backlog = - self.with_state_ref(|state| -> Result>, Errno> { - let listen = state.listen().ok_or(Errno::EINVAL)?; - Ok(listen.backlog.clone()) - })?; + ) -> Result, Errno> { + let backlog = self.with_state_ref(|state| -> Result>, Errno> { + let listen = state.listen().ok_or(Errno::EINVAL)?; + Ok(listen.backlog.clone()) + })?; let res = cx .wait_on_events( is_nonblocking, @@ -997,11 +991,11 @@ impl ReadEnd { /// The local address of a bound datagram socket together with the global state /// it was registered in (used to deregister the address on drop). -type BoundDatagramAddr = (UnixBoundSocketAddr, Arc>); +type BoundDatagramAddr = (UnixBoundSocketAddr, Arc>); -struct UnixDatagramInner { +struct UnixDatagramInner { /// The local address this socket is bound to, if any. - addr: Option>, + addr: Option>, /// The read end of the local socket's channel for receiving messages. /// Set when the socket is bound via `bind` or `new_pair`. recv_channel: Option>, @@ -1013,11 +1007,11 @@ struct UnixDatagramInner { pollee: Arc>, } /// Represents a Unix datagram socket. -struct UnixDatagram { - inner: RwLock>, +struct UnixDatagram { + inner: RwLock>, } -impl Drop for UnixDatagramInner { +impl Drop for UnixDatagramInner { fn drop(&mut self) { if let Some((addr, global)) = self.addr.take() { let key = addr.to_key(); @@ -1033,9 +1027,9 @@ impl Drop for UnixDatagramInner UnixDatagramInner { +impl UnixDatagramInner { /// Binds this socket to the given address. - fn bind(&mut self, task: &Task, addr: UnixSocketAddr) -> Result<(), Errno> { + fn bind(&mut self, task: &Task, addr: UnixSocketAddr) -> Result<(), Errno> { if self.addr.is_some() { if addr.is_unnamed() { return Ok(()); @@ -1082,7 +1076,7 @@ impl UnixDatagramInner { } } -impl UnixDatagram { +impl UnixDatagram { fn new() -> Self { Self { inner: RwLock::new(UnixDatagramInner { @@ -1096,7 +1090,7 @@ impl UnixDatagram { } } - fn new_pair() -> (UnixDatagram, UnixDatagram) { + fn new_pair() -> (UnixDatagram, UnixDatagram) { let pollee1 = Arc::new(Pollee::new()); let pollee2 = Arc::new(Pollee::new()); let (send_channel, recv_channel) = @@ -1129,14 +1123,14 @@ impl UnixDatagram { } /// Binds this socket to the given address. - fn bind(&self, task: &Task, addr: UnixSocketAddr) -> Result<(), Errno> { + fn bind(&self, task: &Task, addr: UnixSocketAddr) -> Result<(), Errno> { self.inner.write().bind(task, addr) } /// Looks up a socket address and returns its write endpoint. fn lookup( &self, - task: &Task, + task: &Task, addr: UnixSocketAddr, ) -> Result, Errno> { let guard = task.global.unix_addr_table.read(); @@ -1157,7 +1151,7 @@ impl UnixDatagram { /// Connects this socket to a default peer address. /// /// Subsequent sends without an address will use this peer. - fn connect(&self, task: &Task, addr: UnixSocketAddr) -> Result<(), Errno> { + fn connect(&self, task: &Task, addr: UnixSocketAddr) -> Result<(), Errno> { let send_channel = self.lookup(task, addr.clone())?; let mut inner = self.inner.write(); if inner.write_shutdown { @@ -1210,7 +1204,7 @@ impl UnixDatagram { /// connected peer (set via `connect()`). fn sendto( &self, - task: &Task, + task: &Task, timeout: Option, buf: &[u8], is_nonblocking: bool, @@ -1300,18 +1294,18 @@ impl UnixDatagram { } } -enum UnixSocketInner { - Stream(UnixStream), - Datagram(UnixDatagram), +enum UnixSocketInner { + Stream(UnixStream), + Datagram(UnixDatagram), } -pub(crate) struct UnixSocket { - inner: UnixSocketInner, +pub(crate) struct UnixSocket { + inner: UnixSocketInner, status: AtomicU32, options: Mutex, } -impl UnixSocket { - fn new_with_inner(inner: UnixSocketInner, flags: SockFlags) -> Self { +impl UnixSocket { + fn new_with_inner(inner: UnixSocketInner, flags: SockFlags) -> Self { let mut status = OFlags::RDWR; status.set(OFlags::NONBLOCK, flags.contains(SockFlags::NONBLOCK)); Self { @@ -1335,11 +1329,7 @@ impl UnixSocket { Some(Self::new_with_inner(inner, flags)) } - pub(super) fn bind( - &self, - task: &Task, - addr: UnixSocketAddr, - ) -> Result<(), Errno> { + pub(super) fn bind(&self, task: &Task, addr: UnixSocketAddr) -> Result<(), Errno> { match &self.inner { UnixSocketInner::Stream(stream) => stream.bind(task, addr), UnixSocketInner::Datagram(datagram) => datagram.bind(task, addr), @@ -1349,7 +1339,7 @@ impl UnixSocket { pub(super) fn listen( &self, backlog: u16, - global: &Arc>, + global: &Arc>, ) -> Result<(), Errno> { match &self.inner { UnixSocketInner::Stream(stream) => stream.listen(backlog, global), @@ -1357,11 +1347,7 @@ impl UnixSocket { } } - pub(super) fn connect( - &self, - task: &Task, - addr: UnixSocketAddr, - ) -> Result<(), Errno> { + pub(super) fn connect(&self, task: &Task, addr: UnixSocketAddr) -> Result<(), Errno> { match &self.inner { UnixSocketInner::Stream(stream) => { stream.connect(task, addr, self.get_status().contains(OFlags::NONBLOCK)) @@ -1375,7 +1361,7 @@ impl UnixSocket { cx: &WaitContext<'_, Platform>, flags: SockFlags, peer: Option<&mut UnixSocketAddr>, - ) -> Result, Errno> { + ) -> Result, Errno> { match &self.inner { UnixSocketInner::Stream(stream) => { let accepted = stream.accept( @@ -1392,7 +1378,7 @@ impl UnixSocket { pub(super) fn sendto( &self, - task: &Task, + task: &Task, buf: &[u8], flags: SendFlags, addr: Option, @@ -1460,7 +1446,7 @@ impl UnixSocket { pub(super) fn new_connected_pair( ty: SockType, flags: SockFlags, - ) -> Option<(UnixSocket, UnixSocket)> { + ) -> Option<(UnixSocket, UnixSocket)> { match ty { SockType::Stream => { let (conn1, conn2) = UnixConnectedStream::new_pair(None, None, None, false, false); @@ -1488,7 +1474,7 @@ impl UnixSocket { pub(super) fn setsockopt( &self, - global: &GlobalState, + global: &GlobalState, optname: SocketOptionName, optval: UserPtr, optlen: usize, @@ -1554,7 +1540,7 @@ impl UnixSocket { } pub(super) fn getsockopt( &self, - global: &GlobalState, + global: &GlobalState, optname: SocketOptionName, optval: UserPtrMut, len: u32, @@ -1635,7 +1621,7 @@ impl UnixSocket { super::common_functions_for_file_status!(); } -impl IOPollable for UnixSocket { +impl IOPollable for UnixSocket { fn register_observer( &self, observer: Weak>, @@ -1663,11 +1649,11 @@ impl IOPollable for UnixSocket } } -pub(crate) struct UnixEntry(UnixEntryInner); -enum UnixEntryInner { - Stream(Arc>), +pub(crate) struct UnixEntry(UnixEntryInner); +enum UnixEntryInner { + Stream(Arc>), Datagram(WriteEnd), } /// Type alias for the global Unix socket address table. -pub(crate) type UnixAddrTable = BTreeMap>; +pub(crate) type UnixAddrTable = BTreeMap>; diff --git a/litebox_shim_linux/src/transport.rs b/litebox_shim_linux/src/transport.rs index 7e48eda28..10f4b87d6 100644 --- a/litebox_shim_linux/src/transport.rs +++ b/litebox_shim_linux/src/transport.rs @@ -12,23 +12,27 @@ use litebox::net::{ReceiveFlags, SendFlags}; use litebox_common_linux::{SockFlags, SockType, errno::Errno}; use crate::syscalls::net::SocketFd; -use crate::{GlobalState, ShimFS, ShimPlatform}; +use crate::{GlobalState, ShimPlatform}; -/// Handles socket cleanup on drop without exposing the `FS` generic. +/// Handles socket cleanup on drop without exposing the concrete socket/global-state types. /// /// This is stored as `Box` inside [`ShimTransport`] so that the -/// transport itself does not need to be generic over `FS`. +/// transport itself does not need to name them. +// XXX: this erasure only existed to hide the old `FS` generic. Now that `SocketDropGuard`'s fields +// are nameable from `Platform` alone, we could inline them into [`ShimTransport`] and drop this +// trait. However, this `DropGuard` _may_ be worth keeping if a future non-socket backing (shared +// memory, ...) needs to share `ShimTransport`. trait DropGuard: Send + Sync { fn close(&mut self); } /// Concrete, generic implementation of [`DropGuard`]. -struct SocketDropGuard { - global: Arc>, +struct SocketDropGuard { + global: Arc>, sockfd: SocketFd, } -impl DropGuard for SocketDropGuard { +impl DropGuard for SocketDropGuard { fn close(&mut self) { let _ = self .global @@ -62,8 +66,8 @@ impl ShimTransport { /// /// Connection and all subsequent I/O use the [`NetworkProxy`] directly, /// spin-polling when the operation cannot complete immediately. - pub(crate) fn connect( - global: Arc>, + pub(crate) fn connect( + global: Arc>, addr: core::net::SocketAddr, ) -> Result { // 1. Create the raw socket. @@ -143,7 +147,7 @@ mod tests { use litebox::fs::nine_p::NineP; use litebox::fs::resolver::Resolver; - use litebox::fs::{FileSystem as _, Mode, OFlags}; + use litebox::fs::{Mode, OFlags}; use crate::syscalls::tests::init_platform; @@ -259,10 +263,7 @@ mod tests { } fn connect_9p( - task: &crate::Task< - crate::syscalls::tests::TestPlatform, - crate::DefaultFS, - >, + task: &crate::Task, server: &DiodServer, ) -> Resolver { let addr = socket_addr([10, 0, 0, 1], server.port); diff --git a/litebox_shim_linux/src/wait.rs b/litebox_shim_linux/src/wait.rs index c2eedb659..562b7687b 100644 --- a/litebox_shim_linux/src/wait.rs +++ b/litebox_shim_linux/src/wait.rs @@ -6,7 +6,7 @@ //! Use a dedicated module to prevent code from accidentally accessing //! `wait_state` without going through `wait_cx()`. -use crate::{ShimFS, ShimPlatform, Task}; +use crate::{ShimPlatform, Task}; pub(crate) struct WaitState(litebox::event::wait::WaitState); @@ -21,7 +21,7 @@ impl WaitState { } } -impl Task { +impl Task { /// Returns a wait context to use to perform interruptible waits. pub(crate) fn wait_cx(&self) -> litebox::event::wait::WaitContext<'_, Platform> { self.wait_state.0.context().with_check_for_interrupt(self) @@ -48,9 +48,7 @@ impl Task { } } -impl litebox::event::wait::CheckForInterrupt - for Task -{ +impl litebox::event::wait::CheckForInterrupt for Task { fn check_for_interrupt(&self) -> bool { self.global.platform.take_pending_signals(|sig| { self.queue_signals(sig);