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 a762f4fe1..8333d3185 100644 --- a/litebox_runner_linux_on_windows_userland/tests/common/mod.rs +++ b/litebox_runner_linux_on_windows_userland/tests/common/mod.rs @@ -10,7 +10,7 @@ use litebox_platform_multiplex::Platform; pub struct TestLauncher { platform: &'static Platform, - shim_builder: litebox_shim_linux::LinuxShimBuilder, + shim_builder: litebox_shim_linux::LinuxShimBuilder, fs: litebox_shim_linux::DefaultFS, } diff --git a/litebox_runner_linux_userland/tests/loader.rs b/litebox_runner_linux_userland/tests/loader.rs index e6a0599b4..26a15f77d 100644 --- a/litebox_runner_linux_userland/tests/loader.rs +++ b/litebox_runner_linux_userland/tests/loader.rs @@ -11,7 +11,7 @@ use litebox_platform_multiplex::Platform; struct TestLauncher { platform: &'static Platform, - shim_builder: litebox_shim_linux::LinuxShimBuilder, + shim_builder: litebox_shim_linux::LinuxShimBuilder, fs: litebox_shim_linux::DefaultFS, } diff --git a/litebox_runner_snp/src/main.rs b/litebox_runner_snp/src/main.rs index 975437756..3a665722b 100644 --- a/litebox_runner_snp/src/main.rs +++ b/litebox_runner_snp/src/main.rs @@ -16,7 +16,7 @@ use litebox_platform_linux_kernel::{HostInterface, host::snp::ghcb::ghcb_prints} // FUTURE: replace this with some kind of OnceLock, or just eliminate this // entirely (ideal). -static mut SHIM: Option = None; +static mut SHIM: Option> = None; #[unsafe(no_mangle)] pub extern "C" fn floating_point_handler(_pt_regs: &mut litebox_common_linux::PtRegs) { diff --git a/litebox_shim_linux/src/lib.rs b/litebox_shim_linux/src/lib.rs index f4dccc729..ed7702148 100644 --- a/litebox_shim_linux/src/lib.rs +++ b/litebox_shim_linux/src/lib.rs @@ -21,7 +21,7 @@ use alloc::sync::Arc; use core::cell::{Cell, RefCell}; use litebox::{ LiteBox, - fd::{ErrRawIntFd, TypedFd}, + fd::TypedFd, mm::{PageManager, linux::PAGE_SIZE}, net::Network, pipes::Pipes, @@ -59,7 +59,11 @@ pub(crate) type LinuxFS = litebox::fs::layered::FileSystem< >, >; -pub(crate) type FileFd = litebox::fd::TypedFd; +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 {} /// On debug builds, logs that the user attempted to use an unsupported feature. fn log_unsupported_fmt(args: core::fmt::Arguments<'_>) { @@ -71,14 +75,14 @@ fn log_unsupported_fmt(args: core::fmt::Arguments<'_>) { } } -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 { @@ -102,12 +106,12 @@ impl litebox::shim::EnterShim for LinuxShimEntrypoints { } } -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(); @@ -122,20 +126,20 @@ impl LinuxShimEntrypoints { } /// The shim entry point structure. -pub struct LinuxShimBuilder { +pub struct LinuxShimBuilder { platform: &'static Platform, litebox: LiteBox, - fs: Option, + fs: Option, load_filter: Option, } -impl Default for LinuxShimBuilder { +impl Default for LinuxShimBuilder { fn default() -> Self { Self::new() } } -impl LinuxShimBuilder { +impl LinuxShimBuilder { /// Returns a new shim builder. pub fn new() -> Self { let platform = litebox_platform_multiplex::platform(); @@ -156,7 +160,7 @@ impl LinuxShimBuilder { /// /// NOTE: This function signature might change as better parametricity is added to file systems. /// Related: - pub fn set_fs(&mut self, fs: LinuxFS) { + pub fn set_fs(&mut self, fs: FS) { self.fs = Some(fs); } @@ -179,7 +183,7 @@ impl LinuxShimBuilder { /// # Panics /// Panics if the file system has not been set with [`set_fs`](Self::set_fs) /// before calling this method. - 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 { @@ -201,10 +205,14 @@ impl LinuxShimBuilder { } } -#[derive(Clone)] -pub struct LinuxShim(Arc); +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( @@ -213,7 +221,7 @@ impl LinuxShim { path: &str, argv: Vec, envp: Vec, - ) -> Result { + ) -> Result, loader::elf::ElfLoaderError> { let litebox_common_linux::TaskParams { pid, ppid, @@ -275,8 +283,8 @@ impl LinuxShim { } } -pub struct LoadedProgram { - pub entrypoints: LinuxShimEntrypoints, +pub struct LoadedProgram { + pub entrypoints: LinuxShimEntrypoints, pub process: LinuxShimProcess, } @@ -319,9 +327,9 @@ fn default_fs( // Special override so that `GETFL` can return stdio-specific flags pub(crate) struct StdioStatusFlags(litebox::fs::OFlags); -impl syscalls::file::FilesState { - fn initialize_stdio_in_shared_descriptors_table(&self, global: &GlobalState) { - use litebox::fs::{FileSystem as _, Mode, OFlags}; +impl syscalls::file::FilesState { + fn initialize_stdio_in_shared_descriptors_table(&self, global: &GlobalState) { + use litebox::fs::{Mode, OFlags}; let stdin = global .fs .open("/dev/stdin", OFlags::RDONLY, Mode::empty()) @@ -351,11 +359,11 @@ impl syscalls::file::FilesState { type ConstPtr = ::RawConstPointer; type MutPtr = ::RawMutPointer; -struct Descriptors { - descriptors: Vec>, +struct Descriptors { + descriptors: Vec>>, } -impl Descriptors { +impl Descriptors { fn new() -> Self { Self { descriptors: vec![ @@ -370,7 +378,11 @@ impl Descriptors { /// /// Returns the assigned file descriptor number, or the descriptor back on failure /// if the limit is exceeded. - fn insert(&mut self, task: &Task, descriptor: Descriptor) -> Result { + fn insert( + &mut self, + task: &Task, + descriptor: Descriptor, + ) -> Result> { self.insert_in_range( descriptor, 0, @@ -385,10 +397,10 @@ impl Descriptors { /// or the descriptor back if no slot is found within the limit. fn insert_in_range( &mut self, - descriptor: Descriptor, + descriptor: Descriptor, min_idx: usize, max_idx: usize, - ) -> Result { + ) -> Result> { let idx = self .descriptors .iter() @@ -412,10 +424,10 @@ impl Descriptors { /// if the index exceeds the limit. fn insert_at( &mut self, - task: &Task, - descriptor: Descriptor, + task: &Task, + descriptor: Descriptor, idx: usize, - ) -> Result, Descriptor> { + ) -> Result>, Descriptor> { if idx >= task .process() @@ -432,11 +444,11 @@ impl Descriptors { .get_mut(idx) .and_then(|v| v.replace(descriptor))) } - fn remove(&mut self, fd: u32) -> Option { + fn remove(&mut self, fd: u32) -> Option> { let fd = fd as usize; self.descriptors.get_mut(fd)?.take() } - fn get_fd(&self, fd: u32) -> Option<&Descriptor> { + fn get_fd(&self, fd: u32) -> Option<&Descriptor> { self.descriptors.get(fd as usize)?.as_ref() } @@ -445,7 +457,7 @@ impl Descriptors { } } -impl Task { +impl Task { fn close_on_exec(&self) { let files = self.files.borrow(); files @@ -467,18 +479,18 @@ impl Task { } } -enum Descriptor { +enum Descriptor { LiteBoxRawFd(usize), Eventfd { file: alloc::sync::Arc>, close_on_exec: core::sync::atomic::AtomicBool, }, Epoll { - file: alloc::sync::Arc, + file: alloc::sync::Arc>, close_on_exec: core::sync::atomic::AtomicBool, }, Unix { - file: alloc::sync::Arc, + file: alloc::sync::Arc>, close_on_exec: core::sync::atomic::AtomicBool, }, } @@ -487,53 +499,36 @@ enum Descriptor { /// /// This enum only ever stores `Arc>`s, and should not store any additional data /// alongside them (i.e., it is a trivial tagged union across the subsystems being used). -enum StrongFd { - FileSystem(Arc>), +enum StrongFd { + FileSystem(Arc>), Network(Arc>>), Pipes(Arc>>), } -impl StrongFd { - fn from_raw(files: &syscalls::file::FilesState, fd: usize) -> Result { - match files - .raw_descriptor_store - .read() - .typed_fd_at_raw_3::, Pipes>(fd) - { - Ok(r) => Ok(r), - Err(ErrRawIntFd::InvalidSubsystem) => { - // We currently only have net and fs FDs at the moment, when we add more, we need to - // expand out `StrongFd` too. - unreachable!() - } - Err(ErrRawIntFd::NotFound) => Err(Errno::EBADF), +impl StrongFd { + fn from_raw(files: &syscalls::file::FilesState, fd: usize) -> Result { + let rds = files.raw_descriptor_store.read(); + if let Ok(fd) = rds.fd_from_raw_integer::(fd) { + return Ok(StrongFd::FileSystem(fd)); } - } -} -impl From>> for StrongFd { - fn from(v: Arc>) -> Self { - StrongFd::FileSystem(v) - } -} -impl From>>> for StrongFd { - fn from(v: Arc>>) -> Self { - StrongFd::Network(v) - } -} -impl From>>> for StrongFd { - fn from(v: Arc>>) -> Self { - StrongFd::Pipes(v) + if let Ok(fd) = rds.fd_from_raw_integer::>(fd) { + return Ok(StrongFd::Network(fd)); + } + if let Ok(fd) = rds.fd_from_raw_integer::>(fd) { + return Ok(StrongFd::Pipes(fd)); + } + Err(Errno::EBADF) } } -impl syscalls::file::FilesState { +impl syscalls::file::FilesState { pub(crate) fn run_on_raw_fd( &self, fd: usize, - fs: impl FnOnce(&TypedFd) -> R, + fs: impl FnOnce(&TypedFd) -> R, net: impl FnOnce(&TypedFd>) -> R, pipes: impl FnOnce(&TypedFd>) -> R, ) -> Result { - match StrongFd::from_raw(self, fd)? { + match StrongFd::::from_raw(self, fd)? { StrongFd::FileSystem(fd) => Ok(fs(&fd)), StrongFd::Network(fd) => Ok(net(&fd)), StrongFd::Pipes(fd) => Ok(pipes(&fd)), @@ -567,7 +562,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, @@ -1139,7 +1134,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. @@ -1147,7 +1142,7 @@ struct GlobalState { /// The page manager for managing virtual memory. pm: litebox::mm::PageManager, /// The filesystem implementation. - fs: LinuxFS, + fs: FS, /// The futex manager for handling futex operations. futex_manager: FutexManager, /// The anonymous pipe implementation. @@ -1162,11 +1157,11 @@ 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>, } -struct Task { - global: Arc, +struct Task { + global: Arc>, wait_state: wait::WaitState, thread: syscalls::process::ThreadState, /// Process ID @@ -1183,12 +1178,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(); } @@ -1201,9 +1196,9 @@ 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) -> Task { + pub(crate) fn new_test_task(self: Arc) -> Task { let pid = self .next_thread_id .fetch_add(1, core::sync::atomic::Ordering::Relaxed); @@ -1230,7 +1225,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 @@ -1259,7 +1254,7 @@ mod test_utils { /// Panics if the test process is already terminating. 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 a901453be..e23c4a62e 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::Task; +use crate::{ShimFS, Task}; use litebox::platform::SystemInfoProvider as _; #[allow(non_camel_case_types)] @@ -67,7 +67,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 254b5ec62..0d62030a8 100644 --- a/litebox_shim_linux/src/loader/elf.rs +++ b/litebox_shim_linux/src/loader/elf.rs @@ -19,16 +19,16 @@ use crate::{ }; use super::stack::UserStack; -use crate::Task; +use crate::{ShimFS, Task}; // An opened elf file -struct ElfFile<'a> { - task: &'a Task, +struct ElfFile<'a, FS: ShimFS> { + task: &'a Task, fd: i32, } -impl<'a> ElfFile<'a> { - fn new(task: &'a Task, path: impl litebox::path::Arg) -> Result { +impl<'a, FS: ShimFS> ElfFile<'a, FS> { + fn new(task: &'a Task, path: impl litebox::path::Arg) -> Result { let fd = task .sys_open(path, OFlags::RDONLY, Mode::empty())? .reinterpret_as_signed(); @@ -36,13 +36,13 @@ impl<'a> ElfFile<'a> { } } -impl Drop for ElfFile<'_> { +impl Drop for ElfFile<'_, FS> { fn drop(&mut self) { self.task.sys_close(self.fd).expect("failed to close fd"); } } -impl litebox_common_linux::loader::ReadAt for &'_ ElfFile<'_> { +impl litebox_common_linux::loader::ReadAt for &'_ ElfFile<'_, FS> { type Error = Errno; fn read_at(&mut self, mut offset: u64, mut buf: &mut [u8]) -> Result<(), Self::Error> { @@ -68,7 +68,7 @@ impl litebox_common_linux::loader::ReadAt for &'_ ElfFile<'_> { } } -impl litebox_common_linux::loader::MapMemory for ElfFile<'_> { +impl litebox_common_linux::loader::MapMemory for ElfFile<'_, FS> { type Error = Errno; fn reserve(&mut self, len: usize, align: usize) -> Result { @@ -156,19 +156,19 @@ pub struct ElfLoadInfo { } /// Loader for ELF files -pub(crate) struct ElfLoader<'a> { +pub(crate) struct ElfLoader<'a, FS: ShimFS> { path: &'a str, - main: FileAndParsed<'a>, - interp: Option>, + main: FileAndParsed<'a, FS>, + interp: Option>, } -struct FileAndParsed<'a> { - file: ElfFile<'a>, +struct FileAndParsed<'a, FS: ShimFS> { + file: ElfFile<'a, FS>, parsed: ElfParsedFile, } -impl<'a> FileAndParsed<'a> { - fn new(task: &'a Task, path: impl litebox::path::Arg) -> Result { +impl<'a, FS: ShimFS> FileAndParsed<'a, FS> { + fn new(task: &'a Task, path: impl litebox::path::Arg) -> Result { let file = ElfFile::new(task, path).map_err(ElfLoaderError::OpenError)?; let mut parsed = litebox_common_linux::loader::ElfParsedFile::parse(&mut &file) .map_err(ElfLoaderError::ParseError)?; @@ -177,9 +177,9 @@ impl<'a> FileAndParsed<'a> { } } -impl<'a> ElfLoader<'a> { +impl<'a, FS: ShimFS> ElfLoader<'a, FS> { /// 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)?; diff --git a/litebox_shim_linux/src/syscalls/epoll.rs b/litebox_shim_linux/src/syscalls/epoll.rs index 038ac11ec..c6f3ea07c 100644 --- a/litebox_shim_linux/src/syscalls/epoll.rs +++ b/litebox_shim_linux/src/syscalls/epoll.rs @@ -21,7 +21,7 @@ use litebox_common_linux::{EpollEvent, EpollOp, errno::Errno}; use litebox_platform_multiplex::Platform; use super::file::FilesState; -use crate::{Descriptor, GlobalState, StrongFd}; +use crate::{Descriptor, GlobalState, ShimFS, StrongFd}; bitflags::bitflags! { /// Linux's epoll flags. @@ -34,19 +34,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, desc: &Descriptor) -> Result { +impl EpollDescriptor { + pub fn try_from(files: &FilesState, desc: &Descriptor) -> Result { match desc { - Descriptor::LiteBoxRawFd(raw_fd) => match StrongFd::from_raw(files, *raw_fd)? { + Descriptor::LiteBoxRawFd(raw_fd) => match StrongFd::::from_raw(files, *raw_fd)? { StrongFd::FileSystem(fd) => Ok(EpollDescriptor::File(fd)), StrongFd::Network(fd) => Ok(EpollDescriptor::Socket(fd)), StrongFd::Pipes(fd) => Ok(EpollDescriptor::Pipe(fd)), @@ -58,17 +58,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)), @@ -79,7 +79,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), @@ -91,12 +91,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 { @@ -132,16 +132,16 @@ impl EpollDescriptor { } } -pub(crate) struct EpollFile { +pub(crate) struct EpollFile { interests: litebox::sync::Mutex< litebox_platform_multiplex::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()), @@ -152,7 +152,7 @@ impl EpollFile { pub(crate) fn wait( &self, - global: &GlobalState, + global: &GlobalState, cx: &WaitContext<'_, Platform>, maxevents: usize, ) -> Result, WaitError> { @@ -172,10 +172,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 { @@ -196,9 +196,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(); @@ -233,9 +233,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 @@ -292,7 +292,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(), @@ -305,10 +305,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, @@ -320,13 +320,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, @@ -338,7 +338,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(); @@ -373,21 +373,21 @@ impl EpollEntry { } } -impl Observer for EpollEntry { +impl Observer for EpollEntry { fn on_events(&self, _events: &Events) { self.ready.push(self); } } -struct ReadySet { +struct ReadySet { entries: litebox::sync::Mutex< litebox_platform_multiplex::Platform, - VecDeque>, + VecDeque>>, >, pollee: Pollee, } -impl ReadySet { +impl ReadySet { fn new() -> Self { Self { entries: litebox::sync::Mutex::new(VecDeque::new()), @@ -395,7 +395,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; @@ -412,7 +412,12 @@ impl ReadySet { self.pollee.notify_observers(Events::IN); } - fn pop_multiple(&self, global: &GlobalState, maxevents: usize, events: &mut Vec) { + fn pop_multiple( + &self, + global: &GlobalState, + maxevents: usize, + events: &mut Vec, + ) { let mut nums = self.entries.lock().len(); while nums > 0 { nums -= 1; @@ -495,10 +500,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; @@ -541,16 +546,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(()); @@ -602,7 +607,7 @@ mod test { extern crate std; - 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 8c7283712..7e05ed22b 100644 --- a/litebox_shim_linux/src/syscalls/file.rs +++ b/litebox_shim_linux/src/syscalls/file.rs @@ -11,7 +11,7 @@ use alloc::{ use litebox::{ event::{Events, wait::WaitError}, fd::{FdEnabledSubsystem, MetadataError, TypedFd}, - fs::{FileSystem as _, Mode, OFlags, SeekWhence}, + fs::{Mode, OFlags, SeekWhence}, path, platform::{RawConstPointer, RawMutPointer}, utils::{ReinterpretSignedExt as _, ReinterpretUnsignedExt as _, TruncateExt as _}, @@ -22,7 +22,7 @@ use litebox_common_linux::{ }; use litebox_platform_multiplex::Platform; -use crate::{ConstPtr, Descriptor, Descriptors, GlobalState, MutPtr, Task}; +use crate::{ConstPtr, Descriptor, Descriptors, GlobalState, MutPtr, ShimFS, Task}; use core::sync::atomic::Ordering; /// Task state shared by `CLONE_FS`. @@ -51,12 +51,12 @@ impl FsState { } /// Task state shared by `CLONE_FILES`. -pub(crate) struct FilesState { - pub file_descriptors: litebox::sync::RwLock, +pub(crate) struct FilesState { + pub file_descriptors: litebox::sync::RwLock>, pub raw_descriptor_store: litebox::sync::RwLock, } -impl FilesState { +impl FilesState { pub fn new() -> Self { Self { file_descriptors: litebox::sync::RwLock::new(Descriptors::new()), @@ -113,7 +113,7 @@ impl FsPath

{ } } -impl Task { +impl Task { fn get_umask(&self) -> Mode { self.fs.borrow().umask() } @@ -376,7 +376,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(fd) = u32::try_from(fd) else { @@ -406,7 +406,7 @@ impl Task { self.global.fs.mkdir(pathname, mode).map_err(Errno::from) } - pub(crate) fn do_close(&self, desc: Descriptor) -> Result<(), Errno> { + pub(crate) fn do_close(&self, desc: Descriptor) -> Result<(), Errno> { let files = self.files.borrow(); match desc { Descriptor::LiteBoxRawFd(raw_fd) => { @@ -553,7 +553,7 @@ where Ok(total_written) } -impl Task { +impl Task { /// Handle syscall `writev` pub fn sys_writev( &self, @@ -690,8 +690,8 @@ impl Task { } } -impl Descriptor { - fn stat(&self, task: &Task) -> Result { +impl Descriptor { + fn stat(&self, task: &Task) -> Result { let fstat = match self { Descriptor::LiteBoxRawFd(raw_fd) => task .files @@ -798,13 +798,13 @@ impl Descriptor { pub(crate) fn get_file_descriptor_flags( &self, - 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 @@ -833,12 +833,12 @@ impl Descriptor { } fn set_file_descriptor_flags( &self, - 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, ) { @@ -868,7 +868,7 @@ impl Descriptor { } } -impl Task { +impl Task { fn do_stat(&self, pathname: impl path::Arg, follow_symlink: bool) -> Result { let normalized_path = pathname.normalized()?; let path = if follow_symlink { @@ -1182,7 +1182,7 @@ impl Task { const DEFAULT_PIPE_BUF_SIZE: usize = 1024 * 1024; -impl Task { +impl Task { /// Handle syscall `pipe2` pub fn sys_pipe2(&self, flags: OFlags) -> Result<(u32, u32), Errno> { let (pipe_flags, cloexec) = { @@ -1293,7 +1293,7 @@ impl Task { } } - fn is_stdio(&self, fd: &TypedFd) -> Result { + fn is_stdio(&self, fd: &TypedFd) -> Result { match self.global.fs.fd_file_status(fd) { Ok(status) => { // See https://www.kernel.org/doc/Documentation/admin-guide/devices.txt @@ -1729,17 +1729,17 @@ impl Task { Ok(count) } - fn do_dup(&self, file: &Descriptor, flags: OFlags) -> Result { + fn do_dup(&self, file: &Descriptor, flags: OFlags) -> Result, Errno> { let close_on_exec = flags.contains(OFlags::CLOEXEC); let files = self.files.borrow(); match file { Descriptor::LiteBoxRawFd(raw_fd) => { - fn dup( - global: &GlobalState, - files: &FilesState, + fn dup( + global: &GlobalState, + files: &FilesState, fd: &TypedFd, close_on_exec: bool, - ) -> Result { + ) -> Result, Errno> { let mut dt = global.litebox.descriptor_table_mut(); let fd: TypedFd<_> = dt.duplicate(fd).ok_or(Errno::EBADF)?; if close_on_exec { @@ -1843,7 +1843,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 bab87ad60..4e82dacd8 100644 --- a/litebox_shim_linux/src/syscalls/misc.rs +++ b/litebox_shim_linux/src/syscalls/misc.rs @@ -5,14 +5,14 @@ //! //! Examples of syscalls handled here include `getrandom`, `uname`, and similar operations. -use crate::Task; +use crate::{ShimFS, Task}; use litebox::{ platform::{Instant as _, RawConstPointer as _, RawMutPointer as _, TimeProvider as _}, utils::TruncateExt as _, }; use litebox_common_linux::errno::Errno; -impl Task { +impl Task { /// Handle syscall `getrandom`. pub(crate) fn sys_getrandom( &self, @@ -67,7 +67,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, @@ -108,7 +108,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 8743d8c53..3f541b523 100644 --- a/litebox_shim_linux/src/syscalls/mm.rs +++ b/litebox_shim_linux/src/syscalls/mm.rs @@ -11,6 +11,7 @@ use litebox::{ use litebox_common_linux::{MRemapFlags, MapFlags, ProtFlags, errno::Errno}; use crate::MutPtr; +use crate::ShimFS; use crate::Task; #[inline] @@ -29,7 +30,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 2617afd5a..5f266228f 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, IntoBytes}; use crate::{ConstPtr, Descriptor, MutPtr}; -use crate::{GlobalState, Task}; +use crate::{GlobalState, ShimFS, Task}; use crate::{ Platform, syscalls::unix::{CSockUnixAddr, UnixSocket, UnixSocketAddr}, @@ -56,7 +56,7 @@ macro_rules! convert_flags { pub(super) type SocketFd = litebox::net::SocketFd; -impl super::file::FilesState { +impl super::file::FilesState { fn with_socket_fd( &self, raw_fd: usize, @@ -87,7 +87,7 @@ impl super::file::FilesState { &self, sockfd: u32, inet_op: impl FnOnce(&SocketFd) -> Result, - unix_op: impl FnOnce(Arc) -> Result, + unix_op: impl FnOnce(Arc>) -> Result, ) -> Result { let file_table = self.file_descriptors.read(); match file_table.get_fd(sockfd).ok_or(Errno::EBADF)? { @@ -191,7 +191,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 { fn initialize_socket( &self, fd: &SocketFd, @@ -900,7 +900,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, @@ -1167,7 +1167,7 @@ pub(crate) fn write_sockaddr_to_user( addrlen.write_at_offset(0, len).ok_or(Errno::EFAULT) } -impl Task { +impl Task { /// Handle syscall `accept` pub(crate) fn sys_accept( &self, @@ -1660,7 +1660,7 @@ impl Task { } #[cfg(target_arch = "x86")] -impl Task { +impl Task { pub(crate) fn sys_socketcall(&self, call: i32, args: ConstPtr) -> Result { use crate::ToSyscallResult; use litebox_common_linux::SocketcallType; @@ -1856,7 +1856,7 @@ mod tests { const SERVER_PORT: u16 = 8080; const CLIENT_PORT: u16 = 8081; - fn init_platform(tun_device_name: Option<&str>) -> crate::Task { + fn init_platform(tun_device_name: Option<&str>) -> crate::Task { let task = crate::syscalls::tests::init_platform(tun_device_name); let global = task.global.clone(); if tun_device_name.is_some() { @@ -1877,12 +1877,17 @@ mod tests { task } - fn close_socket(task: &crate::Task, fd: u32) { + fn close_socket(task: &crate::Task, fd: u32) { task.sys_close(i32::try_from(fd).unwrap()) .expect("close socket failed"); } - fn epoll_add(task: &crate::Task, epfd: i32, target_fd: u32, events: litebox::event::Events) { + fn epoll_add( + task: &crate::Task, + epfd: i32, + target_fd: u32, + events: litebox::event::Events, + ) { let ev = litebox_common_linux::EpollEvent { events: events.bits(), data: u64::from(target_fd), @@ -1899,7 +1904,7 @@ mod tests { } fn epoll_wait( - task: &crate::Task, + task: &crate::Task, epfd: i32, events: &mut [litebox_common_linux::EpollEvent], ) -> usize { @@ -1909,7 +1914,7 @@ mod tests { } fn test_tcp_socket_as_server( - task: &crate::Task, + task: &crate::Task, ip: [u8; 4], port: u16, is_nonblocking: bool, @@ -2482,11 +2487,15 @@ mod unix_tests { extern crate std; - fn create_unix_socket(task: &Task, ty: SockType, flags: SockFlags) -> u32 { + fn create_unix_socket(task: &Task, ty: SockType, flags: SockFlags) -> u32 { task.do_socket(AddressFamily::UNIX, ty, flags, 0).unwrap() } - fn create_unix_server_socket(task: &Task, addr: &str, flags: SockFlags) -> Result { + fn create_unix_server_socket( + task: &Task, + addr: &str, + flags: SockFlags, + ) -> Result { let server_fd = create_unix_socket(task, SockType::Stream, flags); task.do_bind( server_fd, @@ -2496,12 +2505,12 @@ mod unix_tests { Ok(server_fd) } - fn close_socket(task: &crate::Task, fd: u32) { + fn close_socket(task: &crate::Task, fd: u32) { task.sys_close(i32::try_from(fd).unwrap()) .expect("close socket failed"); } - fn ppoll(task: &Task, fd: u32, events: Events) { + fn ppoll(task: &Task, fd: u32, events: Events) { let fd = i32::try_from(fd).unwrap(); let mut pollfd = [litebox_common_linux::Pollfd { fd, diff --git a/litebox_shim_linux/src/syscalls/process.rs b/litebox_shim_linux/src/syscalls/process.rs index 4f0abf1e9..05e015244 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::{ConstPtr, MutPtr, Task}; +use crate::{ConstPtr, MutPtr, ShimFS, Task}; use alloc::boxed::Box; use alloc::collections::btree_map::BTreeMap; use alloc::sync::Arc; @@ -228,7 +228,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(); @@ -320,7 +320,7 @@ pub(crate) struct Credentials { pub egid: u32, } -impl Task { +impl Task { pub(crate) fn process(&self) -> &Arc { &self.thread.process } @@ -499,7 +499,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(); @@ -547,12 +547,12 @@ type ThreadLocalDescriptor = MutPtr; #[cfg(target_arch = "x86")] type ThreadLocalDescriptor = litebox_common_linux::UserDesc; -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( @@ -568,7 +568,7 @@ impl litebox::shim::InitThread for NewThreadArgs { } } -impl Task { +impl Task { pub(crate) fn sys_clone( &self, ctx: &litebox_common_linux::PtRegs, @@ -853,7 +853,7 @@ impl ResourceLimits { } } -impl Task { +impl Task { /// Get resource limits, and optionally set new limits. pub(crate) fn do_prlimit( &self, @@ -1189,7 +1189,7 @@ impl CpuSet { } } -impl Task { +impl Task { /// Handle syscall `sched_getaffinity`. /// /// Note this is a dummy implementation that always returns the same CPU set @@ -1200,7 +1200,7 @@ impl Task { } } -impl Task { +impl Task { /// Handle syscall `futex` pub(crate) fn sys_futex( &self, @@ -1276,7 +1276,7 @@ impl Task { const MAX_VEC: usize = 4096; // limit count const MAX_TOTAL_BYTES: usize = 256 * 1024; // size cap -impl Task { +impl Task { /// Handle syscall `execve`. pub(crate) fn sys_execve( &self, @@ -1377,7 +1377,7 @@ impl Task { /// to start executing it. pub(crate) fn load_program( &self, - mut loader: crate::loader::elf::ElfLoader<'_>, + mut loader: crate::loader::elf::ElfLoader<'_, FS>, argv: Vec, mut 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 a48b98dfa..560431d26 100644 --- a/litebox_shim_linux/src/syscalls/signal/mod.rs +++ b/litebox_shim_linux/src/syscalls/signal/mod.rs @@ -16,7 +16,7 @@ use x86_64 as arch; use zerocopy::FromZeros; use crate::syscalls::process::ExitStatus; -use crate::{ConstPtr, MutPtr, Task}; +use crate::{ConstPtr, MutPtr, ShimFS, Task}; use alloc::collections::vec_deque::VecDeque; use alloc::sync::Arc; use core::cell::{Cell, RefCell}; @@ -378,7 +378,7 @@ impl SignalState { /// A fault when delivering a signal. struct DeliverFault; -impl Task { +impl Task { pub(crate) fn sys_rt_sigprocmask( &self, how: SigmaskHow, diff --git a/litebox_shim_linux/src/syscalls/signal/x86.rs b/litebox_shim_linux/src/syscalls/signal/x86.rs index 34c6872dc..07da741d9 100644 --- a/litebox_shim_linux/src/syscalls/signal/x86.rs +++ b/litebox_shim_linux/src/syscalls/signal/x86.rs @@ -39,7 +39,7 @@ struct SignalFrameRt { ucontext: Ucontext, } -impl Task { +impl Task { /// Legacy signal return syscall implementation for x86. pub(crate) fn sys_sigreturn(&self, ctx: &mut PtRegs) -> Result { let lctx_addr = ctx.esp.wrapping_sub(8); diff --git a/litebox_shim_linux/src/syscalls/tests.rs b/litebox_shim_linux/src/syscalls/tests.rs index e6c7e95c5..124454ab5 100644 --- a/litebox_shim_linux/src/syscalls/tests.rs +++ b/litebox_shim_linux/src/syscalls/tests.rs @@ -17,7 +17,7 @@ const TEST_TAR_FILE: &[u8] = include_bytes!("../../../litebox/src/fs/test.tar"); not(target_os = "linux"), expect(unused_variables, reason = "ignored parameter on non-linux platforms") )] -pub(crate) fn init_platform(tun_device_name: Option<&str>) -> crate::Task { +pub(crate) fn init_platform(tun_device_name: Option<&str>) -> crate::Task { static PLATFORM_INIT: std::sync::Once = std::sync::Once::new(); PLATFORM_INIT.call_once(|| { #[cfg(target_os = "linux")] diff --git a/litebox_shim_linux/src/syscalls/unix.rs b/litebox_shim_linux/src/syscalls/unix.rs index d1959eb2a..9395bf7d1 100644 --- a/litebox_shim_linux/src/syscalls/unix.rs +++ b/litebox_shim_linux/src/syscalls/unix.rs @@ -20,7 +20,7 @@ use litebox::{ polling::{Pollee, TryOpError}, wait::WaitContext, }, - fs::{FileSystem, Mode, OFlags, errors::OpenError}, + fs::{Mode, OFlags, errors::OpenError}, sync::{Mutex, RwLock}, utils::TruncateExt as _, }; @@ -30,7 +30,7 @@ use litebox_common_linux::{ }; use crate::{ - ConstPtr, FileFd, GlobalState, MutPtr, Task, + ConstPtr, FileFd, GlobalState, MutPtr, ShimFS, Task, channel::{Channel, ReadEnd, WriteEnd}, syscalls::net::{SocketOptionValue, SocketOptions}, }; @@ -61,8 +61,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), } @@ -94,7 +94,11 @@ impl UnixSocketAddr { /// /// Returns an error if the address cannot be bound (e.g., file doesn't exist, /// permission denied). - fn bind(self, task: &Task, is_server: bool) -> Result { + fn bind( + self, + task: &Task, + is_server: bool, + ) -> Result, Errno> { match self { UnixSocketAddr::Path(path) => { let flags = if is_server { @@ -139,7 +143,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 { @@ -149,7 +153,7 @@ impl UnixBoundSocketAddr { } } -impl Drop for UnixBoundSocketAddr { +impl Drop for UnixBoundSocketAddr { fn drop(&mut self) { match self { Self::Path((_, file, global)) => { @@ -160,8 +164,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()), @@ -173,13 +177,13 @@ 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, } -impl UnixInitStream { +impl UnixInitStream { fn new() -> Self { Self { addr: None, @@ -188,7 +192,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); } @@ -207,8 +211,8 @@ impl UnixInitStream { fn listen( self, backlog: u16, - global: &Arc, - ) -> Result { + global: &Arc>, + ) -> Result, (Self, Errno)> { let Some(addr) = self.addr else { return Err((self, Errno::EINVAL)); }; @@ -227,8 +231,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 } = self; UnixConnectedStream::new_pair(addr.map(Arc::new), Some(Arc::new(pollee)), Some(peer_addr)) } @@ -237,18 +241,18 @@ 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, + addr: Arc>, /// Maximum number of pending connections limit: AtomicU16, /// Queue of pending connections (None when shut down) - sockets: Mutex>>, + sockets: Mutex>>>, pollee: Pollee, } -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), limit: AtomicU16::new(backlog), @@ -265,8 +269,8 @@ impl Backlog { /// Attempts to establish a connection without blocking. fn try_connect( &self, - init: UnixInitStream, - ) -> Result { + init: UnixInitStream, + ) -> Result, (UnixInitStream, Errno)> { let mut sockets = self.sockets.lock(); let Some(sockets) = &mut *sockets else { // the server socket is shutdown @@ -286,7 +290,7 @@ impl Backlog { } /// Attempts to accept a pending connection without blocking. - fn try_accept(&self) -> Result> { + fn try_accept(&self) -> Result, TryOpError> { let mut sockets = self.sockets.lock(); let Some(sockets) = &mut *sockets else { // the server socket is shutdown @@ -325,12 +329,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); @@ -345,12 +349,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(); @@ -366,18 +370,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(), @@ -391,12 +395,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() } } @@ -409,8 +413,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. @@ -419,12 +423,12 @@ struct UnixConnectedStream { } const UNIX_BUF_SIZE: usize = 65536; -impl UnixConnectedStream { +impl UnixConnectedStream { /// Creates a pair of connected Unix stream sockets. fn new_pair( - addr: Option>, + addr: Option>>, pollee: Option>>, - peer: Option>, + peer: Option>>, ) -> (Self, Self) { let (addr1, addr2) = AddrView::new_pair(addr, peer); let pollee1 = pollee.unwrap_or(Arc::new(Pollee::new())); @@ -519,20 +523,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, @@ -540,12 +544,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)), } @@ -553,7 +557,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")) @@ -561,7 +565,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")) @@ -569,7 +573,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")); @@ -577,7 +581,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), @@ -591,7 +595,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) => { @@ -610,7 +614,7 @@ impl UnixStream { }) } - fn lookup(&self, task: &Task, addr: &UnixSocketAddr) -> Result, Errno> { + fn lookup(&self, task: &Task, addr: &UnixSocketAddr) -> Result>, Errno> { let guard = task.global.unix_addr_table.read(); let Some(key) = addr.to_key() else { return Err(Errno::EINVAL); @@ -623,7 +627,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(())), @@ -639,7 +643,7 @@ impl UnixStream { } fn connect( &self, - task: &Task, + task: &Task, addr: UnixSocketAddr, is_nonblocking: bool, ) -> Result<(), Errno> { @@ -664,8 +668,8 @@ impl UnixStream { cx: &WaitContext<'_, crate::Platform>, mut peer: Option<&mut UnixSocketAddr>, is_nonblocking: bool, - ) -> Result { - let backlog = self.with_state_ref(|state| -> Result, Errno> { + ) -> Result, Errno> { + let backlog = self.with_state_ref(|state| -> Result>, Errno> { let listen = state.listen().ok_or(Errno::EINVAL)?; Ok(listen.backlog.clone()) })?; @@ -900,9 +904,9 @@ impl ReadEnd { } } -struct UnixDatagramInner { +struct UnixDatagramInner { /// The local address this socket is bound to, if any. - addr: Option<(UnixBoundSocketAddr, Arc)>, + addr: Option<(UnixBoundSocketAddr, Arc>)>, /// 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>, @@ -912,11 +916,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(); @@ -932,9 +936,9 @@ impl Drop for UnixDatagramInner { } } -impl 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() { return if addr.is_unnamed() { Ok(()) @@ -960,7 +964,7 @@ impl UnixDatagramInner { } } -impl UnixDatagram { +impl UnixDatagram { fn new() -> Self { Self { inner: RwLock::new(UnixDatagramInner { @@ -972,7 +976,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) = @@ -1001,14 +1005,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(); @@ -1029,7 +1033,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> { self.inner.write().connected_send_channel = Some((self.lookup(task, addr.clone())?, addr)); Ok(()) } @@ -1067,7 +1071,7 @@ impl UnixDatagram { /// connected peer (set via `connect()`). fn sendto( &self, - task: &Task, + task: &Task, timeout: Option, buf: &[u8], is_nonblocking: bool, @@ -1132,18 +1136,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 { @@ -1167,21 +1171,21 @@ 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), } } - pub(super) fn listen(&self, backlog: u16, global: &Arc) -> Result<(), Errno> { + pub(super) fn listen(&self, backlog: u16, global: &Arc>) -> Result<(), Errno> { match &self.inner { UnixSocketInner::Stream(stream) => stream.listen(backlog, global), UnixSocketInner::Datagram(_) => Err(Errno::EOPNOTSUPP), } } - 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)) @@ -1195,7 +1199,7 @@ impl UnixSocket { cx: &WaitContext<'_, crate::Platform>, flags: SockFlags, peer: Option<&mut UnixSocketAddr>, - ) -> Result { + ) -> Result, Errno> { match &self.inner { UnixSocketInner::Stream(stream) => { let accepted = stream.accept( @@ -1212,7 +1216,7 @@ impl UnixSocket { pub(super) fn sendto( &self, - task: &Task, + task: &Task, buf: &[u8], flags: SendFlags, addr: Option, @@ -1287,7 +1291,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); @@ -1315,7 +1319,7 @@ impl UnixSocket { pub(super) fn setsockopt( &self, - global: &GlobalState, + global: &GlobalState, optname: SocketOptionName, optval: ConstPtr, optlen: usize, @@ -1372,7 +1376,7 @@ impl UnixSocket { } pub(super) fn getsockopt( &self, - global: &GlobalState, + global: &GlobalState, optname: SocketOptionName, optval: MutPtr, len: u32, @@ -1444,7 +1448,7 @@ impl UnixSocket { super::common_functions_for_file_status!(); } -impl IOPollable for UnixSocket { +impl IOPollable for UnixSocket { fn register_observer( &self, observer: Weak>, @@ -1472,11 +1476,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/wait.rs b/litebox_shim_linux/src/wait.rs index 568067945..43a35e742 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::{Platform, Task}; +use crate::{Platform, ShimFS, 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) @@ -43,7 +43,7 @@ impl Task { } } -impl litebox::event::wait::CheckForInterrupt for Task { +impl litebox::event::wait::CheckForInterrupt for Task { fn check_for_interrupt(&self) -> bool { self.is_exiting() || self.has_pending_signals() }