fix bugs in poll and epoll (#1135)

* fix bugs in poll and epoll

Signed-off-by: Godones <chenlinfeng25@outlook.com>

* fix: wakeup all epitems instead of the first

Signed-off-by: Godones <chenlinfeng25@outlook.com>

* Fix wakeup_epoll error

Signed-off-by: Godones <chenlinfeng25@outlook.com>

* Make test_epoll pass

Signed-off-by: Godones <chenlinfeng25@outlook.com>

---------

Signed-off-by: Godones <chenlinfeng25@outlook.com>
This commit is contained in:
linfeng 2025-05-09 23:08:50 +08:00 committed by GitHub
parent cd3289e4b4
commit 7486ad438c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 62 additions and 75 deletions

View File

@ -6,7 +6,7 @@ use system_error::SystemError;
use crate::{ use crate::{
libs::spinlock::{SpinLock, SpinLockGuard}, libs::spinlock::{SpinLock, SpinLockGuard},
net::event_poll::EventPoll, net::event_poll::{EPollEventType, EventPoll},
}; };
use super::tty_core::TtyCore; use super::tty_core::TtyCore;
@ -80,17 +80,14 @@ pub trait TtyPort: Sync + Send + Debug {
/// 作为客户端的tty ports接收数据 /// 作为客户端的tty ports接收数据
fn receive_buf(&self, buf: &[u8], _flags: &[u8], count: usize) -> Result<usize, SystemError> { fn receive_buf(&self, buf: &[u8], _flags: &[u8], count: usize) -> Result<usize, SystemError> {
let tty = self.port_data().internal_tty().unwrap(); let tty = self.port_data().internal_tty().unwrap();
let ld = tty.ldisc(); let ld = tty.ldisc();
let ret = ld.receive_buf2(tty.clone(), buf, None, count); let ret = ld.receive_buf2(tty.clone(), buf, None, count);
if let Err(SystemError::ENOSYS) = ret { if let Err(SystemError::ENOSYS) = ret {
return ld.receive_buf(tty, buf, None, count); return ld.receive_buf(tty, buf, None, count);
} }
let event: usize = ld.poll(tty.clone())?;
EventPoll::wakeup_epoll(tty.core().eptiems(), None)?; let pollflag = EPollEventType::from_bits_truncate(event as u32);
EventPoll::wakeup_epoll(tty.core().eptiems(), pollflag)?;
ret ret
} }
} }

View File

@ -186,7 +186,7 @@ impl IndexNode for EventFdInode {
drop(eventfd); drop(eventfd);
// 唤醒epoll中等待的进程 // 唤醒epoll中等待的进程
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?; EventPoll::wakeup_epoll(&self.epitems, pollflag)?;
return Ok(8); return Ok(8);
} }
@ -240,7 +240,7 @@ impl IndexNode for EventFdInode {
drop(eventfd); drop(eventfd);
// 唤醒epoll中等待的进程 // 唤醒epoll中等待的进程
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?; EventPoll::wakeup_epoll(&self.epitems, pollflag)?;
return Ok(8); return Ok(8);
} }

View File

@ -64,9 +64,11 @@ impl<'a> PollAdapter<'a> {
fn poll_all_fds(&mut self, timeout: Option<Instant>) -> Result<usize, SystemError> { fn poll_all_fds(&mut self, timeout: Option<Instant>) -> Result<usize, SystemError> {
let mut epoll_events = vec![EPollEvent::default(); self.poll_fds.len()]; let mut epoll_events = vec![EPollEvent::default(); self.poll_fds.len()];
let len = epoll_events.len() as i32; let len = epoll_events.len() as i32;
let remain_timeout = timeout let remain_timeout = timeout.map(|t| {
.and_then(|t| t.duration_since(Instant::now())) t.duration_since(Instant::now())
.map(|t| t.into()); .unwrap_or(Duration::ZERO)
.into()
});
let events = EventPoll::epoll_wait_with_file( let events = EventPoll::epoll_wait_with_file(
self.ep_file.clone(), self.ep_file.clone(),
&mut epoll_events, &mut epoll_events,
@ -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> { fn poll_select_set_timeout(timeout_ms: u64) -> Option<Instant> {
if timeout_ms == 0 {
return None;
}
Some(Instant::now() + Duration::from_millis(timeout_ms)) Some(Instant::now() + Duration::from_millis(timeout_ms))
} }

View File

@ -288,7 +288,7 @@ impl IndexNode for LockedPipeInode {
let pollflag = EPollEventType::from_bits_truncate(inner_guard.poll(&data)? as u32); let pollflag = EPollEventType::from_bits_truncate(inner_guard.poll(&data)? as u32);
drop(inner_guard); drop(inner_guard);
// 唤醒epoll中等待的进程 // 唤醒epoll中等待的进程
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?; EventPoll::wakeup_epoll(&self.epitems, pollflag)?;
//返回读取的字节数 //返回读取的字节数
return Ok(num); return Ok(num);
@ -477,7 +477,7 @@ impl IndexNode for LockedPipeInode {
drop(inner_guard); drop(inner_guard);
// 唤醒epoll中等待的进程 // 唤醒epoll中等待的进程
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag))?; EventPoll::wakeup_epoll(&self.epitems, pollflag)?;
// 返回写入的字节数 // 返回写入的字节数
return Ok(len); return Ok(len);

View File

@ -479,7 +479,7 @@ impl EventPoll {
} }
} else if timespec.is_none() { } else if timespec.is_none() {
// 非阻塞情况 // 非阻塞情况
timeout = true; timeout = false;
} }
// 判断epoll上有没有就绪事件 // 判断epoll上有没有就绪事件
let mut available = epoll_guard.ep_events_available(); let mut available = epoll_guard.ep_events_available();
@ -775,52 +775,37 @@ impl EventPoll {
/// ### epoll的回调支持epoll的文件有事件到来时直接调用该方法即可 /// ### epoll的回调支持epoll的文件有事件到来时直接调用该方法即可
pub fn wakeup_epoll( pub fn wakeup_epoll(
epitems: &SpinLock<LinkedList<Arc<EPollItem>>>, epitems: &SpinLock<LinkedList<Arc<EPollItem>>>,
pollflags: Option<EPollEventType>, pollflags: EPollEventType,
) -> Result<(), SystemError> { ) -> Result<(), SystemError> {
let mut epitems_guard = epitems.try_lock_irqsave()?; let epitems_guard = epitems.try_lock_irqsave()?;
// 一次只取一个,因为一次也只有一个进程能拿到对应文件的🔓 for epitem in epitems_guard.iter() {
if let Some(epitem) = epitems_guard.pop_front() { // The upgrade is safe because EventPoll always exists when the epitem is in the list
let pollflags = match pollflags { let epoll = epitem.epoll().upgrade().unwrap();
Some(flags) => flags, let mut epoll_guard = epoll.try_lock()?;
None => { let binding = epitem.clone();
if let Some(file) = epitem.file.upgrade() { let event_guard = binding.event().read();
// warning: deadlock will happen if poll() is called when pollflags is None let ep_events = EPollEventType::from_bits_truncate(event_guard.events());
EPollEventType::from_bits_truncate(file.poll()? as u32) // 检查事件合理性以及是否有感兴趣的事件
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 { } else {
EPollEventType::empty() epoll_guard.ep_wake_all();
} }
} }
};
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();
}
}
}
epitems_guard.push_back(epitem);
} }
} }
Ok(()) Ok(())

View File

@ -245,7 +245,7 @@ fn send_event(sockets: &smoltcp::iface::SocketSet) -> Result<(), SystemError> {
} }
EventPoll::wakeup_epoll( EventPoll::wakeup_epoll(
&posix_item.epitems, &posix_item.epitems,
Some(EPollEventType::from_bits_truncate(events as u32)), EPollEventType::from_bits_truncate(events as u32),
)?; )?;
drop(handle_guard); drop(handle_guard);
// crate::debug!( // crate::debug!(

View File

@ -77,7 +77,7 @@ impl PerfEventInode {
fn epoll_callback(&self) -> Result<()> { fn epoll_callback(&self) -> Result<()> {
let pollflag = EPollEventType::from_bits_truncate(self.do_poll()? as u32); let pollflag = EPollEventType::from_bits_truncate(self.do_poll()? as u32);
// 唤醒epoll中等待的进程 // 唤醒epoll中等待的进程
EventPoll::wakeup_epoll(&self.epitems, Some(pollflag)) EventPoll::wakeup_epoll(&self.epitems, pollflag)
} }
} }

View File

@ -98,19 +98,26 @@ int main() {
printf("主线程epoll_wait 返回,事件数量 = %d\n", nfds); 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++) { for (int i = 0; i < nfds; i++) {
// if (events[i].data.fd == efd || events[i].data.fd == efd2) { if (events[i].data.fd == efd || events[i].data.fd == efd2) {
// uint64_t count; uint64_t count;
// int fd = events[i].data.fd; int fd = events[i].data.fd;
// printf("主线程:事件发生在 fd = %d\n", fd); printf("主线程:事件发生在 fd = %d\n", fd);
// if (read(fd, &count, sizeof(count)) != sizeof(count)) { if (read(fd, &count, sizeof(count)) != sizeof(count)) {
// perror("从 eventfd 读取失败"); perror("从 eventfd 读取失败");
// exit(EXIT_FAILURE); exit(EXIT_FAILURE);
// } }
// printf("主线程:接收到 eventfd 事件,计数值 = %lu\n", count); printf("主线程:接收到 eventfd 事件,计数值 = %lu\n", count);
// } }
// } }
// 等待工作线程结束 // 等待工作线程结束
pthread_join(tid, NULL); pthread_join(tid, NULL);