修复pipe2在读端或写端关闭后还阻塞问题 (#396)

* 修复pipe2在读端或写端关闭后还阻塞问题。

* update

* update

* 修改cloexec

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>
This commit is contained in:
GnoCiYeH 2023-10-03 12:03:34 +08:00 committed by GitHub
parent fba5623183
commit 876cb89ecf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 166 additions and 15 deletions

View File

@ -111,6 +111,7 @@ impl Syscall {
// "tmp_rs_execve: done, load_result.entry_point()={:?}",
// load_result.entry_point()
// );
return Ok(());
}
}

View File

@ -12,7 +12,7 @@ use crate::arch::{PciArch, TraitPciArch};
use crate::include::bindings::bindings::{
c_irq_install, c_irq_uninstall, pt_regs, ul, EAGAIN, EINVAL,
};
use crate::kdebug;
use crate::libs::volatile::{volread, volwrite, Volatile, VolatileReadable, VolatileWritable};
/// MSIX表的一项

View File

@ -8,6 +8,7 @@ use crate::{
tty::TtyFilePrivateData,
},
filesystem::procfs::ProcfsFilePrivateData,
ipc::pipe::PipeFsPrivateData,
kerror,
libs::spinlock::SpinLock,
process::ProcessManager,
@ -19,6 +20,8 @@ use super::{Dirent, FileType, IndexNode, InodeId, Metadata};
/// 文件私有信息的枚举类型
#[derive(Debug, Clone)]
pub enum FilePrivateData {
/// 管道文件私有信息
Pipefs(PipeFsPrivateData),
/// procfs文件私有信息
Procfs(ProcfsFilePrivateData),
/// 设备文件的私有信息
@ -513,4 +516,54 @@ impl FileDescriptorVec {
assert!(Arc::strong_count(&file) == 1);
return Ok(());
}
pub fn iter(&self) -> FileDescriptorIterator {
return FileDescriptorIterator::new(self);
}
pub fn close_on_exec(&mut self) {
for i in 0..FileDescriptorVec::PROCESS_MAX_FD {
if let Some(file) = &self.fds[i] {
let to_drop = file.lock().close_on_exec();
if to_drop {
let r = self.drop_fd(i as i32);
if let Err(r) = r {
kerror!(
"Failed to close file: pid = {:?}, fd = {}, error = {:?}",
ProcessManager::current_pcb().pid(),
i,
r
);
}
}
}
}
}
}
#[derive(Debug)]
pub struct FileDescriptorIterator<'a> {
fds: &'a FileDescriptorVec,
index: usize,
}
impl<'a> FileDescriptorIterator<'a> {
pub fn new(fds: &'a FileDescriptorVec) -> Self {
return Self { fds, index: 0 };
}
}
impl<'a> Iterator for FileDescriptorIterator<'a> {
type Item = (i32, Arc<SpinLock<File>>);
fn next(&mut self) -> Option<Self::Item> {
while self.index < FileDescriptorVec::PROCESS_MAX_FD {
let fd = self.index as i32;
self.index += 1;
if let Some(file) = self.fds.get_file_by_fd(fd) {
return Some((fd, file));
}
}
return None;
}
}

View File

@ -16,6 +16,17 @@ use alloc::sync::{Arc, Weak};
/// 我们设定pipe_buff的总大小为1024字节
const PIPE_BUFF_SIZE: usize = 1024;
#[derive(Debug, Clone)]
pub struct PipeFsPrivateData {
mode: FileMode,
}
impl PipeFsPrivateData {
pub fn new(mode: FileMode) -> Self {
return PipeFsPrivateData { mode: mode };
}
}
/// @brief 管道文件i节点(锁)
#[derive(Debug)]
pub struct LockedPipeInode(SpinLock<InnerPipeInode>);
@ -32,11 +43,12 @@ pub struct InnerPipeInode {
data: [u8; PIPE_BUFF_SIZE],
/// INode 元数据
metadata: Metadata,
flags: FileMode,
reader: u32,
writer: u32,
}
impl LockedPipeInode {
pub fn new(flags: FileMode) -> Arc<Self> {
pub fn new() -> Arc<Self> {
let inner = InnerPipeInode {
self_ref: Weak::default(),
valid_cnt: 0,
@ -62,7 +74,8 @@ impl LockedPipeInode {
gid: 0,
raw_dev: 0,
},
flags,
reader: 0,
writer: 0,
};
let result = Arc::new(Self(SpinLock::new(inner)));
let mut guard = result.0.lock();
@ -79,8 +92,16 @@ impl IndexNode for LockedPipeInode {
_offset: usize,
len: usize,
buf: &mut [u8],
_data: &mut FilePrivateData,
data: &mut FilePrivateData,
) -> Result<usize, crate::syscall::SystemError> {
// 获取mode
let mode: FileMode;
if let FilePrivateData::Pipefs(pdata) = data {
mode = pdata.mode;
} else {
return Err(SystemError::EBADF);
}
if buf.len() < len {
return Err(SystemError::EINVAL);
}
@ -89,12 +110,17 @@ impl IndexNode for LockedPipeInode {
// 如果管道里面没有数据,则唤醒写端,
while inode.valid_cnt == 0 {
// 如果当前管道写者数为0则返回EOF
if inode.writer == 0 {
return Ok(0);
}
inode
.write_wait_queue
.wakeup(Some(ProcessState::Blocked(true)));
// 如果为非阻塞管道,直接返回错误
if inode.flags.contains(FileMode::O_NONBLOCK) {
if mode.contains(FileMode::O_NONBLOCK) {
drop(inode);
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
}
@ -145,9 +171,24 @@ impl IndexNode for LockedPipeInode {
fn open(
&self,
_data: &mut FilePrivateData,
_mode: &crate::filesystem::vfs::file::FileMode,
data: &mut FilePrivateData,
mode: &crate::filesystem::vfs::file::FileMode,
) -> Result<(), SystemError> {
let mut guard = self.0.lock();
// 不能以读写方式打开管道
if mode.contains(FileMode::O_RDWR) {
return Err(SystemError::EACCES);
}
if mode.contains(FileMode::O_RDONLY) {
guard.reader += 1;
}
if mode.contains(FileMode::O_WRONLY) {
guard.writer += 1;
}
// 设置mode
*data = FilePrivateData::Pipefs(PipeFsPrivateData { mode: *mode });
return Ok(());
}
@ -159,7 +200,39 @@ impl IndexNode for LockedPipeInode {
return Ok(metadata);
}
fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> {
fn close(&self, data: &mut FilePrivateData) -> Result<(), SystemError> {
let mode: FileMode;
if let FilePrivateData::Pipefs(pipe_data) = data {
mode = pipe_data.mode;
} else {
return Err(SystemError::EBADF);
}
let mut guard = self.0.lock();
// 写端关闭
if mode.contains(FileMode::O_WRONLY) {
assert!(guard.writer > 0);
guard.writer -= 1;
// 如果已经没有写端了,则唤醒读端
if guard.writer == 0 {
guard
.read_wait_queue
.wakeup_all(Some(ProcessState::Blocked(true)));
}
}
// 读端关闭
if mode.contains(FileMode::O_RDONLY) {
assert!(guard.reader > 0);
guard.reader -= 1;
// 如果已经没有写端了,则唤醒读端
if guard.reader == 0 {
guard
.write_wait_queue
.wakeup_all(Some(ProcessState::Blocked(true)));
}
}
return Ok(());
}
@ -168,8 +241,16 @@ impl IndexNode for LockedPipeInode {
_offset: usize,
len: usize,
buf: &[u8],
_data: &mut FilePrivateData,
data: &mut FilePrivateData,
) -> Result<usize, crate::syscall::SystemError> {
// 获取mode
let mode: FileMode;
if let FilePrivateData::Pipefs(pdata) = data {
mode = pdata.mode;
} else {
return Err(SystemError::EBADF);
}
if buf.len() < len || len > PIPE_BUFF_SIZE {
return Err(SystemError::EINVAL);
}
@ -177,6 +258,9 @@ impl IndexNode for LockedPipeInode {
let mut inode = self.0.lock();
// TODO: 如果已经没有读端存在了则向写端进程发送SIGPIPE信号
if inode.reader == 0 {}
// 如果管道空间不够
while len + inode.valid_cnt as usize > PIPE_BUFF_SIZE {
@ -186,7 +270,7 @@ impl IndexNode for LockedPipeInode {
.wakeup(Some(ProcessState::Blocked(true)));
// 如果为非阻塞管道,直接返回错误
if inode.flags.contains(FileMode::O_NONBLOCK) {
if mode.contains(FileMode::O_NONBLOCK) {
drop(inode);
return Err(SystemError::ENOMEM);
}

View File

@ -1,12 +1,15 @@
use core::ffi::c_int;
use crate::{
filesystem::vfs::file::{File, FileMode},
filesystem::vfs::{
file::{File, FileMode},
FilePrivateData,
},
process::{Pid, ProcessManager},
syscall::{user_access::UserBufferWriter, Syscall, SystemError},
};
use super::pipe::LockedPipeInode;
use super::pipe::{LockedPipeInode, PipeFsPrivateData};
impl Syscall {
/// # 创建带参数的匿名管道
@ -23,9 +26,13 @@ impl Syscall {
let mut user_buffer =
UserBufferWriter::new(fd, core::mem::size_of::<[c_int; 2]>(), true)?;
let fd = user_buffer.buffer::<i32>(0)?;
let pipe_ptr = LockedPipeInode::new(flags);
let pipe_ptr = LockedPipeInode::new();
let mut read_file = File::new(pipe_ptr.clone(), FileMode::O_RDONLY)?;
read_file.private_data =
FilePrivateData::Pipefs(PipeFsPrivateData::new(FileMode::O_RDONLY));
let mut write_file = File::new(pipe_ptr.clone(), FileMode::O_WRONLY)?;
write_file.private_data =
FilePrivateData::Pipefs(PipeFsPrivateData::new(FileMode::O_WRONLY));
if flags.contains(FileMode::O_CLOEXEC) {
read_file.set_close_on_exec(true);
write_file.set_close_on_exec(true);

View File

@ -61,7 +61,13 @@ impl Syscall {
.basic_mut()
.set_name(ProcessControlBlock::generate_name(&path, &argv));
return Self::do_execve(path, argv, envp, frame);
Self::do_execve(path, argv, envp, frame)?;
// 关闭设置了O_CLOEXEC的文件描述符
let fd_table = ProcessManager::current_pcb().fd_table();
fd_table.write().close_on_exec();
return Ok(());
}
pub fn wait4(