Skip to content

fix bugs in poll and epoll #1135

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
11 changes: 4 additions & 7 deletions kernel/src/driver/tty/tty_port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use system_error::SystemError;

use crate::{
libs::spinlock::{SpinLock, SpinLockGuard},
net::event_poll::EventPoll,
net::event_poll::{EPollEventType, EventPoll},
};

use super::tty_core::TtyCore;
Expand Down Expand Up @@ -80,17 +80,14 @@ pub trait TtyPort: Sync + Send + Debug {
/// 作为客户端的tty ports接收数据
fn receive_buf(&self, buf: &[u8], _flags: &[u8], count: usize) -> Result<usize, SystemError> {
let tty = self.port_data().internal_tty().unwrap();

let ld = tty.ldisc();

let ret = ld.receive_buf2(tty.clone(), buf, None, count);

if let Err(SystemError::ENOSYS) = ret {
return ld.receive_buf(tty, buf, None, count);
}

EventPoll::wakeup_epoll(tty.core().eptiems(), None)?;

let event: usize = ld.poll(tty.clone())?;
let pollflag = EPollEventType::from_bits_truncate(event as u32);
EventPoll::wakeup_epoll(tty.core().eptiems(), pollflag)?;
ret
}
}
Expand Down
4 changes: 2 additions & 2 deletions kernel/src/filesystem/eventfd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ impl IndexNode for EventFdInode {
drop(eventfd);

// 唤醒epoll中等待的进程
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?;
EventPoll::wakeup_epoll(&self.epitems, pollflag)?;

return Ok(8);
}
Expand Down Expand Up @@ -240,7 +240,7 @@ impl IndexNode for EventFdInode {
drop(eventfd);

// 唤醒epoll中等待的进程
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?;
EventPoll::wakeup_epoll(&self.epitems, pollflag)?;
return Ok(8);
}

Expand Down
12 changes: 5 additions & 7 deletions kernel/src/filesystem/poll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ impl<'a> PollAdapter<'a> {
fn poll_all_fds(&mut self, timeout: Option<Instant>) -> Result<usize, SystemError> {
let mut epoll_events = vec![EPollEvent::default(); self.poll_fds.len()];
let len = epoll_events.len() as i32;
let remain_timeout = timeout
.and_then(|t| t.duration_since(Instant::now()))
.map(|t| t.into());
let remain_timeout = timeout.map(|t| {
t.duration_since(Instant::now())
.unwrap_or(Duration::ZERO)
.into()
});
let events = EventPoll::epoll_wait_with_file(
self.ep_file.clone(),
&mut epoll_events,
Expand Down Expand Up @@ -176,10 +178,6 @@ fn do_sys_poll(poll_fds: &mut [PollFd], timeout: Option<Instant>) -> Result<usiz

/// 计算超时的时刻
fn poll_select_set_timeout(timeout_ms: u64) -> Option<Instant> {
if timeout_ms == 0 {
return None;
}

Some(Instant::now() + Duration::from_millis(timeout_ms))
}

Expand Down
8 changes: 5 additions & 3 deletions kernel/src/init/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,12 @@ fn do_start_kernel() {
crate::bpf::init_bpf_system();
crate::debug::jump_label::static_keys_init();

// #[cfg(all(target_arch = "x86_64", feature = "kvm"))]
// crate::virt::kvm::kvm_init();
#[cfg(all(target_arch = "x86_64", feature = "kvm"))]
crate::arch::vm::vmx::vmx_init().unwrap();
{
if let Err(e) = crate::arch::vm::vmx::vmx_init() {
log::error!("KVM init failed: {:?}", e);
}
}
}

/// 在内存管理初始化之前,执行的初始化
Expand Down
4 changes: 2 additions & 2 deletions kernel/src/ipc/pipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ impl IndexNode for LockedPipeInode {
let pollflag = EPollEventType::from_bits_truncate(inner_guard.poll(&data)? as u32);
drop(inner_guard);
// 唤醒epoll中等待的进程
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?;
EventPoll::wakeup_epoll(&self.epitems, pollflag)?;

//返回读取的字节数
return Ok(num);
Expand Down Expand Up @@ -476,7 +476,7 @@ impl IndexNode for LockedPipeInode {

drop(inner_guard);
// 唤醒epoll中等待的进程
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?;
EventPoll::wakeup_epoll(&self.epitems, pollflag)?;

// 返回写入的字节数
return Ok(len);
Expand Down
71 changes: 28 additions & 43 deletions kernel/src/net/event_poll/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ impl EventPoll {
}
} else if timespec.is_none() {
// 非阻塞情况
timeout = true;
timeout = false;
}
// 判断epoll上有没有就绪事件
let mut available = epoll_guard.ep_events_available();
Expand Down Expand Up @@ -775,52 +775,37 @@ impl EventPoll {
/// ### epoll的回调,支持epoll的文件有事件到来时直接调用该方法即可
pub fn wakeup_epoll(
epitems: &SpinLock<LinkedList<Arc<EPollItem>>>,
pollflags: Option<EPollEventType>,
pollflags: EPollEventType,
) -> Result<(), SystemError> {
let mut epitems_guard = epitems.try_lock_irqsave()?;
// 一次只取一个,因为一次也只有一个进程能拿到对应文件的🔓
if let Some(epitem) = epitems_guard.pop_front() {
let pollflags = match pollflags {
Some(flags) => flags,
None => {
if let Some(file) = epitem.file.upgrade() {
// warning: deadlock will happen if poll() is called when pollflags is None
EPollEventType::from_bits_truncate(file.poll()? as u32)
} else {
EPollEventType::empty()
}
}
};
let epitems_guard = epitems.try_lock_irqsave()?;
for epitem in epitems_guard.iter() {
// The upgrade is safe because EventPoll always exists when the epitem is in the list
let epoll = epitem.epoll().upgrade().unwrap();
let mut epoll_guard = epoll.try_lock()?;
let binding = epitem.clone();
let event_guard = binding.event().read();
let ep_events = EPollEventType::from_bits_truncate(event_guard.events());
// 检查事件合理性以及是否有感兴趣的事件
if !(ep_events
.difference(EPollEventType::EP_PRIVATE_BITS)
.is_empty()
|| pollflags.difference(ep_events).is_empty())
{
// TODO: 未处理pm相关

if let Some(epoll) = epitem.epoll().upgrade() {
let mut epoll_guard = epoll.try_lock()?;
let binding = epitem.clone();
let event_guard = binding.event().read();
let ep_events = EPollEventType::from_bits_truncate(event_guard.events());
// 检查事件合理性以及是否有感兴趣的事件
if !(ep_events
.difference(EPollEventType::EP_PRIVATE_BITS)
.is_empty()
|| pollflags.difference(ep_events).is_empty())
{
// TODO: 未处理pm相关

// 首先将就绪的epitem加入等待队列
epoll_guard.ep_add_ready(epitem.clone());

if epoll_guard.ep_has_waiter() {
if ep_events.contains(EPollEventType::EPOLLEXCLUSIVE)
&& !pollflags.contains(EPollEventType::POLLFREE)
{
// 避免惊群
epoll_guard.ep_wake_one();
} else {
epoll_guard.ep_wake_all();
}
// 首先将就绪的epitem加入等待队列
epoll_guard.ep_add_ready(epitem.clone());

if epoll_guard.ep_has_waiter() {
if ep_events.contains(EPollEventType::EPOLLEXCLUSIVE)
&& !pollflags.contains(EPollEventType::POLLFREE)
{
// 避免惊群
epoll_guard.ep_wake_one();
} else {
epoll_guard.ep_wake_all();
}
}

epitems_guard.push_back(epitem);
}
}
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/net/net_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ fn send_event(sockets: &smoltcp::iface::SocketSet) -> Result<(), SystemError> {
}
EventPoll::wakeup_epoll(
&posix_item.epitems,
Some(EPollEventType::from_bits_truncate(events as u32)),
EPollEventType::from_bits_truncate(events as u32),
)?;
drop(handle_guard);
// crate::debug!(
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/perf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl PerfEventInode {
fn epoll_callback(&self) -> Result<()> {
let pollflag = EPollEventType::from_bits_truncate(self.do_poll()? as u32);
// 唤醒epoll中等待的进程
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))
EventPoll::wakeup_epoll(&self.epitems, pollflag)
}
}

Expand Down
31 changes: 19 additions & 12 deletions user/apps/test_epoll/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,19 +98,26 @@ int main() {
printf("主线程:epoll_wait 返回,事件数量 = %d\n", nfds);
}

if (nfds != 2) {
printf("主线程:事件数量不匹配,预期 2,实际 %d\n", nfds);
exit(EXIT_FAILURE);
}

// 由于dup复制了 eventfd 描述符,所以 只需要处理一个就行
nfds -= 1;
// 处理就绪事件
// for (int i = 0; i < nfds; i++) {
// if (events[i].data.fd == efd || events[i].data.fd == efd2) {
// uint64_t count;
// int fd = events[i].data.fd;
// printf("主线程:事件发生在 fd = %d\n", fd);
// if (read(fd, &count, sizeof(count)) != sizeof(count)) {
// perror("从 eventfd 读取失败");
// exit(EXIT_FAILURE);
// }
// printf("主线程:接收到 eventfd 事件,计数值 = %lu\n", count);
// }
// }
for (int i = 0; i < nfds; i++) {
if (events[i].data.fd == efd || events[i].data.fd == efd2) {
uint64_t count;
int fd = events[i].data.fd;
printf("主线程:事件发生在 fd = %d\n", fd);
if (read(fd, &count, sizeof(count)) != sizeof(count)) {
perror("从 eventfd 读取失败");
exit(EXIT_FAILURE);
}
printf("主线程:接收到 eventfd 事件,计数值 = %lu\n", count);
}
}

// 等待工作线程结束
pthread_join(tid, NULL);
Expand Down