mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
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:
parent
cd3289e4b4
commit
7486ad438c
@ -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;
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
@ -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))
|
||||
}
|
||||
|
||||
|
@ -288,7 +288,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);
|
||||
@ -477,7 +477,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);
|
||||
|
@ -479,7 +479,7 @@ impl EventPoll {
|
||||
}
|
||||
} else if timespec.is_none() {
|
||||
// 非阻塞情况
|
||||
timeout = true;
|
||||
timeout = false;
|
||||
}
|
||||
// 判断epoll上有没有就绪事件
|
||||
let mut available = epoll_guard.ep_events_available();
|
||||
@ -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)
|
||||
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相关
|
||||
|
||||
// 首先将就绪的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 {
|
||||
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(())
|
||||
|
@ -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!(
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user