Rewrite FileTable with SlotVec

This commit is contained in:
LI Qing
2023-04-18 18:58:45 +08:00
committed by Tate, Hongliang Tian
parent 0abe40e0f8
commit c3152c4978
4 changed files with 84 additions and 47 deletions

View File

@ -23,14 +23,14 @@ enum Inner {
} }
impl FileHandle { impl FileHandle {
pub fn new_file(file: Arc<dyn File>) -> Self { pub fn new_file(file: Arc<dyn File>) -> Arc<Self> {
let inner = Inner::File(file); 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<Self> {
let inner = Inner::Inode(inode_handle); let inner = Inner::Inode(inode_handle);
Self { inner } Arc::new(Self { inner })
} }
pub fn as_file(&self) -> Option<&Arc<dyn File>> { pub fn as_file(&self) -> Option<&Arc<dyn File>> {

View File

@ -1,92 +1,115 @@
use crate::events::{Events, Observer, Subject}; use crate::events::{Events, Observer, Subject};
use crate::prelude::*; use crate::prelude::*;
use core::cell::Cell;
use jinux_util::slot_vec::SlotVec;
use super::{ use super::{
file_handle::FileHandle, file_handle::FileHandle,
stdio::{Stderr, Stdin, Stdout, FD_STDERR, FD_STDIN, FD_STDOUT}, stdio::{Stderr, Stdin, Stdout},
}; };
pub type FileDescripter = i32; pub type FileDescripter = i32;
pub struct FileTable { pub struct FileTable {
table: BTreeMap<FileDescripter, FileHandle>, table: SlotVec<FileTableEntry>,
subject: Subject<FdEvents>, subject: Subject<FdEvents>,
} }
impl FileTable { impl FileTable {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
table: BTreeMap::new(), table: SlotVec::new(),
subject: Subject::new(), subject: Subject::new(),
} }
} }
pub fn new_with_stdio() -> Self { pub fn new_with_stdio() -> Self {
let mut table = BTreeMap::new(); let mut table = SlotVec::new();
let stdin = Stdin::new_with_default_console(); let stdin = Stdin::new_with_default_console();
let stdout = Stdout::new_with_default_console(); let stdout = Stdout::new_with_default_console();
let stderr = Stderr::new_with_default_console(); let stderr = Stderr::new_with_default_console();
table.insert(FD_STDIN, FileHandle::new_file(Arc::new(stdin))); table.put(FileTableEntry::new(
table.insert(FD_STDOUT, FileHandle::new_file(Arc::new(stdout))); FileHandle::new_file(Arc::new(stdin)),
table.insert(FD_STDERR, FileHandle::new_file(Arc::new(stderr))); false,
));
table.put(FileTableEntry::new(
FileHandle::new_file(Arc::new(stdout)),
false,
));
table.put(FileTableEntry::new(
FileHandle::new_file(Arc::new(stderr)),
false,
));
Self { Self {
table, table,
subject: Subject::new(), subject: Subject::new(),
} }
} }
pub fn dup(&mut self, fd: FileDescripter, new_fd: Option<FileDescripter>) -> Result<()> { pub fn dup(&mut self, fd: FileDescripter, new_fd: FileDescripter) -> Result<FileDescripter> {
let file = self.table.get(&fd).map_or_else( let entry = self.table.get(fd as usize).map_or_else(
|| return_errno_with_message!(Errno::ENOENT, "No such file"), || 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 // Get the lowest-numbered available fd equal to or greater than `new_fd`.
} else { let get_min_free_fd = || -> usize {
self.max_fd() + 1 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 { pub fn insert(&mut self, item: Arc<FileHandle>) -> FileDescripter {
self.table.iter().map(|(fd, _)| fd.clone()).max().unwrap() let entry = FileTableEntry::new(item, false);
self.table.put(entry) as FileDescripter
} }
pub fn insert(&mut self, item: FileHandle) -> FileDescripter { pub fn insert_at(
let fd = self.max_fd() + 1; &mut self,
self.table.insert(fd, item); fd: FileDescripter,
fd item: Arc<FileHandle>,
} ) -> Option<Arc<FileHandle>> {
let entry = FileTableEntry::new(item, false);
pub fn insert_at(&mut self, fd: FileDescripter, item: FileHandle) -> Option<FileHandle> { let entry = self.table.put_at(fd as usize, entry);
let file = self.table.insert(fd, item); if entry.is_some() {
if file.is_some() {
self.notify_close_fd_event(fd); self.notify_close_fd_event(fd);
} }
file entry.map(|e| e.file)
} }
pub fn close_file(&mut self, fd: FileDescripter) -> Option<FileHandle> { pub fn close_file(&mut self, fd: FileDescripter) -> Option<Arc<FileHandle>> {
let file = self.table.remove(&fd); let entry = self.table.remove(fd as usize);
if file.is_some() { if entry.is_some() {
self.notify_close_fd_event(fd); 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<FileHandle>> {
self.table self.table
.get(&fd) .get(fd as usize)
.map(|entry| &entry.file)
.ok_or(Error::with_message(Errno::EBADF, "fd not exits")) .ok_or(Error::with_message(Errno::EBADF, "fd not exits"))
} }
pub fn fds_and_files(&self) -> impl Iterator<Item = (&'_ FileDescripter, &'_ FileHandle)> { pub fn fds_and_files(&self) -> impl Iterator<Item = (FileDescripter, &'_ Arc<FileHandle>)> {
self.table.iter() self.table
.idxes_and_items()
.map(|(idx, entry)| (idx as FileDescripter, &entry.file))
} }
pub fn register_observer(&self, observer: Weak<dyn Observer<FdEvents>>) { pub fn register_observer(&self, observer: Weak<dyn Observer<FdEvents>>) {
@ -126,3 +149,18 @@ pub enum FdEvents {
} }
impl Events for FdEvents {} impl Events for FdEvents {}
#[derive(Clone)]
struct FileTableEntry {
file: Arc<FileHandle>,
close_on_exec: Cell<bool>,
}
impl FileTableEntry {
pub fn new(file: Arc<FileHandle>, close_on_exec: bool) -> Self {
Self {
file,
close_on_exec: Cell::new(close_on_exec),
}
}
}

View File

@ -62,10 +62,10 @@ impl DirOps for FdDirOps {
} }
/// Represents the inode at `/proc/[pid]/fd/N`. /// Represents the inode at `/proc/[pid]/fd/N`.
struct FileSymOps(FileHandle); struct FileSymOps(Arc<FileHandle>);
impl FileSymOps { impl FileSymOps {
pub fn new_inode(file: FileHandle, parent: Weak<dyn Inode>) -> Arc<dyn Inode> { pub fn new_inode(file: Arc<FileHandle>, parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
ProcSymBuilder::new(Self(file)) ProcSymBuilder::new(Self(file))
.parent(parent) .parent(parent)
.build() .build()

View File

@ -12,8 +12,7 @@ pub fn sys_fcntl(fd: FileDescripter, cmd: i32, arg: u64) -> Result<SyscallReturn
// FIXME: deal with the cloexec flag // FIXME: deal with the cloexec flag
let current = current!(); let current = current!();
let mut file_table = current.file_table().lock(); let mut file_table = current.file_table().lock();
let new_fd = arg as FileDescripter; let new_fd = file_table.dup(fd, arg as FileDescripter)?;
file_table.dup(fd, Some(new_fd))?;
return Ok(SyscallReturn::Return(new_fd as _)); return Ok(SyscallReturn::Return(new_fd as _));
} }
FcntlCmd::F_SETFD => { FcntlCmd::F_SETFD => {