Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加epoll机制 #455

Merged
merged 7 commits into from
Dec 25, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 23 additions & 25 deletions kernel/src/net/event_poll/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use core::{
fmt::Debug,
ops::Add,
sync::atomic::{AtomicBool, Ordering},
};

Expand All @@ -23,9 +22,8 @@ use crate::{
spinlock::{SpinLock, SpinLockGuard},
wait_queue::WaitQueue,
},
mm::VirtAddr,
process::ProcessManager,
syscall::{user_access::UserBufferWriter, SystemError},
syscall::SystemError,
time::{
timer::{next_n_us_timer_jiffies, Timer, WakeUpHelper},
TimeSpec,
Expand Down Expand Up @@ -384,7 +382,7 @@ impl EventPoll {
/// ## epoll_wait的具体实现
pub fn do_epoll_wait(
epfd: i32,
epoll_event: VirtAddr,
epoll_event: &mut [EPollEvent],
max_events: i32,
timespec: Option<TimeSpec>,
) -> Result<usize, SystemError> {
Expand Down Expand Up @@ -510,7 +508,7 @@ impl EventPoll {
/// - max_events: 处理的最大事件数量
fn ep_send_events(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

所有大的函数都需要把入参、返回值、功能写注释。

epoll: LockedEventPoll,
user_event: VirtAddr,
user_event: &mut [EPollEvent],
max_events: i32,
) -> Result<usize, SystemError> {
let mut ep_guard = epoll.0.lock_irqsave();
Expand All @@ -519,9 +517,9 @@ impl EventPoll {
// 在水平触发模式下,需要将epitem再次加入队列,在下次循环再次判断是否还有事件
// (所以边缘触发的效率会高于水平触发,但是水平触发某些情况下能够使得更迅速地向用户反馈)
let mut push_back = Vec::new();
let max_offset = user_event.data() + 12 * max_events as usize;
while let Some(epitem) = ep_guard.ready_list.pop_front() {
if res >= max_events as usize {
push_back.push(epitem);
break;
}
let ep_events = EPollEventType::from_bits_truncate(epitem.event.read().events);
Expand All @@ -538,25 +536,26 @@ impl EventPoll {
data: epitem.event.read().data,
};

// C标准的epoll_event大小为12字节,在内核我们不使用#[repr(packed)]来强制与C兼容,可以提高效率
let user_addr = user_event.add(res * 12);
if user_addr.data() >= max_offset {
// 当前指向的地址已为空,则把epitem放回队列
ep_guard.ready_list.push_back(epitem.clone());
if res == 0 {
// 一个都未写入成功,表明用户传进的地址就是有问题的
return Err(SystemError::EFAULT);
}
}
// 这里是需要判断下一个写入的位置是否为空指针

// TODO:这里有可能会出现事件丢失的情况
// 如果用户传入的数组长度小于传入的max_event,到这里时如果已经到数组最大长度,但是未到max_event
// 会出现的问题是我们会把这个数据写入到后面的内存中,用户无法在传入的数组中拿到事件,而且写脏数据到了后面一片内存,导致事件丢失
// 出现这个问题的几率比较小,首先是因为用户的使用不规范,后因为前面地址校验是按照max_event来校验的,只会在两块内存连着分配时出现,但是也是需要考虑的
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里我还没有想好如何解决,但是问题出现的几率很小而且主要是因为用户态的使用不规范才会出现这样的问题。如果有合适解决方法cue我一下

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个我感觉只要不影响内核的空间安全就行。


// 以下的写法判断并无意义,只是记一下错误处理
// offset += core::mem::size_of::<EPollEvent>();
// if offset >= max_offset {
// // 当前指向的地址已为空,则把epitem放回队列
// ep_guard.ready_list.push_back(epitem.clone());
// if res == 0 {
// // 一个都未写入成功,表明用户传进的地址就是有问题的
// return Err(SystemError::EFAULT);
// }
// }

// 拷贝到用户空间
// 先拷贝events字段
UserBufferWriter::new(user_addr.as_ptr::<u32>(), core::mem::size_of::<u32>(), true)?
.copy_one_to_user::<u32>(&event.events, 0)?;
// 增加偏移量
let user_addr = user_addr.add(core::mem::size_of::<u32>());
UserBufferWriter::new(user_addr.as_ptr::<u64>(), core::mem::size_of::<u64>(), true)?
.copy_one_to_user::<u64>(&event.data, 0)?;
user_event[res] = event;
// 记数加一
res += 1;

Expand Down Expand Up @@ -615,8 +614,6 @@ impl EventPoll {
epoll_guard.ep_wake_one();
}

drop(epoll_guard);

// TODO: 嵌套epoll?

// 这个标志是用与电源管理相关,暂时不支持
Expand Down Expand Up @@ -711,6 +708,7 @@ impl EventPoll {

/// 与C兼容的Epoll事件结构体
#[derive(Copy, Clone, Default)]
#[repr(packed)]
pub struct EPollEvent {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里需要加详细的注释,描述字段含义以及相应的行为

/// 表示触发的事件
events: u32,
Expand Down
40 changes: 21 additions & 19 deletions kernel/src/net/event_poll/syscall.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use core::ops::Add;

use crate::{
arch::ipc::signal::SigSet,
filesystem::vfs::file::FileMode,
ipc::signal::set_current_sig_blocked,
mm::{verify_area, VirtAddr},
syscall::{user_access::UserBufferReader, Syscall, SystemError},
mm::VirtAddr,
syscall::{
user_access::{UserBufferReader, UserBufferWriter},
Syscall, SystemError,
},
time::TimeSpec,
};

Expand Down Expand Up @@ -49,10 +50,15 @@ impl Syscall {
timespec = Some(TimeSpec::new(sec, nsec))
}

// 因为C中的epoll_event大小为12字节,而在rust中为16字节
verify_area(events, 12 * max_events as usize)?;
// 从用户传入的地址中拿到epoll_events
let mut epds_writer = UserBufferWriter::new(
events.as_ptr::<EPollEvent>(),
max_events as usize * core::mem::size_of::<EPollEvent>(),
true,
)?;

return EventPoll::do_epoll_wait(epfd, events, max_events, timespec);
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> {
Expand All @@ -66,18 +72,14 @@ impl Syscall {

// 还是一样的问题,C标准的epoll_event大小为12字节,而内核实现的epoll_event内存对齐后为16字节
// 这样分别拷贝其实和整体拷贝差别不大,内核使用内存对其版本甚至可能提升性能
let ev_reader =
UserBufferReader::new(event.as_ptr::<u32>(), core::mem::size_of::<u32>(), true)?;
let events = ev_reader.read_one_from_user::<u32>(0)?;
let event = event.add(core::mem::size_of::<u32>());
let data_reader =
UserBufferReader::new(event.as_ptr::<u64>(), core::mem::size_of::<u64>(), true)?;
let data = data_reader.read_one_from_user::<u64>(0)?;

epds = EPollEvent {
events: *events,
data: *data,
};
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);
Expand Down
1 change: 0 additions & 1 deletion kernel/src/net/net_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,6 @@ fn send_event(sockets: &smoltcp::iface::SocketSet) -> Result<(), SystemError> {
smoltcp::socket::Socket::Dhcpv4(_) => {}
smoltcp::socket::Socket::Dns(_) => unimplemented!("Dns socket hasn't unimplemented"),
}
drop(handle_item);
drop(handle_guard);
wakeup_epoll(handle, events as u32)?;
// crate::kdebug!(
Expand Down