refactor: split cargo workspace
This commit is contained in:
parent
5db14936e7
commit
1c21bd1259
695 changed files with 32023 additions and 44964 deletions
14
crates/eventfd-cache/Cargo.toml
Normal file
14
crates/eventfd-cache/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "jay-eventfd-cache"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = "GPL-3.0-only"
|
||||
|
||||
[dependencies]
|
||||
jay-async-engine = { version = "0.1.0", path = "../async-engine" }
|
||||
jay-io-uring = { version = "0.1.0", path = "../io-uring" }
|
||||
jay-utils = { version = "0.1.0", path = "../utils" }
|
||||
|
||||
log = { version = "0.4.20", features = ["std"] }
|
||||
thiserror = "2.0.11"
|
||||
uapi = "0.2.13"
|
||||
157
crates/eventfd-cache/src/lib.rs
Normal file
157
crates/eventfd-cache/src/lib.rs
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
use {
|
||||
jay_async_engine::{AsyncEngine, SpawnedFuture},
|
||||
jay_io_uring::{IoUring, IoUringError},
|
||||
jay_utils::{
|
||||
buf::Buf,
|
||||
errorfmt::ErrorFmt,
|
||||
oserror::{OsError, OsErrorExt, OsErrorExt2},
|
||||
queue::AsyncQueue,
|
||||
stack::Stack,
|
||||
},
|
||||
std::{cell::Cell, future::poll_fn, pin::Pin, rc::Rc, slice, task::Poll},
|
||||
thiserror::Error,
|
||||
uapi::{OwnedFd, c},
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum EventfdError {
|
||||
#[error("Could not create an eventfd")]
|
||||
CreateEventfd(#[source] OsError),
|
||||
}
|
||||
|
||||
pub struct EventfdCache {
|
||||
inner: Rc<Inner>,
|
||||
_task: SpawnedFuture<()>,
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
ring: Rc<IoUring>,
|
||||
fds: Stack<Rc<OwnedFd>>,
|
||||
recycle: AsyncQueue<Rc<OwnedFd>>,
|
||||
}
|
||||
|
||||
pub struct Eventfd {
|
||||
cache: Rc<Inner>,
|
||||
pub fd: Rc<OwnedFd>,
|
||||
signaled: Cell<bool>,
|
||||
}
|
||||
|
||||
impl EventfdCache {
|
||||
pub fn new(ring: &Rc<IoUring>, eng: &Rc<AsyncEngine>) -> Rc<Self> {
|
||||
let inner = Rc::new(Inner {
|
||||
ring: ring.clone(),
|
||||
fds: Default::default(),
|
||||
recycle: Default::default(),
|
||||
});
|
||||
let task = eng.spawn("eventfd-cache", inner.clone().recycle());
|
||||
Rc::new(Self { inner, _task: task })
|
||||
}
|
||||
|
||||
pub fn acquire(&self) -> Result<Eventfd, EventfdError> {
|
||||
let fd = match self.inner.fds.pop() {
|
||||
Some(fd) => fd,
|
||||
_ => uapi::eventfd(0, c::EFD_CLOEXEC)
|
||||
.map(Rc::new)
|
||||
.map_os_err(EventfdError::CreateEventfd)?,
|
||||
};
|
||||
Ok(Eventfd {
|
||||
cache: self.inner.clone(),
|
||||
fd,
|
||||
signaled: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Eventfd {
|
||||
pub fn is_signaled(&self) -> bool {
|
||||
self.signaled.get()
|
||||
}
|
||||
|
||||
pub async fn signaled(&self) -> Result<(), IoUringError> {
|
||||
if self.signaled.get() {
|
||||
return Ok(());
|
||||
}
|
||||
self.cache.ring.readable(&self.fd).await?;
|
||||
self.signaled.set(true);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn signaled_blocking(&self) -> Result<(), OsError> {
|
||||
if self.signaled.get() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut pollfd = c::pollfd {
|
||||
fd: self.fd.raw(),
|
||||
events: c::POLLIN,
|
||||
revents: 0,
|
||||
};
|
||||
uapi::poll(slice::from_mut(&mut pollfd), -1).to_os_error()?;
|
||||
self.signaled.set(true);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
async fn recycle(self: Rc<Self>) {
|
||||
let slf = &*self;
|
||||
let mut fds = vec![];
|
||||
let mut bufs = vec![];
|
||||
let mut tasks = vec![];
|
||||
let mut todo = vec![];
|
||||
loop {
|
||||
fds.clear();
|
||||
tasks.clear();
|
||||
todo.clear();
|
||||
slf.recycle.non_empty().await;
|
||||
while let Some(fd) = slf.recycle.try_pop() {
|
||||
fds.push(fd);
|
||||
}
|
||||
for (idx, fd) in fds.iter().enumerate() {
|
||||
if idx >= bufs.len() {
|
||||
bufs.push(Buf::new(size_of::<u64>()));
|
||||
}
|
||||
let fd = fd.clone();
|
||||
let buf = bufs[idx].clone();
|
||||
tasks.push(async move { slf.ring.read(&fd, buf).await });
|
||||
todo.push(idx);
|
||||
}
|
||||
poll_fn(|ctx| {
|
||||
let mut i = 0;
|
||||
while i < todo.len() {
|
||||
let idx = todo[i];
|
||||
let task = unsafe { Pin::new_unchecked(&mut tasks[idx]) };
|
||||
if let Poll::Ready(res) = task.poll(ctx) {
|
||||
todo.swap_remove(i);
|
||||
match res {
|
||||
Ok(_) => {
|
||||
self.fds.push(fds[idx].clone());
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Could not read from eventfd: {}", ErrorFmt(e));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
if todo.is_empty() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Eventfd {
|
||||
fn drop(&mut self) {
|
||||
if self.signaled.get() {
|
||||
self.cache.recycle.push(self.fd.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
67
crates/eventfd-cache/src/tests.rs
Normal file
67
crates/eventfd-cache/src/tests.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
use {
|
||||
crate::EventfdCache,
|
||||
jay_async_engine::AsyncEngine,
|
||||
jay_io_uring::IoUring,
|
||||
jay_utils::array,
|
||||
std::{rc::Rc, slice},
|
||||
uapi::c,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let eng = AsyncEngine::new();
|
||||
let ring = IoUring::new(&eng, 32).unwrap();
|
||||
let cache = Rc::new(EventfdCache::new(&ring, &eng));
|
||||
const TOTAL: usize = 5;
|
||||
let signaled = 3;
|
||||
let fd1: [_; TOTAL] = array::from_fn(|_| cache.acquire().unwrap());
|
||||
let fd2: [_; TOTAL] = array::from_fn(|_| cache.acquire().unwrap());
|
||||
for fd in fd1.iter().chain(fd2.iter()) {
|
||||
uapi::eventfd_write(fd.fd.raw(), 1).unwrap();
|
||||
let mut poll = c::pollfd {
|
||||
fd: fd.fd.raw(),
|
||||
events: c::POLLIN,
|
||||
revents: 0,
|
||||
};
|
||||
uapi::poll(slice::from_mut(&mut poll), 0).unwrap();
|
||||
assert_eq!(poll.revents, c::POLLIN);
|
||||
}
|
||||
assert_eq!(cache.inner.fds.len(), 0);
|
||||
let ring2 = ring.clone();
|
||||
let cache2 = cache.clone();
|
||||
let _fut1 = eng.spawn("", async move {
|
||||
for i in 0..signaled {
|
||||
fd1[i].signaled().await.unwrap();
|
||||
}
|
||||
drop(fd1);
|
||||
let debouncer = ring2.debouncer(0);
|
||||
while cache2.inner.fds.len() != signaled {
|
||||
debouncer.debounce().await;
|
||||
}
|
||||
for i in 0..signaled {
|
||||
fd2[i].signaled().await.unwrap();
|
||||
}
|
||||
drop(fd2);
|
||||
while cache2.inner.fds.len() != 2 * signaled {
|
||||
debouncer.debounce().await;
|
||||
}
|
||||
ring2.stop();
|
||||
});
|
||||
let now_nsec = eng.now().nsec();
|
||||
let ring2 = ring.clone();
|
||||
let _fut2 = eng.spawn("", async move {
|
||||
ring2.timeout(now_nsec + 1_000_000_000).await.unwrap();
|
||||
ring2.stop();
|
||||
});
|
||||
ring.run().unwrap();
|
||||
assert_eq!(cache.inner.fds.len(), 2 * signaled);
|
||||
for fd in cache.inner.fds.take() {
|
||||
let mut poll = c::pollfd {
|
||||
fd: fd.raw(),
|
||||
events: c::POLLIN,
|
||||
revents: 0,
|
||||
};
|
||||
uapi::poll(slice::from_mut(&mut poll), 0).unwrap();
|
||||
assert_eq!(poll.revents, 0);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue