LoGin 2b72148cae
feat(syscall): 实现syscall restart (#1075)
能够在系统调用返回ERESTARTSYS时,信号处理结束后,自动重启系统调用.

TODO: 实现wait等需要restart_block的系统调用的重启

Signed-off-by: longjin <longjin@DragonOS.org>
2024-12-13 00:56:20 +08:00

286 lines
9.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::filesystem::vfs::file::{File, FileMode};
use crate::filesystem::vfs::syscall::ModeType;
use crate::filesystem::vfs::{FilePrivateData, FileSystem, FileType, IndexNode, Metadata};
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
use crate::libs::wait_queue::WaitQueue;
use crate::net::event_poll::{EPollEventType, EPollItem, EventPoll, KernelIoctlData};
use crate::process::{ProcessFlags, ProcessManager};
use crate::sched::SchedMode;
use crate::syscall::Syscall;
use alloc::collections::LinkedList;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::sync::Weak;
use alloc::vec::Vec;
use core::any::Any;
use ida::IdAllocator;
use system_error::SystemError;
static EVENTFD_ID_ALLOCATOR: SpinLock<IdAllocator> =
SpinLock::new(IdAllocator::new(0, u32::MAX as usize).unwrap());
bitflags! {
pub struct EventFdFlags: u32{
/// Provide semaphore-like semantics for reads from the new
/// file descriptor.
const EFD_SEMAPHORE = 0o1;
/// Set the close-on-exec (FD_CLOEXEC) flag on the new file
/// descriptor
const EFD_CLOEXEC = 0o2000000;
/// Set the O_NONBLOCK file status flag on the open file
/// description (see open(2)) referred to by the new file
/// descriptor
const EFD_NONBLOCK = 0o0004000;
}
}
#[derive(Debug)]
pub struct EventFd {
count: u64,
flags: EventFdFlags,
#[allow(unused)]
id: u32,
}
impl EventFd {
pub fn new(count: u64, flags: EventFdFlags, id: u32) -> Self {
EventFd { count, flags, id }
}
}
#[derive(Debug)]
pub struct EventFdInode {
eventfd: SpinLock<EventFd>,
wait_queue: WaitQueue,
epitems: SpinLock<LinkedList<Arc<EPollItem>>>,
}
impl EventFdInode {
pub fn new(eventfd: EventFd) -> Self {
EventFdInode {
eventfd: SpinLock::new(eventfd),
wait_queue: WaitQueue::default(),
epitems: SpinLock::new(LinkedList::new()),
}
}
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)
}
fn readable(&self) -> bool {
let count = self.eventfd.lock().count;
return count > 0;
}
}
impl IndexNode for EventFdInode {
fn open(
&self,
_data: SpinLockGuard<FilePrivateData>,
_mode: &FileMode,
) -> Result<(), SystemError> {
Ok(())
}
fn close(&self, _data: SpinLockGuard<FilePrivateData>) -> Result<(), SystemError> {
Ok(())
}
/// # 从 counter 里读取一个 8 字节的int值
///
/// 1. counter !=0
/// - EFD_SEMAPHORE 如果没有被设置,从 eventfd read会得到 counter并将它归0
/// - EFD_SEMAPHORE 如果被设置,从 eventfd read会得到值 1并将 counter - 1
/// 2. counter == 0
/// - EFD_NONBLOCK 如果被设置,那么会以 EAGAIN 的错失败
/// - 否则 read 会被阻塞直到为非0。
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);
if len < 8 {
return Err(SystemError::EINVAL);
}
let mut lock_efd = self.eventfd.lock();
while lock_efd.count == 0 {
if lock_efd.flags.contains(EventFdFlags::EFD_NONBLOCK) {
drop(lock_efd);
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
}
drop(lock_efd);
let r = wq_wait_event_interruptible!(self.wait_queue, self.readable(), {});
if r.is_err() {
ProcessManager::current_pcb()
.flags()
.insert(ProcessFlags::HAS_PENDING_SIGNAL);
return Err(SystemError::ERESTARTSYS);
}
lock_efd = self.eventfd.lock();
}
let mut val = lock_efd.count;
let mut eventfd = self.eventfd.lock();
if eventfd.flags.contains(EventFdFlags::EFD_SEMAPHORE) {
eventfd.count -= 1;
val = 1;
} else {
eventfd.count = 0;
}
let val_bytes = val.to_ne_bytes();
buf[..8].copy_from_slice(&val_bytes);
let pollflag = EPollEventType::from_bits_truncate(self.poll(&data)? as u32);
// 唤醒epoll中等待的进程
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?;
return Ok(8);
}
/// # 把一个 8 字节的int值写入到 counter 里
///
/// - counter 最大值是 2^64 - 1
/// - 如果写入时会发生溢出则write会被阻塞
/// - 如果 EFD_NONBLOCK 被设置,那么以 EAGAIN 失败
/// - 以不合法的值写入时,会以 EINVAL 失败
/// - 比如 0xffffffffffffffff 不合法
/// - 比如 写入的值 size 小于8字节
fn write_at(
&self,
_offset: usize,
len: usize,
buf: &[u8],
data: SpinLockGuard<FilePrivateData>,
) -> Result<usize, SystemError> {
if len < 8 {
return Err(SystemError::EINVAL);
}
let val = u64::from_ne_bytes(buf[..8].try_into().unwrap());
if val == u64::MAX {
return Err(SystemError::EINVAL);
}
loop {
let eventfd = self.eventfd.lock();
if u64::MAX - eventfd.count > val {
break;
}
// block until a read() is performed on the
// file descriptor, or fails with the error EAGAIN if the
// file descriptor has been made nonblocking.
if eventfd.flags.contains(EventFdFlags::EFD_NONBLOCK) {
return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
}
drop(eventfd);
self.wait_queue.sleep();
}
let mut eventfd = self.eventfd.lock();
eventfd.count += val;
self.wait_queue.wakeup_all(None);
let pollflag = EPollEventType::from_bits_truncate(self.poll(&data)? as u32);
// 唤醒epoll中等待的进程
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?;
return Ok(8);
}
/// # 检查 eventfd 的状态
///
/// - 如果 counter 的值大于 0 ,那么 fd 的状态就是可读的
/// - 如果能无阻塞地写入一个至少为 1 的值,那么 fd 的状态就是可写的
fn poll(&self, _private_data: &FilePrivateData) -> Result<usize, SystemError> {
let mut events = EPollEventType::empty();
if self.eventfd.lock().count != 0 {
events |= EPollEventType::EPOLLIN | EPollEventType::EPOLLRDNORM;
}
if self.eventfd.lock().count != u64::MAX {
events |= EPollEventType::EPOLLOUT | EPollEventType::EPOLLWRNORM;
}
return Ok(events.bits() as usize);
}
fn metadata(&self) -> Result<Metadata, SystemError> {
let meta = Metadata {
mode: ModeType::from_bits_truncate(0o755),
file_type: FileType::File,
..Default::default()
};
Ok(meta)
}
fn resize(&self, _len: usize) -> Result<(), SystemError> {
Ok(())
}
fn kernel_ioctl(
&self,
arg: Arc<dyn KernelIoctlData>,
_data: &FilePrivateData,
) -> Result<usize, SystemError> {
let epitem = arg
.arc_any()
.downcast::<EPollItem>()
.map_err(|_| SystemError::EFAULT)?;
self.epitems.lock().push_back(epitem);
Ok(0)
}
fn fs(&self) -> Arc<dyn FileSystem> {
panic!("EventFd does not have a filesystem")
}
fn as_any_ref(&self) -> &dyn Any {
self
}
fn list(&self) -> Result<Vec<String>, SystemError> {
Err(SystemError::EINVAL)
}
}
impl Syscall {
/// # 创建一个 eventfd 文件描述符
///
/// ## 参数
/// - `init_val`: u32: eventfd 的初始值
/// - `flags`: u32: eventfd 的标志
///
/// ## 返回值
/// - `Ok(usize)`: 成功创建的文件描述符
/// - `Err(SystemError)`: 创建失败
///
/// See: https://man7.org/linux/man-pages/man2/eventfd2.2.html
pub fn sys_eventfd(init_val: u32, flags: u32) -> Result<usize, SystemError> {
let flags = EventFdFlags::from_bits(flags).ok_or(SystemError::EINVAL)?;
let id = EVENTFD_ID_ALLOCATOR
.lock()
.alloc()
.ok_or(SystemError::ENOMEM)? as u32;
let eventfd = EventFd::new(init_val as u64, flags, id);
let inode = Arc::new(EventFdInode::new(eventfd));
let filemode = if flags.contains(EventFdFlags::EFD_CLOEXEC) {
FileMode::O_RDWR | FileMode::O_CLOEXEC
} else {
FileMode::O_RDWR
};
let file = File::new(inode, filemode)?;
let binding = ProcessManager::current_pcb().fd_table();
let mut fd_table_guard = binding.write();
let fd = fd_table_guard.alloc_fd(file, None).map(|x| x as usize);
return fd;
}
}