Make fd_monitor types useable from native code

We were only using their ffi implementations which are automatically
exported/public, but the actual functions we would need if we were to use
FdMonitor and co. in native rust code were either private or missing convenient
wrappers.
This commit is contained in:
Mahmoud Al-Qudsi 2023-03-04 23:43:46 -06:00
parent 78a78a834c
commit 83a220a532

View File

@ -3,7 +3,8 @@ use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use self::fd_monitor_ffi::{new_fd_event_signaller, FdEventSignaller, ItemWakeReason};
pub use self::fd_monitor_ffi::ItemWakeReason;
use self::fd_monitor_ffi::{new_fd_event_signaller, FdEventSignaller};
use crate::fd_readable_set::FdReadableSet;
use crate::fds::AutoCloseFd;
use crate::ffi::void_ptr;
@ -93,7 +94,20 @@ unsafe impl Send for FdEventSignaller {}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct FdMonitorItemId(u64);
impl From<FdMonitorItemId> for u64 {
fn from(value: FdMonitorItemId) -> Self {
value.0
}
}
impl From<u64> for FdMonitorItemId {
fn from(value: u64) -> Self {
FdMonitorItemId(value)
}
}
type FfiCallback = extern "C" fn(*mut AutoCloseFd, u8, void_ptr);
type NativeCallback = Box<dyn Fn(&mut AutoCloseFd, ItemWakeReason) + Send + Sync>;
/// 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
@ -107,7 +121,7 @@ type FfiCallback = extern "C" fn(*mut AutoCloseFd, u8, void_ptr);
enum FdMonitorCallback {
None,
#[allow(clippy::type_complexity)]
Native(Box<dyn Fn(&mut AutoCloseFd, ItemWakeReason) + Send + Sync>),
Native(NativeCallback),
Ffi(FfiCallback /* fn ptr */, void_ptr /* param */),
}
@ -139,6 +153,11 @@ enum ItemAction {
}
impl FdMonitorItem {
/// Returns the id for this `FdMonitorItem` that is registered with the [`FdMonitor`].
pub fn id(&self) -> FdMonitorItemId {
self.item_id
}
/// Return the duration until the timeout should trigger or `None`. A return of `0` means we are
/// at or past the timeout.
fn remaining_time(&self, now: &Instant) -> Option<Duration> {
@ -208,16 +227,27 @@ impl FdMonitorItem {
}
}
fn new() -> Self {
Self {
callback: FdMonitorCallback::None,
fd: AutoCloseFd::empty(),
timeout: None,
last_time: None,
pub fn new(
fd: AutoCloseFd,
timeout: Option<Duration>,
callback: Option<NativeCallback>,
) -> Self {
FdMonitorItem {
fd,
timeout,
callback: match callback {
Some(callback) => FdMonitorCallback::Native(callback),
None => FdMonitorCallback::None,
},
item_id: FdMonitorItemId(0),
last_time: None,
}
}
pub fn set_callback(&mut self, callback: NativeCallback) {
self.callback = FdMonitorCallback::Native(callback);
}
fn set_callback_ffi(&mut self, callback: *const u8, param: *const u8) {
// Safety: we are just marshalling our function pointers with identical definitions on both
// sides of the ffi bridge as void pointers to keep cxx bridge happy. Whether we invoke the
@ -228,6 +258,18 @@ impl FdMonitorItem {
}
}
impl Default for FdMonitorItem {
fn default() -> Self {
Self {
callback: FdMonitorCallback::None,
fd: AutoCloseFd::empty(),
timeout: None,
last_time: None,
item_id: FdMonitorItemId(0),
}
}
}
// cxx bridge does not support "static member functions" in C++ or rust, so we need a top-level fn.
fn new_fd_monitor_ffi() -> Box<FdMonitor> {
Box::new(FdMonitor::new())
@ -245,7 +287,7 @@ fn new_fd_monitor_item_ffi(
// raw function as a void pointer or as a typed fn that helps us keep track of what we're
// doing is unsafe in all cases, so might as well make the best of it.
let callback = unsafe { std::mem::transmute(callback) };
let mut item = FdMonitorItem::new();
let mut item = FdMonitorItem::default();
item.fd.reset(fd);
item.callback = FdMonitorCallback::Ffi(callback, param.into());
if timeout_usecs != FdReadableSet::kNoTimeout {
@ -360,7 +402,7 @@ impl FdMonitor {
// raw function as a void pointer or as a typed fn that helps us keep track of what we're
// doing is unsafe in all cases, so might as well make the best of it.
let callback = unsafe { std::mem::transmute(callback) };
let mut item = FdMonitorItem::new();
let mut item = FdMonitorItem::default();
item.fd.reset(fd);
item.callback = FdMonitorCallback::Ffi(callback, param.into());
if timeout_usecs != FdReadableSet::kNoTimeout {