GnoCiYeH 406099704e
增加epoll机制 (#455)
* ## 增加epoll机制
- 增加epoll机制
- 添加事件等待队列,提升socket性能
- 优化poll,删除不能poll的文件系统中的poll方法

* 添加细节注释

* 修复文件关闭后epoll还持有对应描述符的文件弱引用的bug

* 将EPollEvent设计为POSIX标准

* 修改s到us转换的计算错误
2023-12-25 18:08:12 +08:00

108 lines
3.4 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::{
arch::ipc::signal::SigSet,
filesystem::vfs::file::FileMode,
ipc::signal::set_current_sig_blocked,
mm::VirtAddr,
syscall::{
user_access::{UserBufferReader, UserBufferWriter},
Syscall, SystemError,
},
time::TimeSpec,
};
use super::{EPollCtlOption, EPollEvent, EventPoll};
impl Syscall {
pub fn epoll_create(max_size: i32) -> Result<usize, SystemError> {
if max_size < 0 {
return Err(SystemError::EINVAL);
}
return EventPoll::do_create_epoll(FileMode::empty());
}
pub fn epoll_create1(flag: usize) -> Result<usize, SystemError> {
let flags = FileMode::from_bits_truncate(flag as u32);
let ret = EventPoll::do_create_epoll(flags);
ret
}
pub fn epoll_wait(
epfd: i32,
events: VirtAddr,
max_events: i32,
timeout: i32,
) -> Result<usize, SystemError> {
if max_events <= 0 || max_events as u32 > EventPoll::EP_MAX_EVENTS {
return Err(SystemError::EINVAL);
}
let mut timespec = None;
if timeout == 0 {
timespec = Some(TimeSpec::new(0, 0));
}
if timeout > 0 {
let sec: i64 = timeout as i64 / 1000;
let nsec: i64 = 1000000 * (timeout as i64 % 1000);
timespec = Some(TimeSpec::new(sec, nsec))
}
// 从用户传入的地址中拿到epoll_events
let mut epds_writer = UserBufferWriter::new(
events.as_ptr::<EPollEvent>(),
max_events as usize * core::mem::size_of::<EPollEvent>(),
true,
)?;
let epoll_events = epds_writer.buffer::<EPollEvent>(0)?;
return EventPoll::do_epoll_wait(epfd, epoll_events, max_events, timespec);
}
pub fn epoll_ctl(epfd: i32, op: usize, fd: i32, event: VirtAddr) -> Result<usize, SystemError> {
let op = EPollCtlOption::from_op_num(op)?;
let mut epds = EPollEvent::default();
if op != EPollCtlOption::EpollCtlDel {
// 不为EpollCtlDel时不允许传入空指针
if event.is_null() {
return Err(SystemError::EFAULT);
}
// 还是一样的问题C标准的epoll_event大小为12字节而内核实现的epoll_event内存对齐后为16字节
// 这样分别拷贝其实和整体拷贝差别不大,内核使用内存对其版本甚至可能提升性能
let epds_reader = UserBufferReader::new(
event.as_ptr::<EPollEvent>(),
core::mem::size_of::<EPollEvent>(),
true,
)?;
// 拷贝到内核
epds_reader.copy_one_from_user(&mut epds, 0)?;
}
return EventPoll::do_epoll_ctl(epfd, op, fd, &mut epds, false);
}
/// ## 在epoll_wait时屏蔽某些信号
pub fn epoll_pwait(
epfd: i32,
epoll_event: VirtAddr,
max_events: i32,
timespec: i32,
mut sigmask: &mut SigSet,
) -> Result<usize, SystemError> {
// 设置屏蔽的信号
set_current_sig_blocked(&mut sigmask);
let wait_ret = Self::epoll_wait(epfd, epoll_event, max_events, timespec);
if wait_ret.is_err() && *wait_ret.as_ref().unwrap_err() != SystemError::EINTR {
// TODO: 恢复信号?
// linkhttps://code.dragonos.org.cn/xref/linux-6.1.9/fs/eventpoll.c#2294
}
wait_ret
}
}