mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-13 15:26:48 +00:00
Fix poll behavior
This commit is contained in:
parent
479d98c8b9
commit
6151d65cf5
@ -1,8 +1,5 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
#![allow(dead_code)]
|
|
||||||
#![allow(unused_variables)]
|
|
||||||
|
|
||||||
use core::{
|
use core::{
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
@ -149,7 +146,7 @@ impl EpollFile {
|
|||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
Error::with_message(Errno::ENOENT, "fd is not in the interest list")
|
Error::with_message(Errno::ENOENT, "fd is not in the interest list")
|
||||||
})?;
|
})?;
|
||||||
entry.update(new_ep_event, new_ep_flags);
|
entry.update(new_ep_event, new_ep_flags)?;
|
||||||
|
|
||||||
entry.clone()
|
entry.clone()
|
||||||
};
|
};
|
||||||
@ -232,20 +229,22 @@ impl EpollFile {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let (ep_event, ep_flags) = entry.event_and_flags();
|
let (has_ready_events, ep_flags) = match entry.poll() {
|
||||||
// If this entry's file is ready, save it in the output array.
|
// If this entry's file is ready, the events need to be saved in the output array.
|
||||||
// EPOLLHUP and EPOLLERR should always be reported.
|
Some((ready_events, user_data, ep_flags)) if !ready_events.is_empty() => {
|
||||||
let ready_events = entry.poll() & (ep_event.events | IoEvents::HUP | IoEvents::ERR);
|
ep_events.push(EpollEvent::new(ready_events, user_data));
|
||||||
|
count_events += 1;
|
||||||
// Records the events from the ready list
|
(true, ep_flags)
|
||||||
if !ready_events.is_empty() {
|
}
|
||||||
ep_events.push(EpollEvent::new(ready_events, ep_event.user_data));
|
// If the file is not ready, there is nothing to do.
|
||||||
count_events += 1;
|
Some((_, _, ep_flags)) => (false, ep_flags),
|
||||||
}
|
// If the file no longer exists, the entry should be removed.
|
||||||
|
None => (false, EpollFlags::ONE_SHOT),
|
||||||
|
};
|
||||||
|
|
||||||
// If there are events and the epoll entry is neither edge-triggered
|
// If there are events and the epoll entry is neither edge-triggered
|
||||||
// nor one-shot, then we should keep the entry in the ready list.
|
// nor one-shot, then we should keep the entry in the ready list.
|
||||||
if !ready_events.is_empty()
|
if has_ready_events
|
||||||
&& !ep_flags.intersects(EpollFlags::ONE_SHOT | EpollFlags::EDGE_TRIGGER)
|
&& !ep_flags.intersects(EpollFlags::ONE_SHOT | EpollFlags::EDGE_TRIGGER)
|
||||||
{
|
{
|
||||||
ready.push_back(weak_entry);
|
ready.push_back(weak_entry);
|
||||||
@ -285,11 +284,11 @@ impl Pollable for EpollFile {
|
|||||||
|
|
||||||
// Implement the common methods required by FileHandle
|
// Implement the common methods required by FileHandle
|
||||||
impl FileLike for EpollFile {
|
impl FileLike for EpollFile {
|
||||||
fn read(&self, writer: &mut VmWriter) -> Result<usize> {
|
fn read(&self, _writer: &mut VmWriter) -> Result<usize> {
|
||||||
return_errno_with_message!(Errno::EINVAL, "epoll files do not support read");
|
return_errno_with_message!(Errno::EINVAL, "epoll files do not support read");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&self, reader: &mut VmReader) -> Result<usize> {
|
fn write(&self, _reader: &mut VmReader) -> Result<usize> {
|
||||||
return_errno_with_message!(Errno::EINVAL, "epoll files do not support write");
|
return_errno_with_message!(Errno::EINVAL, "epoll files do not support write");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,38 +406,30 @@ impl EpollEntry {
|
|||||||
self.key.file.upgrade().map(KeyableArc::into)
|
self.key.file.upgrade().map(KeyableArc::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the epoll event associated with the epoll entry.
|
|
||||||
pub fn event(&self) -> EpollEvent {
|
|
||||||
let inner = self.inner.lock();
|
|
||||||
inner.event
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the epoll flags associated with the epoll entry.
|
|
||||||
pub fn flags(&self) -> EpollFlags {
|
|
||||||
let inner = self.inner.lock();
|
|
||||||
inner.flags
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the epoll event and flags that are associated with this epoll entry.
|
|
||||||
pub fn event_and_flags(&self) -> (EpollEvent, EpollFlags) {
|
|
||||||
let inner = self.inner.lock();
|
|
||||||
(inner.event, inner.flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Poll the events of the file associated with this epoll entry.
|
/// Poll the events of the file associated with this epoll entry.
|
||||||
///
|
///
|
||||||
/// If the returned events is not empty, then the file is considered ready.
|
/// If the returned events is not empty, then the file is considered ready.
|
||||||
pub fn poll(&self) -> IoEvents {
|
pub fn poll(&self) -> Option<(IoEvents, u64, EpollFlags)> {
|
||||||
match self.file() {
|
let file = self.file()?;
|
||||||
Some(file) => file.poll(IoEvents::all(), None),
|
|
||||||
None => IoEvents::empty(),
|
let (event, flags) = {
|
||||||
}
|
let inner = self.inner.lock();
|
||||||
|
(inner.event, inner.flags)
|
||||||
|
};
|
||||||
|
|
||||||
|
Some((file.poll(event.events, None), event.user_data, flags))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the epoll entry, most likely to be triggered via `EpollCtl::Mod`.
|
/// Update the epoll entry, most likely to be triggered via `EpollCtl::Mod`.
|
||||||
pub fn update(&self, event: EpollEvent, flags: EpollFlags) {
|
pub fn update(&self, event: EpollEvent, flags: EpollFlags) -> Result<()> {
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
*inner = EpollEntryInner { event, flags }
|
|
||||||
|
if let Some(file) = self.file() {
|
||||||
|
file.register_observer(self.self_weak(), event.events)?;
|
||||||
|
}
|
||||||
|
*inner = EpollEntryInner { event, flags };
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the epoll entry is in the ready list.
|
/// Returns whether the epoll entry is in the ready list.
|
||||||
|
@ -50,3 +50,44 @@ FN_TEST(epoll_add_del)
|
|||||||
TEST_SUCC(close(rfd2));
|
TEST_SUCC(close(rfd2));
|
||||||
}
|
}
|
||||||
END_TEST()
|
END_TEST()
|
||||||
|
|
||||||
|
FN_TEST(epoll_mod)
|
||||||
|
{
|
||||||
|
int fildes[2];
|
||||||
|
int epfd, rfd, wfd;
|
||||||
|
struct epoll_event ev;
|
||||||
|
char buf[1];
|
||||||
|
|
||||||
|
// Setup pipes
|
||||||
|
TEST_SUCC(pipe(fildes));
|
||||||
|
rfd = fildes[0];
|
||||||
|
wfd = fildes[1];
|
||||||
|
TEST_SUCC(write(wfd, "", 1));
|
||||||
|
|
||||||
|
// Setup epoll
|
||||||
|
epfd = TEST_SUCC(epoll_create1(0));
|
||||||
|
ev.events = EPOLLOUT;
|
||||||
|
ev.data.fd = rfd;
|
||||||
|
TEST_SUCC(epoll_ctl(epfd, EPOLL_CTL_ADD, rfd, &ev));
|
||||||
|
|
||||||
|
// Wait for EPOLLOUT
|
||||||
|
TEST_RES(epoll_wait(epfd, &ev, 1, 0), _ret == 0);
|
||||||
|
|
||||||
|
// Modify the events
|
||||||
|
ev.events = EPOLLIN;
|
||||||
|
ev.data.fd = rfd;
|
||||||
|
TEST_SUCC(epoll_ctl(epfd, EPOLL_CTL_MOD, rfd, &ev));
|
||||||
|
|
||||||
|
// Wait for EPOLLIN
|
||||||
|
TEST_RES(epoll_wait(epfd, &ev, 1, 0), _ret == 1);
|
||||||
|
TEST_SUCC(read(rfd, buf, 1));
|
||||||
|
TEST_RES(epoll_wait(epfd, &ev, 1, 0), _ret == 0);
|
||||||
|
TEST_SUCC(write(wfd, "", 1));
|
||||||
|
TEST_RES(epoll_wait(epfd, &ev, 1, 0), _ret == 1);
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
TEST_SUCC(close(epfd));
|
||||||
|
TEST_SUCC(close(rfd));
|
||||||
|
TEST_SUCC(close(wfd));
|
||||||
|
}
|
||||||
|
END_TEST()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user