Jelajahi Sumber

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>
linfeng 13 jam lalu
induk
melakukan
7486ad438c

+ 4 - 7
kernel/src/driver/tty/tty_port.rs

@@ -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
     }
 }

+ 2 - 2
kernel/src/filesystem/eventfd.rs

@@ -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);
     }
 

+ 5 - 7
kernel/src/filesystem/poll.rs

@@ -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))
 }
 

+ 2 - 2
kernel/src/ipc/pipe.rs

@@ -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);

+ 28 - 43
kernel/src/net/event_poll/mod.rs

@@ -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)
-                    } 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(())

+ 1 - 1
kernel/src/net/net_core.rs

@@ -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!(

+ 1 - 1
kernel/src/perf/mod.rs

@@ -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)
     }
 }
 

+ 19 - 12
user/apps/test_epoll/main.c

@@ -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);