Further cleanup of FdMonitor

This commit is contained in:
ridiculousfish 2024-01-13 12:35:55 -08:00
parent d8da79717e
commit 8554eb5f80
3 changed files with 25 additions and 29 deletions

View File

@ -192,10 +192,10 @@ impl From<u64> for FdMonitorItemId {
} }
/// The callback type used by [`FdMonitorItem`]. It is passed a mutable reference to the /// The callback type used by [`FdMonitorItem`]. It is passed a mutable reference to the
/// `FdMonitorItem`'s [`FdMonitorItem::fd`] and [the reason](ItemWakeupReason) for the wakeup. The /// `FdMonitorItem`'s [`FdMonitorItem::fd`] and [the reason](ItemWakeupReason) for the wakeup.
/// callback may close the fd, in which case the `FdMonitorItem` is removed from [`FdMonitor`]'s /// It should return an [`ItemAction`] to indicate whether the item should be removed from the
/// set. /// [`FdMonitor`] set.
pub type Callback = Box<dyn Fn(&mut AutoCloseFd, ItemWakeReason) + Send + Sync>; pub type Callback = Box<dyn Fn(&mut AutoCloseFd, ItemWakeReason) -> ItemAction + Send + Sync>;
/// An item containing an fd and callback, which can be monitored to watch when it becomes readable /// An item containing an fd and callback, which can be monitored to watch when it becomes readable
/// and invoke the callback. /// and invoke the callback.
@ -214,11 +214,9 @@ pub struct FdMonitorItem {
item_id: FdMonitorItemId, item_id: FdMonitorItemId,
} }
/// Unlike C++, rust's `Vec` has `Vec::retain()` instead of `std::remove_if(...)` with the inverse /// A value returned by the callback to indicate what to do with the item.
/// logic. It's hard to keep track of which bool means what across the different layers, so be more
/// explicit.
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
enum ItemAction { pub enum ItemAction {
Remove, Remove,
Retain, Retain,
} }
@ -257,12 +255,9 @@ impl FdMonitorItem {
} else { } else {
ItemWakeReason::Timeout ItemWakeReason::Timeout
}; };
(self.callback)(&mut self.fd, reason); result = (self.callback)(&mut self.fd, reason);
if !self.fd.is_valid() {
result = ItemAction::Remove;
}
} }
return result; result
} }
/// Invoke this item's callback with a poke, if its id is present in the sorted poke list. /// Invoke this item's callback with a poke, if its id is present in the sorted poke list.
@ -272,12 +267,7 @@ impl FdMonitorItem {
return ItemAction::Retain; return ItemAction::Retain;
} }
(self.callback)(&mut self.fd, ItemWakeReason::Poke); (self.callback)(&mut self.fd, ItemWakeReason::Poke)
// Return `ItemAction::Remove` if the callback closed the fd
match self.fd.is_valid() {
true => ItemAction::Retain,
false => ItemAction::Remove,
}
} }
pub fn new(fd: AutoCloseFd, timeout: Option<Duration>, callback: Callback) -> Self { pub fn new(fd: AutoCloseFd, timeout: Option<Duration>, callback: Callback) -> Self {
@ -483,11 +473,11 @@ impl BackgroundFdMonitor {
// A predicate which services each item in turn, returning true if it should be removed // A predicate which services each item in turn, returning true if it should be removed
let servicer = |item: &mut FdMonitorItem| { let servicer = |item: &mut FdMonitorItem| {
let fd = item.fd.as_raw_fd(); let fd = item.fd.as_raw_fd();
if item.service_item(&fds, &now) == ItemAction::Remove { let action = item.service_item(&fds, &now);
if action == ItemAction::Remove {
FLOG!(fd_monitor, "Removing fd", fd); FLOG!(fd_monitor, "Removing fd", fd);
return ItemAction::Remove;
} }
return ItemAction::Retain; action
}; };
// Service all items that are either readable or have timed out, and remove any which // Service all items that are either readable or have timed out, and remove any which

View File

@ -1,6 +1,8 @@
use crate::builtins::shared::{STATUS_CMD_ERROR, STATUS_CMD_OK, STATUS_READ_TOO_MUCH}; use crate::builtins::shared::{STATUS_CMD_ERROR, STATUS_CMD_OK, STATUS_READ_TOO_MUCH};
use crate::common::{str2wcstring, wcs2string, EMPTY_STRING}; use crate::common::{str2wcstring, wcs2string, EMPTY_STRING};
use crate::fd_monitor::{Callback, FdMonitor, FdMonitorItem, FdMonitorItemId, ItemWakeReason}; use crate::fd_monitor::{
Callback, FdMonitor, FdMonitorItem, FdMonitorItemId, ItemAction, ItemWakeReason,
};
use crate::fds::{ use crate::fds::{
make_autoclose_pipes, make_fd_nonblocking, wopen_cloexec, AutoCloseFd, PIPE_ERROR, make_autoclose_pipes, make_fd_nonblocking, wopen_cloexec, AutoCloseFd, PIPE_ERROR,
}; };
@ -580,7 +582,9 @@ fn begin_filling(iobuffer: &Arc<IoBuffer>, fd: AutoCloseFd) {
} }
done = true; done = true;
} }
if done { if !done {
ItemAction::Retain
} else {
fd.close(); fd.close();
let (mutex, condvar) = &*promise; let (mutex, condvar) = &*promise;
{ {
@ -588,6 +592,7 @@ fn begin_filling(iobuffer: &Arc<IoBuffer>, fd: AutoCloseFd) {
*done = true; *done = true;
} }
condvar.notify_one(); condvar.notify_one();
ItemAction::Remove
} }
}) })
}; };

View File

@ -5,7 +5,7 @@ use std::sync::{Arc, Mutex};
use std::time::Duration; use std::time::Duration;
use crate::fd_monitor::{ use crate::fd_monitor::{
FdEventSignaller, FdMonitor, FdMonitorItem, FdMonitorItemId, ItemWakeReason, FdEventSignaller, FdMonitor, FdMonitorItem, FdMonitorItemId, ItemAction, ItemWakeReason,
}; };
use crate::fds::{make_autoclose_pipes, AutoCloseFd}; use crate::fds::{make_autoclose_pipes, AutoCloseFd};
use crate::tests::prelude::*; use crate::tests::prelude::*;
@ -51,9 +51,7 @@ impl ItemMaker {
let result = Arc::new(result); let result = Arc::new(result);
let callback = { let callback = {
let result = Arc::clone(&result); let result = Arc::clone(&result);
move |fd: &mut AutoCloseFd, reason: ItemWakeReason| { move |fd: &mut AutoCloseFd, reason: ItemWakeReason| result.callback(fd, reason)
result.callback(fd, reason);
}
}; };
let item = FdMonitorItem::new(pipes.read, timeout, Box::new(callback)); let item = FdMonitorItem::new(pipes.read, timeout, Box::new(callback));
let item_id = monitor.add(item); let item_id = monitor.add(item);
@ -66,7 +64,7 @@ impl ItemMaker {
self.item_id.load(Ordering::Relaxed).into() self.item_id.load(Ordering::Relaxed).into()
} }
fn callback(&self, fd: &mut AutoCloseFd, reason: ItemWakeReason) { fn callback(&self, fd: &mut AutoCloseFd, reason: ItemWakeReason) -> ItemAction {
let mut was_closed = false; let mut was_closed = false;
match reason { match reason {
@ -89,6 +87,9 @@ impl ItemMaker {
self.total_calls.fetch_add(1, Ordering::Relaxed); self.total_calls.fetch_add(1, Ordering::Relaxed);
if self.always_exit || was_closed { if self.always_exit || was_closed {
fd.close(); fd.close();
ItemAction::Remove
} else {
ItemAction::Retain
} }
} }