mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 16:33:24 +00:00
Make wait_events
support timeout
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
f21394c679
commit
7ddfd42baa
@ -138,7 +138,7 @@ impl FileIo for PtyMaster {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: deal with nonblocking and timeout
|
// TODO: deal with nonblocking and timeout
|
||||||
self.wait_events(IoEvents::IN, || self.try_read(writer))
|
self.wait_events(IoEvents::IN, None, || self.try_read(writer))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&self, reader: &mut VmReader) -> Result<usize> {
|
fn write(&self, reader: &mut VmReader) -> Result<usize> {
|
||||||
|
@ -235,7 +235,7 @@ impl LineDiscipline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
||||||
self.wait_events(IoEvents::IN, || self.try_read(buf))
|
self.wait_events(IoEvents::IN, None, || self.try_read(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads all bytes buffered to `dst`.
|
/// Reads all bytes buffered to `dst`.
|
||||||
|
@ -194,34 +194,21 @@ impl EpollFile {
|
|||||||
/// expires or a signal arrives.
|
/// expires or a signal arrives.
|
||||||
pub fn wait(&self, max_events: usize, timeout: Option<&Duration>) -> Result<Vec<EpollEvent>> {
|
pub fn wait(&self, max_events: usize, timeout: Option<&Duration>) -> Result<Vec<EpollEvent>> {
|
||||||
let mut ep_events = Vec::new();
|
let mut ep_events = Vec::new();
|
||||||
let mut poller = None;
|
|
||||||
loop {
|
self.wait_events(IoEvents::IN, timeout, || {
|
||||||
// Try to pop some ready entries
|
|
||||||
self.pop_multi_ready(max_events, &mut ep_events);
|
self.pop_multi_ready(max_events, &mut ep_events);
|
||||||
if !ep_events.is_empty() {
|
|
||||||
return Ok(ep_events);
|
if ep_events.is_empty() {
|
||||||
|
return Err(Error::with_message(
|
||||||
|
Errno::EAGAIN,
|
||||||
|
"there are no available events",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return immediately if specifying a timeout of zero
|
Ok(())
|
||||||
if timeout.is_some() && timeout.as_ref().unwrap().is_zero() {
|
})?;
|
||||||
return Ok(ep_events);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no ready entries for now, wait for them
|
Ok(ep_events)
|
||||||
if poller.is_none() {
|
|
||||||
poller = Some(Poller::new());
|
|
||||||
let events = self.pollee.poll(IoEvents::IN, poller.as_mut());
|
|
||||||
if !events.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(timeout) = timeout {
|
|
||||||
poller.as_ref().unwrap().wait_timeout(timeout)?;
|
|
||||||
} else {
|
|
||||||
poller.as_ref().unwrap().wait()?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_ready(&self, entry: Arc<EpollEntry>) {
|
fn push_ready(&self, entry: Arc<EpollEntry>) {
|
||||||
|
@ -63,7 +63,7 @@ impl FileLike for PipeReader {
|
|||||||
let read_len = if self.status_flags().contains(StatusFlags::O_NONBLOCK) {
|
let read_len = if self.status_flags().contains(StatusFlags::O_NONBLOCK) {
|
||||||
self.consumer.try_read(writer)?
|
self.consumer.try_read(writer)?
|
||||||
} else {
|
} else {
|
||||||
self.wait_events(IoEvents::IN, || self.consumer.try_read(writer))?
|
self.wait_events(IoEvents::IN, None, || self.consumer.try_read(writer))?
|
||||||
};
|
};
|
||||||
Ok(read_len)
|
Ok(read_len)
|
||||||
}
|
}
|
||||||
@ -148,7 +148,7 @@ impl FileLike for PipeWriter {
|
|||||||
if self.status_flags().contains(StatusFlags::O_NONBLOCK) {
|
if self.status_flags().contains(StatusFlags::O_NONBLOCK) {
|
||||||
self.producer.try_write(reader)
|
self.producer.try_write(reader)
|
||||||
} else {
|
} else {
|
||||||
self.wait_events(IoEvents::OUT, || self.producer.try_write(reader))
|
self.wait_events(IoEvents::OUT, None, || self.producer.try_write(reader))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ impl DatagramSocket {
|
|||||||
if self.is_nonblocking() {
|
if self.is_nonblocking() {
|
||||||
self.try_recv(writer, flags)
|
self.try_recv(writer, flags)
|
||||||
} else {
|
} else {
|
||||||
self.wait_events(IoEvents::IN, || self.try_recv(writer, flags))
|
self.wait_events(IoEvents::IN, None, || self.try_recv(writer, flags))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ impl StreamSocket {
|
|||||||
if self.is_nonblocking() {
|
if self.is_nonblocking() {
|
||||||
self.try_recv(writer, flags)
|
self.try_recv(writer, flags)
|
||||||
} else {
|
} else {
|
||||||
self.wait_events(IoEvents::IN, || self.try_recv(writer, flags))
|
self.wait_events(IoEvents::IN, None, || self.try_recv(writer, flags))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +350,7 @@ impl StreamSocket {
|
|||||||
if self.is_nonblocking() {
|
if self.is_nonblocking() {
|
||||||
self.try_send(reader, flags)
|
self.try_send(reader, flags)
|
||||||
} else {
|
} else {
|
||||||
self.wait_events(IoEvents::OUT, || self.try_send(reader, flags))
|
self.wait_events(IoEvents::OUT, None, || self.try_send(reader, flags))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,7 +479,7 @@ impl Socket for StreamSocket {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.wait_events(IoEvents::OUT, || self.check_connect())
|
self.wait_events(IoEvents::OUT, None, || self.check_connect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn listen(&self, backlog: usize) -> Result<()> {
|
fn listen(&self, backlog: usize) -> Result<()> {
|
||||||
@ -518,7 +518,7 @@ impl Socket for StreamSocket {
|
|||||||
if self.is_nonblocking() {
|
if self.is_nonblocking() {
|
||||||
self.try_accept()
|
self.try_accept()
|
||||||
} else {
|
} else {
|
||||||
self.wait_events(IoEvents::IN, || self.try_accept())
|
self.wait_events(IoEvents::IN, None, || self.try_accept())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ impl UnixStreamSocket {
|
|||||||
if self.is_nonblocking() {
|
if self.is_nonblocking() {
|
||||||
self.try_send(reader, flags)
|
self.try_send(reader, flags)
|
||||||
} else {
|
} else {
|
||||||
self.wait_events(IoEvents::OUT, || self.try_send(reader, flags))
|
self.wait_events(IoEvents::OUT, None, || self.try_send(reader, flags))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ impl UnixStreamSocket {
|
|||||||
if self.is_nonblocking() {
|
if self.is_nonblocking() {
|
||||||
self.try_recv(writer, flags)
|
self.try_recv(writer, flags)
|
||||||
} else {
|
} else {
|
||||||
self.wait_events(IoEvents::IN, || self.try_recv(writer, flags))
|
self.wait_events(IoEvents::IN, None, || self.try_recv(writer, flags))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,7 +296,7 @@ impl Socket for UnixStreamSocket {
|
|||||||
if self.is_nonblocking() {
|
if self.is_nonblocking() {
|
||||||
self.try_accept()
|
self.try_accept()
|
||||||
} else {
|
} else {
|
||||||
self.wait_events(IoEvents::IN, || self.try_accept())
|
self.wait_events(IoEvents::IN, None, || self.try_accept())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ impl VsockStreamSocket {
|
|||||||
if self.is_nonblocking() {
|
if self.is_nonblocking() {
|
||||||
self.try_recv(writer, flags)
|
self.try_recv(writer, flags)
|
||||||
} else {
|
} else {
|
||||||
self.wait_events(IoEvents::IN, || self.try_recv(writer, flags))
|
self.wait_events(IoEvents::IN, None, || self.try_recv(writer, flags))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ impl Socket for VsockStreamSocket {
|
|||||||
.poll(IoEvents::IN, Some(&mut poller))
|
.poll(IoEvents::IN, Some(&mut poller))
|
||||||
.contains(IoEvents::IN)
|
.contains(IoEvents::IN)
|
||||||
{
|
{
|
||||||
if let Err(e) = poller.wait() {
|
if let Err(e) = poller.wait(None) {
|
||||||
vsockspace
|
vsockspace
|
||||||
.remove_connecting_socket(&connecting.local_addr())
|
.remove_connecting_socket(&connecting.local_addr())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -285,7 +285,7 @@ impl Socket for VsockStreamSocket {
|
|||||||
if self.is_nonblocking() {
|
if self.is_nonblocking() {
|
||||||
self.try_accept()
|
self.try_accept()
|
||||||
} else {
|
} else {
|
||||||
self.wait_events(IoEvents::IN, || self.try_accept())
|
self.wait_events(IoEvents::IN, None, || self.try_accept())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,17 +158,12 @@ impl Poller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait until there are any interesting events happen since last `wait`. The `wait`
|
/// Waits until some interesting events happen since the last wait or until the timeout
|
||||||
/// can be interrupted by signal.
|
/// expires.
|
||||||
pub fn wait(&self) -> Result<()> {
|
///
|
||||||
self.event_counter.read(&self.waiter, None)?;
|
/// The waiting process can be interrupted by a signal.
|
||||||
Ok(())
|
pub fn wait(&self, timeout: Option<&Duration>) -> Result<()> {
|
||||||
}
|
self.event_counter.read(&self.waiter, timeout)?;
|
||||||
|
|
||||||
/// Wait until there are any interesting events happen since last `wait` or a given timeout
|
|
||||||
/// is expired. This method can be interrupted by signal.
|
|
||||||
pub fn wait_timeout(&self, timeout: &Duration) -> Result<()> {
|
|
||||||
self.event_counter.read(&self.waiter, Some(timeout))?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,29 +251,52 @@ pub trait Pollable {
|
|||||||
/// will return whatever the call to `cond()` returns. Otherwise, the method will wait for some
|
/// will return whatever the call to `cond()` returns. Otherwise, the method will wait for some
|
||||||
/// interesting events specified in `mask` to happen and try again.
|
/// interesting events specified in `mask` to happen and try again.
|
||||||
///
|
///
|
||||||
|
/// This method will fail with `ETIME` if the timeout is specified and the event does not occur
|
||||||
|
/// before the timeout expires.
|
||||||
|
///
|
||||||
/// The user must ensure that a call to `cond()` does not fail with `EAGAIN` when the
|
/// The user must ensure that a call to `cond()` does not fail with `EAGAIN` when the
|
||||||
/// interesting events occur. However, it is allowed to have spurious `EAGAIN` failures due to
|
/// interesting events occur. However, it is allowed to have spurious `EAGAIN` failures due to
|
||||||
/// race conditions where the events are consumed by another thread.
|
/// race conditions where the events are consumed by another thread.
|
||||||
fn wait_events<F, R>(&self, mask: IoEvents, mut cond: F) -> Result<R>
|
fn wait_events<F, R>(
|
||||||
|
&self,
|
||||||
|
mask: IoEvents,
|
||||||
|
timeout: Option<&Duration>,
|
||||||
|
mut cond: F,
|
||||||
|
) -> Result<R>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
F: FnMut() -> Result<R>,
|
F: FnMut() -> Result<R>,
|
||||||
{
|
{
|
||||||
|
// Fast path: Return immediately if the operation gives a result.
|
||||||
|
match cond() {
|
||||||
|
Err(err) if err.error() == Errno::EAGAIN => (),
|
||||||
|
result => return result,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fast path: Return immediately if the timeout is zero.
|
||||||
|
if timeout.is_some_and(|duration| duration.is_zero()) {
|
||||||
|
return_errno_with_message!(Errno::ETIME, "the timeout expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until the event happens.
|
||||||
let mut poller = Poller::new();
|
let mut poller = Poller::new();
|
||||||
|
if self.poll(mask, Some(&mut poller)).is_empty() {
|
||||||
|
poller.wait(timeout)?;
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
// Try again after the event happens.
|
||||||
match cond() {
|
match cond() {
|
||||||
Err(err) if err.error() == Errno::EAGAIN => (),
|
Err(err) if err.error() == Errno::EAGAIN => (),
|
||||||
result => return result,
|
result => return result,
|
||||||
};
|
};
|
||||||
|
|
||||||
let events = self.poll(mask, Some(&mut poller));
|
// Wait until the next event happens.
|
||||||
if !events.is_empty() {
|
//
|
||||||
continue;
|
// FIXME: We need to update `timeout` since we have waited for some time.
|
||||||
}
|
if self.poll(mask, Some(&mut poller)).is_empty() {
|
||||||
|
poller.wait(timeout)?;
|
||||||
// TODO: Support timeout
|
}
|
||||||
poller.wait()?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,7 @@ impl FileLike for EventFile {
|
|||||||
if self.is_nonblocking() {
|
if self.is_nonblocking() {
|
||||||
self.try_read(writer)?;
|
self.try_read(writer)?;
|
||||||
} else {
|
} else {
|
||||||
self.wait_events(IoEvents::IN, || self.try_read(writer))?;
|
self.wait_events(IoEvents::IN, None, || self.try_read(writer))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(read_len)
|
Ok(read_len)
|
||||||
|
@ -41,7 +41,7 @@ pub fn sys_poll(fds: Vaddr, nfds: u64, timeout: i32, ctx: &Context) -> Result<Sy
|
|||||||
poll_fds, nfds, timeout
|
poll_fds, nfds, timeout
|
||||||
);
|
);
|
||||||
|
|
||||||
let num_revents = do_poll(&poll_fds, timeout, ctx)?;
|
let num_revents = do_poll(&poll_fds, timeout.as_ref(), ctx)?;
|
||||||
|
|
||||||
// Write back
|
// Write back
|
||||||
let mut write_addr = fds;
|
let mut write_addr = fds;
|
||||||
@ -55,7 +55,7 @@ pub fn sys_poll(fds: Vaddr, nfds: u64, timeout: i32, ctx: &Context) -> Result<Sy
|
|||||||
Ok(SyscallReturn::Return(num_revents as _))
|
Ok(SyscallReturn::Return(num_revents as _))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_poll(poll_fds: &[PollFd], timeout: Option<Duration>, ctx: &Context) -> Result<usize> {
|
pub fn do_poll(poll_fds: &[PollFd], timeout: Option<&Duration>, ctx: &Context) -> Result<usize> {
|
||||||
let (result, files) = hold_files(poll_fds, ctx);
|
let (result, files) = hold_files(poll_fds, ctx);
|
||||||
match result {
|
match result {
|
||||||
FileResult::AllValid => (),
|
FileResult::AllValid => (),
|
||||||
@ -74,8 +74,7 @@ pub fn do_poll(poll_fds: &[PollFd], timeout: Option<Duration>, ctx: &Context) ->
|
|||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Some(timeout) = timeout.as_ref() {
|
match poller.wait(timeout) {
|
||||||
match poller.wait_timeout(timeout) {
|
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) if e.error() == Errno::ETIME => {
|
Err(e) if e.error() == Errno::ETIME => {
|
||||||
// The return value is zero if the timeout expires
|
// The return value is zero if the timeout expires
|
||||||
@ -84,14 +83,13 @@ pub fn do_poll(poll_fds: &[PollFd], timeout: Option<Duration>, ctx: &Context) ->
|
|||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
poller.wait()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let num_events = count_all_events(poll_fds, &files);
|
let num_events = count_all_events(poll_fds, &files);
|
||||||
if num_events > 0 {
|
if num_events > 0 {
|
||||||
return Ok(num_events);
|
return Ok(num_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: We need to update `timeout` since we have waited for some time.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ pub fn do_sys_select(
|
|||||||
readfds.as_mut(),
|
readfds.as_mut(),
|
||||||
writefds.as_mut(),
|
writefds.as_mut(),
|
||||||
exceptfds.as_mut(),
|
exceptfds.as_mut(),
|
||||||
timeout,
|
timeout.as_ref(),
|
||||||
ctx,
|
ctx,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ fn do_select(
|
|||||||
mut readfds: Option<&mut FdSet>,
|
mut readfds: Option<&mut FdSet>,
|
||||||
mut writefds: Option<&mut FdSet>,
|
mut writefds: Option<&mut FdSet>,
|
||||||
mut exceptfds: Option<&mut FdSet>,
|
mut exceptfds: Option<&mut FdSet>,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<&Duration>,
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
) -> Result<usize> {
|
) -> Result<usize> {
|
||||||
// Convert the FdSet to an array of PollFd
|
// Convert the FdSet to an array of PollFd
|
||||||
|
Reference in New Issue
Block a user