mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
能够在系统调用返回ERESTARTSYS时,信号处理结束后,自动重启系统调用. TODO: 实现wait等需要restart_block的系统调用的重启 Signed-off-by: longjin <longjin@DragonOS.org>
499 lines
16 KiB
Rust
499 lines
16 KiB
Rust
use core::sync::atomic::compiler_fence;
|
||
|
||
use crate::{
|
||
arch::ipc::signal::{SigCode, Signal},
|
||
filesystem::vfs::{
|
||
core::generate_inode_id, file::FileMode, syscall::ModeType, FilePrivateData, FileSystem,
|
||
FileType, IndexNode, Metadata,
|
||
},
|
||
libs::{
|
||
spinlock::{SpinLock, SpinLockGuard},
|
||
wait_queue::WaitQueue,
|
||
},
|
||
net::event_poll::{EPollEventType, EPollItem, EventPoll},
|
||
process::{ProcessFlags, ProcessManager, ProcessState},
|
||
sched::SchedMode,
|
||
time::PosixTimeSpec,
|
||
};
|
||
|
||
use alloc::{
|
||
collections::LinkedList,
|
||
sync::{Arc, Weak},
|
||
vec::Vec,
|
||
};
|
||
use system_error::SystemError;
|
||
|
||
use super::signal_types::{SigInfo, SigType};
|
||
|
||
/// 我们设定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 };
|
||
}
|
||
|
||
pub fn set_mode(&mut self, mode: FileMode) {
|
||
self.mode = mode;
|
||
}
|
||
}
|
||
|
||
/// @brief 管道文件i节点(锁)
|
||
#[derive(Debug)]
|
||
pub struct LockedPipeInode {
|
||
inner: SpinLock<InnerPipeInode>,
|
||
read_wait_queue: WaitQueue,
|
||
write_wait_queue: WaitQueue,
|
||
}
|
||
|
||
/// @brief 管道文件i节点(无锁)
|
||
#[derive(Debug)]
|
||
pub struct InnerPipeInode {
|
||
self_ref: Weak<LockedPipeInode>,
|
||
/// 管道内可读的数据数
|
||
valid_cnt: i32,
|
||
read_pos: i32,
|
||
write_pos: i32,
|
||
data: [u8; PIPE_BUFF_SIZE],
|
||
/// INode 元数据
|
||
metadata: Metadata,
|
||
reader: u32,
|
||
writer: u32,
|
||
had_reader: bool,
|
||
epitems: SpinLock<LinkedList<Arc<EPollItem>>>,
|
||
}
|
||
|
||
impl InnerPipeInode {
|
||
pub fn poll(&self, private_data: &FilePrivateData) -> Result<usize, SystemError> {
|
||
let mut events = EPollEventType::empty();
|
||
|
||
let mode = if let FilePrivateData::Pipefs(PipeFsPrivateData { mode }) = private_data {
|
||
mode
|
||
} else {
|
||
return Err(SystemError::EBADFD);
|
||
};
|
||
|
||
if mode.contains(FileMode::O_RDONLY) {
|
||
if self.valid_cnt != 0 {
|
||
// 有数据可读
|
||
events.insert(EPollEventType::EPOLLIN & EPollEventType::EPOLLRDNORM);
|
||
}
|
||
|
||
// 没有写者
|
||
if self.writer == 0 {
|
||
events.insert(EPollEventType::EPOLLHUP)
|
||
}
|
||
}
|
||
|
||
if mode.contains(FileMode::O_WRONLY) {
|
||
// 管道内数据未满
|
||
if self.valid_cnt as usize != PIPE_BUFF_SIZE {
|
||
events.insert(EPollEventType::EPOLLIN & EPollEventType::EPOLLWRNORM);
|
||
}
|
||
|
||
// 没有读者
|
||
if self.reader == 0 {
|
||
events.insert(EPollEventType::EPOLLERR);
|
||
}
|
||
}
|
||
|
||
Ok(events.bits() as usize)
|
||
}
|
||
|
||
pub fn add_epoll(&mut self, epitem: Arc<EPollItem>) -> Result<(), SystemError> {
|
||
self.epitems.lock().push_back(epitem);
|
||
Ok(())
|
||
}
|
||
|
||
fn buf_full(&self) -> bool {
|
||
return self.valid_cnt as usize == PIPE_BUFF_SIZE;
|
||
}
|
||
|
||
pub fn remove_epoll(&self, epoll: &Weak<SpinLock<EventPoll>>) -> Result<(), SystemError> {
|
||
let is_remove = !self
|
||
.epitems
|
||
.lock_irqsave()
|
||
.extract_if(|x| x.epoll().ptr_eq(epoll))
|
||
.collect::<Vec<_>>()
|
||
.is_empty();
|
||
|
||
if is_remove {
|
||
return Ok(());
|
||
}
|
||
|
||
Err(SystemError::ENOENT)
|
||
}
|
||
}
|
||
|
||
impl LockedPipeInode {
|
||
pub fn new() -> Arc<Self> {
|
||
let inner = InnerPipeInode {
|
||
self_ref: Weak::default(),
|
||
valid_cnt: 0,
|
||
read_pos: 0,
|
||
write_pos: 0,
|
||
had_reader: false,
|
||
data: [0; PIPE_BUFF_SIZE],
|
||
|
||
metadata: Metadata {
|
||
dev_id: 0,
|
||
inode_id: generate_inode_id(),
|
||
size: PIPE_BUFF_SIZE as i64,
|
||
blk_size: 0,
|
||
blocks: 0,
|
||
atime: PosixTimeSpec::default(),
|
||
mtime: PosixTimeSpec::default(),
|
||
ctime: PosixTimeSpec::default(),
|
||
file_type: FileType::Pipe,
|
||
mode: ModeType::from_bits_truncate(0o666),
|
||
nlinks: 1,
|
||
uid: 0,
|
||
gid: 0,
|
||
raw_dev: Default::default(),
|
||
},
|
||
reader: 0,
|
||
writer: 0,
|
||
epitems: SpinLock::new(LinkedList::new()),
|
||
};
|
||
let result = Arc::new(Self {
|
||
inner: SpinLock::new(inner),
|
||
read_wait_queue: WaitQueue::default(),
|
||
write_wait_queue: WaitQueue::default(),
|
||
});
|
||
let mut guard = result.inner.lock();
|
||
guard.self_ref = Arc::downgrade(&result);
|
||
// 释放锁
|
||
drop(guard); //这一步其实不需要,只要离开作用域,guard生命周期结束,自会解锁
|
||
return result;
|
||
}
|
||
|
||
pub fn inner(&self) -> &SpinLock<InnerPipeInode> {
|
||
&self.inner
|
||
}
|
||
|
||
fn readable(&self) -> bool {
|
||
let inode = self.inner.lock();
|
||
return inode.valid_cnt > 0 || inode.writer == 0;
|
||
}
|
||
|
||
fn writeable(&self) -> bool {
|
||
let inode = self.inner.lock();
|
||
return !inode.buf_full() || inode.reader == 0;
|
||
}
|
||
}
|
||
|
||
impl IndexNode for LockedPipeInode {
|
||
fn read_at(
|
||
&self,
|
||
_offset: usize,
|
||
len: usize,
|
||
buf: &mut [u8],
|
||
data_guard: SpinLockGuard<FilePrivateData>,
|
||
) -> Result<usize, SystemError> {
|
||
let data = data_guard.clone();
|
||
drop(data_guard);
|
||
// 获取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);
|
||
}
|
||
// log::debug!("pipe mode: {:?}", mode);
|
||
// 加锁
|
||
let mut inode = self.inner.lock();
|
||
|
||
// 如果管道里面没有数据,则唤醒写端,
|
||
while inode.valid_cnt == 0 {
|
||
// 如果当前管道写者数为0,则返回EOF
|
||
if inode.writer == 0 {
|
||
return Ok(0);
|
||
}
|
||
|
||
self.write_wait_queue
|
||
.wakeup(Some(ProcessState::Blocked(true)));
|
||
|
||
// 如果为非阻塞管道,直接返回错误
|
||
if mode.contains(FileMode::O_NONBLOCK) {
|
||
drop(inode);
|
||
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
|
||
}
|
||
|
||
// 否则在读等待队列中睡眠,并释放锁
|
||
drop(inode);
|
||
let r = wq_wait_event_interruptible!(self.read_wait_queue, self.readable(), {});
|
||
if r.is_err() {
|
||
ProcessManager::current_pcb()
|
||
.flags()
|
||
.insert(ProcessFlags::HAS_PENDING_SIGNAL);
|
||
return Err(SystemError::ERESTARTSYS);
|
||
}
|
||
|
||
inode = self.inner.lock();
|
||
}
|
||
|
||
let mut num = inode.valid_cnt as usize;
|
||
//决定要输出的字节
|
||
let start = inode.read_pos as usize;
|
||
//如果读端希望读取的字节数大于有效字节数,则输出有效字节
|
||
let mut end = (inode.valid_cnt as usize + inode.read_pos as usize) % PIPE_BUFF_SIZE;
|
||
//如果读端希望读取的字节数少于有效字节数,则输出希望读取的字节
|
||
if len < inode.valid_cnt as usize {
|
||
end = (len + inode.read_pos as usize) % PIPE_BUFF_SIZE;
|
||
num = len;
|
||
}
|
||
|
||
// 从管道拷贝数据到用户的缓冲区
|
||
|
||
if end < start {
|
||
buf[0..(PIPE_BUFF_SIZE - start)].copy_from_slice(&inode.data[start..PIPE_BUFF_SIZE]);
|
||
buf[(PIPE_BUFF_SIZE - start)..num].copy_from_slice(&inode.data[0..end]);
|
||
} else {
|
||
buf[0..num].copy_from_slice(&inode.data[start..end]);
|
||
}
|
||
|
||
//更新读位置以及valid_cnt
|
||
inode.read_pos = (inode.read_pos + num as i32) % PIPE_BUFF_SIZE as i32;
|
||
inode.valid_cnt -= num as i32;
|
||
|
||
// 读完以后如果未读完,则唤醒下一个读者
|
||
if inode.valid_cnt > 0 {
|
||
self.read_wait_queue
|
||
.wakeup(Some(ProcessState::Blocked(true)));
|
||
}
|
||
|
||
//读完后解锁并唤醒等待在写等待队列中的进程
|
||
self.write_wait_queue
|
||
.wakeup(Some(ProcessState::Blocked(true)));
|
||
|
||
let pollflag = EPollEventType::from_bits_truncate(inode.poll(&data)? as u32);
|
||
// 唤醒epoll中等待的进程
|
||
EventPoll::wakeup_epoll(&inode.epitems, Some(pollflag))?;
|
||
|
||
//返回读取的字节数
|
||
return Ok(num);
|
||
}
|
||
|
||
fn open(
|
||
&self,
|
||
mut data: SpinLockGuard<FilePrivateData>,
|
||
mode: &crate::filesystem::vfs::file::FileMode,
|
||
) -> Result<(), SystemError> {
|
||
let accmode = mode.accmode();
|
||
let mut guard = self.inner.lock();
|
||
// 不能以读写方式打开管道
|
||
if accmode == FileMode::O_RDWR.bits() {
|
||
return Err(SystemError::EACCES);
|
||
} else if accmode == FileMode::O_RDONLY.bits() {
|
||
guard.reader += 1;
|
||
guard.had_reader = true;
|
||
// println!(
|
||
// "FIFO: pipe try open in read mode with reader pid:{:?}",
|
||
// ProcessManager::current_pid()
|
||
// );
|
||
} else if accmode == FileMode::O_WRONLY.bits() {
|
||
// println!(
|
||
// "FIFO: pipe try open in write mode with {} reader, writer pid:{:?}",
|
||
// guard.reader,
|
||
// ProcessManager::current_pid()
|
||
// );
|
||
if guard.reader == 0 && mode.contains(FileMode::O_NONBLOCK) {
|
||
return Err(SystemError::ENXIO);
|
||
}
|
||
guard.writer += 1;
|
||
}
|
||
|
||
// 设置mode
|
||
*data = FilePrivateData::Pipefs(PipeFsPrivateData { mode: *mode });
|
||
|
||
return Ok(());
|
||
}
|
||
|
||
fn metadata(&self) -> Result<crate::filesystem::vfs::Metadata, SystemError> {
|
||
let inode = self.inner.lock();
|
||
let mut metadata = inode.metadata.clone();
|
||
metadata.size = inode.data.len() as i64;
|
||
|
||
return Ok(metadata);
|
||
}
|
||
|
||
fn close(&self, data: SpinLockGuard<FilePrivateData>) -> Result<(), SystemError> {
|
||
let mode: FileMode;
|
||
if let FilePrivateData::Pipefs(pipe_data) = &*data {
|
||
mode = pipe_data.mode;
|
||
} else {
|
||
return Err(SystemError::EBADF);
|
||
}
|
||
let accmode = mode.accmode();
|
||
let mut guard = self.inner.lock();
|
||
|
||
// 写端关闭
|
||
if accmode == FileMode::O_WRONLY.bits() {
|
||
assert!(guard.writer > 0);
|
||
guard.writer -= 1;
|
||
// 如果已经没有写端了,则唤醒读端
|
||
if guard.writer == 0 {
|
||
self.read_wait_queue
|
||
.wakeup_all(Some(ProcessState::Blocked(true)));
|
||
}
|
||
}
|
||
|
||
// 读端关闭
|
||
if accmode == FileMode::O_RDONLY.bits() {
|
||
assert!(guard.reader > 0);
|
||
guard.reader -= 1;
|
||
// 如果已经没有写端了,则唤醒读端
|
||
if guard.reader == 0 {
|
||
self.write_wait_queue
|
||
.wakeup_all(Some(ProcessState::Blocked(true)));
|
||
}
|
||
}
|
||
|
||
return Ok(());
|
||
}
|
||
|
||
fn write_at(
|
||
&self,
|
||
_offset: usize,
|
||
len: usize,
|
||
buf: &[u8],
|
||
data: SpinLockGuard<FilePrivateData>,
|
||
) -> Result<usize, 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);
|
||
}
|
||
// 加锁
|
||
|
||
let mut inode = self.inner.lock();
|
||
|
||
if inode.reader == 0 {
|
||
if !inode.had_reader {
|
||
// 如果从未有读端,直接返回 ENXIO,无论是否阻塞模式
|
||
return Err(SystemError::ENXIO);
|
||
} else {
|
||
// 如果曾经有读端,现在已关闭
|
||
match mode.contains(FileMode::O_NONBLOCK) {
|
||
true => {
|
||
// 非阻塞模式,直接返回 EPIPE
|
||
return Err(SystemError::EPIPE);
|
||
}
|
||
false => {
|
||
let sig = Signal::SIGPIPE;
|
||
let mut info = SigInfo::new(
|
||
sig,
|
||
0,
|
||
SigCode::Kernel,
|
||
SigType::Kill(ProcessManager::current_pid()),
|
||
);
|
||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||
|
||
let _retval = sig
|
||
.send_signal_info(Some(&mut info), ProcessManager::current_pid())
|
||
.map(|x| x as usize);
|
||
|
||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||
return Err(SystemError::EPIPE);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果管道空间不够
|
||
|
||
while len + inode.valid_cnt as usize > PIPE_BUFF_SIZE {
|
||
// 唤醒读端
|
||
self.read_wait_queue
|
||
.wakeup(Some(ProcessState::Blocked(true)));
|
||
|
||
// 如果为非阻塞管道,直接返回错误
|
||
if mode.contains(FileMode::O_NONBLOCK) {
|
||
drop(inode);
|
||
return Err(SystemError::ENOMEM);
|
||
}
|
||
|
||
// 解锁并睡眠
|
||
drop(inode);
|
||
let r = wq_wait_event_interruptible!(self.write_wait_queue, self.writeable(), {});
|
||
if r.is_err() {
|
||
return Err(SystemError::ERESTARTSYS);
|
||
}
|
||
inode = self.inner.lock();
|
||
}
|
||
|
||
// 决定要输入的字节
|
||
let start = inode.write_pos as usize;
|
||
let end = (inode.write_pos as usize + len) % PIPE_BUFF_SIZE;
|
||
// 从用户的缓冲区拷贝数据到管道
|
||
|
||
if end < start {
|
||
inode.data[start..PIPE_BUFF_SIZE].copy_from_slice(&buf[0..(PIPE_BUFF_SIZE - start)]);
|
||
inode.data[0..end].copy_from_slice(&buf[(PIPE_BUFF_SIZE - start)..len]);
|
||
} else {
|
||
inode.data[start..end].copy_from_slice(&buf[0..len]);
|
||
}
|
||
// 更新写位置以及valid_cnt
|
||
inode.write_pos = (inode.write_pos + len as i32) % PIPE_BUFF_SIZE as i32;
|
||
inode.valid_cnt += len as i32;
|
||
|
||
// 写完后还有位置,则唤醒下一个写者
|
||
if (inode.valid_cnt as usize) < PIPE_BUFF_SIZE {
|
||
self.write_wait_queue
|
||
.wakeup(Some(ProcessState::Blocked(true)));
|
||
}
|
||
|
||
// 读完后解锁并唤醒等待在读等待队列中的进程
|
||
self.read_wait_queue
|
||
.wakeup(Some(ProcessState::Blocked(true)));
|
||
|
||
let pollflag = EPollEventType::from_bits_truncate(inode.poll(&data)? as u32);
|
||
// 唤醒epoll中等待的进程
|
||
EventPoll::wakeup_epoll(&inode.epitems, Some(pollflag))?;
|
||
|
||
// 返回写入的字节数
|
||
return Ok(len);
|
||
}
|
||
|
||
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||
self
|
||
}
|
||
|
||
fn get_entry_name_and_metadata(
|
||
&self,
|
||
ino: crate::filesystem::vfs::InodeId,
|
||
) -> Result<(alloc::string::String, crate::filesystem::vfs::Metadata), SystemError> {
|
||
// 如果有条件,请在文件系统中使用高效的方式实现本接口,而不是依赖这个低效率的默认实现。
|
||
let name = self.get_entry_name(ino)?;
|
||
let entry = self.find(&name)?;
|
||
return Ok((name, entry.metadata()?));
|
||
}
|
||
|
||
fn fs(&self) -> Arc<(dyn FileSystem)> {
|
||
todo!()
|
||
}
|
||
|
||
fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, SystemError> {
|
||
return Err(SystemError::ENOSYS);
|
||
}
|
||
|
||
fn poll(&self, private_data: &FilePrivateData) -> Result<usize, SystemError> {
|
||
return self.inner.lock().poll(private_data);
|
||
}
|
||
}
|