From c3152c4978176e23a4940ad3cb6f1261dad8d7a4 Mon Sep 17 00:00:00 2001 From: LI Qing Date: Tue, 18 Apr 2023 18:58:45 +0800 Subject: [PATCH] Rewrite FileTable with SlotVec --- .../libs/jinux-std/src/fs/file_handle/mod.rs | 8 +- services/libs/jinux-std/src/fs/file_table.rs | 116 ++++++++++++------ .../libs/jinux-std/src/fs/procfs/pid/fd.rs | 4 +- services/libs/jinux-std/src/syscall/fcntl.rs | 3 +- 4 files changed, 84 insertions(+), 47 deletions(-) diff --git a/services/libs/jinux-std/src/fs/file_handle/mod.rs b/services/libs/jinux-std/src/fs/file_handle/mod.rs index 01cd09aa0..595f31925 100644 --- a/services/libs/jinux-std/src/fs/file_handle/mod.rs +++ b/services/libs/jinux-std/src/fs/file_handle/mod.rs @@ -23,14 +23,14 @@ enum Inner { } impl FileHandle { - pub fn new_file(file: Arc) -> Self { + pub fn new_file(file: Arc) -> Arc { let inner = Inner::File(file); - Self { inner } + Arc::new(Self { inner }) } - pub fn new_inode_handle(inode_handle: InodeHandle) -> Self { + pub fn new_inode_handle(inode_handle: InodeHandle) -> Arc { let inner = Inner::Inode(inode_handle); - Self { inner } + Arc::new(Self { inner }) } pub fn as_file(&self) -> Option<&Arc> { diff --git a/services/libs/jinux-std/src/fs/file_table.rs b/services/libs/jinux-std/src/fs/file_table.rs index cc47f45cd..a2345c002 100644 --- a/services/libs/jinux-std/src/fs/file_table.rs +++ b/services/libs/jinux-std/src/fs/file_table.rs @@ -1,92 +1,115 @@ use crate::events::{Events, Observer, Subject}; use crate::prelude::*; +use core::cell::Cell; +use jinux_util::slot_vec::SlotVec; + use super::{ file_handle::FileHandle, - stdio::{Stderr, Stdin, Stdout, FD_STDERR, FD_STDIN, FD_STDOUT}, + stdio::{Stderr, Stdin, Stdout}, }; pub type FileDescripter = i32; pub struct FileTable { - table: BTreeMap, + table: SlotVec, subject: Subject, } impl FileTable { pub fn new() -> Self { Self { - table: BTreeMap::new(), + table: SlotVec::new(), subject: Subject::new(), } } pub fn new_with_stdio() -> Self { - let mut table = BTreeMap::new(); + let mut table = SlotVec::new(); let stdin = Stdin::new_with_default_console(); let stdout = Stdout::new_with_default_console(); let stderr = Stderr::new_with_default_console(); - table.insert(FD_STDIN, FileHandle::new_file(Arc::new(stdin))); - table.insert(FD_STDOUT, FileHandle::new_file(Arc::new(stdout))); - table.insert(FD_STDERR, FileHandle::new_file(Arc::new(stderr))); + table.put(FileTableEntry::new( + FileHandle::new_file(Arc::new(stdin)), + false, + )); + table.put(FileTableEntry::new( + FileHandle::new_file(Arc::new(stdout)), + false, + )); + table.put(FileTableEntry::new( + FileHandle::new_file(Arc::new(stderr)), + false, + )); Self { table, subject: Subject::new(), } } - pub fn dup(&mut self, fd: FileDescripter, new_fd: Option) -> Result<()> { - let file = self.table.get(&fd).map_or_else( + pub fn dup(&mut self, fd: FileDescripter, new_fd: FileDescripter) -> Result { + let entry = self.table.get(fd as usize).map_or_else( || return_errno_with_message!(Errno::ENOENT, "No such file"), - |f| Ok(f.clone()), + |e| Ok(e.clone()), )?; - let new_fd = if let Some(new_fd) = new_fd { - new_fd - } else { - self.max_fd() + 1 + + // Get the lowest-numbered available fd equal to or greater than `new_fd`. + let get_min_free_fd = || -> usize { + let new_fd = new_fd as usize; + if self.table.get(new_fd).is_none() { + return new_fd; + } + + for idx in new_fd + 1..self.table.slots_len() { + if self.table.get(idx).is_none() { + return idx; + } + } + self.table.slots_len() }; - if self.table.contains_key(&new_fd) { - return_errno_with_message!(Errno::EBADF, "Fd exists"); - } - self.table.insert(new_fd, file); - Ok(()) + let min_free_fd = get_min_free_fd(); + self.table.put_at(min_free_fd, entry); + Ok(min_free_fd as FileDescripter) } - fn max_fd(&self) -> FileDescripter { - self.table.iter().map(|(fd, _)| fd.clone()).max().unwrap() + pub fn insert(&mut self, item: Arc) -> FileDescripter { + let entry = FileTableEntry::new(item, false); + self.table.put(entry) as FileDescripter } - pub fn insert(&mut self, item: FileHandle) -> FileDescripter { - let fd = self.max_fd() + 1; - self.table.insert(fd, item); - fd - } - - pub fn insert_at(&mut self, fd: FileDescripter, item: FileHandle) -> Option { - let file = self.table.insert(fd, item); - if file.is_some() { + pub fn insert_at( + &mut self, + fd: FileDescripter, + item: Arc, + ) -> Option> { + let entry = FileTableEntry::new(item, false); + let entry = self.table.put_at(fd as usize, entry); + if entry.is_some() { self.notify_close_fd_event(fd); } - file + entry.map(|e| e.file) } - pub fn close_file(&mut self, fd: FileDescripter) -> Option { - let file = self.table.remove(&fd); - if file.is_some() { + pub fn close_file(&mut self, fd: FileDescripter) -> Option> { + let entry = self.table.remove(fd as usize); + if entry.is_some() { self.notify_close_fd_event(fd); } - file + entry.map(|e| e.file) } - pub fn get_file(&self, fd: FileDescripter) -> Result<&FileHandle> { + pub fn get_file(&self, fd: FileDescripter) -> Result<&Arc> { self.table - .get(&fd) + .get(fd as usize) + .map(|entry| &entry.file) .ok_or(Error::with_message(Errno::EBADF, "fd not exits")) } - pub fn fds_and_files(&self) -> impl Iterator { - self.table.iter() + pub fn fds_and_files(&self) -> impl Iterator)> { + self.table + .idxes_and_items() + .map(|(idx, entry)| (idx as FileDescripter, &entry.file)) } pub fn register_observer(&self, observer: Weak>) { @@ -126,3 +149,18 @@ pub enum FdEvents { } impl Events for FdEvents {} + +#[derive(Clone)] +struct FileTableEntry { + file: Arc, + close_on_exec: Cell, +} + +impl FileTableEntry { + pub fn new(file: Arc, close_on_exec: bool) -> Self { + Self { + file, + close_on_exec: Cell::new(close_on_exec), + } + } +} diff --git a/services/libs/jinux-std/src/fs/procfs/pid/fd.rs b/services/libs/jinux-std/src/fs/procfs/pid/fd.rs index c7778ae15..db422ec29 100644 --- a/services/libs/jinux-std/src/fs/procfs/pid/fd.rs +++ b/services/libs/jinux-std/src/fs/procfs/pid/fd.rs @@ -62,10 +62,10 @@ impl DirOps for FdDirOps { } /// Represents the inode at `/proc/[pid]/fd/N`. -struct FileSymOps(FileHandle); +struct FileSymOps(Arc); impl FileSymOps { - pub fn new_inode(file: FileHandle, parent: Weak) -> Arc { + pub fn new_inode(file: Arc, parent: Weak) -> Arc { ProcSymBuilder::new(Self(file)) .parent(parent) .build() diff --git a/services/libs/jinux-std/src/syscall/fcntl.rs b/services/libs/jinux-std/src/syscall/fcntl.rs index 835081bf1..e6e539647 100644 --- a/services/libs/jinux-std/src/syscall/fcntl.rs +++ b/services/libs/jinux-std/src/syscall/fcntl.rs @@ -12,8 +12,7 @@ pub fn sys_fcntl(fd: FileDescripter, cmd: i32, arg: u64) -> Result {