mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 15:26:47 +00:00
修复pipe2在读端或写端关闭后还阻塞问题 (#396)
* 修复pipe2在读端或写端关闭后还阻塞问题。 * update * update * 修改cloexec --------- Co-authored-by: longjin <longjin@RinGoTek.cn>
This commit is contained in:
parent
fba5623183
commit
876cb89ecf
@ -111,6 +111,7 @@ impl Syscall {
|
||||
// "tmp_rs_execve: done, load_result.entry_point()={:?}",
|
||||
// load_result.entry_point()
|
||||
// );
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
@ -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表的一项
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
Loading…
x
Reference in New Issue
Block a user