From 4d8a340cd0132e9647160d505e0640b11a12228f Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 12 May 2022 20:48:29 +0200 Subject: [PATCH] async: move timer out of async engine --- src/async_engine.rs | 16 ++------- src/async_engine/ae_timer.rs | 50 --------------------------- src/config/handler.rs | 16 +++++---- src/tasks/idle.rs | 14 ++++---- src/utils.rs | 1 + src/utils/timer.rs | 65 ++++++++++++++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 76 deletions(-) delete mode 100644 src/async_engine/ae_timer.rs create mode 100644 src/utils/timer.rs diff --git a/src/async_engine.rs b/src/async_engine.rs index 62655792..bf7b50ac 100644 --- a/src/async_engine.rs +++ b/src/async_engine.rs @@ -1,19 +1,17 @@ mod ae_fd; mod ae_queue; mod ae_task; -mod ae_timer; mod ae_yield; pub use { crate::async_engine::ae_yield::Yield, ae_fd::{AsyncFd, FdStatus}, ae_task::SpawnedFuture, - ae_timer::Timer, }; use { crate::{ event_loop::{EventLoop, EventLoopError}, - utils::{copyhashmap::CopyHashMap, numcell::NumCell, oserror::OsError}, + utils::{copyhashmap::CopyHashMap, numcell::NumCell}, }, ae_fd::AsyncFdData, ae_queue::{DispatchQueue, Dispatcher}, @@ -23,19 +21,13 @@ use { rc::Rc, }, thiserror::Error, - uapi::{c, OwnedFd}, + uapi::OwnedFd, }; #[derive(Debug, Error)] pub enum AsyncError { #[error("The event loop caused an error")] EventLoopError(#[from] EventLoopError), - #[error("Could not read from a timer")] - TimerReadError(#[source] OsError), - #[error("Could not set a timer")] - SetTimer(#[source] OsError), - #[error("Could not create a timer")] - CreateTimer(#[source] OsError), } #[derive(Copy, Clone, Eq, PartialEq)] @@ -63,10 +55,6 @@ impl AsyncEngine { })) } - pub fn timer(self: &Rc, clock_id: c::c_int) -> Result { - Timer::new(self, clock_id) - } - pub fn clear(&self) { for (_, fd) in self.fds.lock().drain() { fd.readers.take(); diff --git a/src/async_engine/ae_timer.rs b/src/async_engine/ae_timer.rs deleted file mode 100644 index fe72d336..00000000 --- a/src/async_engine/ae_timer.rs +++ /dev/null @@ -1,50 +0,0 @@ -use { - crate::async_engine::{AsyncEngine, AsyncError, AsyncFd}, - std::{rc::Rc, time::Duration}, - uapi::c, -}; - -#[derive(Clone)] -pub struct Timer { - fd: AsyncFd, -} - -impl Timer { - pub(super) fn new(eng: &Rc, clock_id: c::c_int) -> Result { - let fd = match uapi::timerfd_create(clock_id, c::TFD_CLOEXEC | c::TFD_NONBLOCK) { - Ok(fd) => fd, - Err(e) => return Err(AsyncError::CreateTimer(e.into())), - }; - let afd = eng.fd(&Rc::new(fd))?; - Ok(Self { fd: afd }) - } - - pub async fn expired(&self) -> Result { - self.fd.readable().await?; - let mut buf = 0u64; - if let Err(e) = uapi::read(self.fd.raw(), &mut buf) { - return Err(AsyncError::TimerReadError(e.into())); - } - Ok(buf) - } - - pub fn program( - &self, - initial: Option, - periodic: Option, - ) -> Result<(), AsyncError> { - let mut timerspec: c::itimerspec = uapi::pod_zeroed(); - if let Some(init) = initial { - timerspec.it_value.tv_sec = init.as_secs() as _; - timerspec.it_value.tv_nsec = init.subsec_nanos() as _; - if let Some(per) = periodic { - timerspec.it_interval.tv_sec = per.as_secs() as _; - timerspec.it_interval.tv_nsec = per.subsec_nanos() as _; - } - } - if let Err(e) = uapi::timerfd_settime(self.fd.raw(), 0, &timerspec) { - return Err(AsyncError::SetTimer(e.into())); - } - Ok(()) - } -} diff --git a/src/config/handler.rs b/src/config/handler.rs index b0445f3b..84a366eb 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -1,6 +1,6 @@ use { crate::{ - async_engine::{AsyncError, SpawnedFuture, Timer}, + async_engine::SpawnedFuture, backend::{ self, ConnectorId, DrmDeviceId, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, @@ -11,8 +11,12 @@ use { state::{ConnectorData, DeviceHandlerData, DrmDevData, OutputData, State}, tree::{ContainerNode, ContainerSplit, FloatNode, Node, NodeVisitorBase}, utils::{ - copyhashmap::CopyHashMap, debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell, + copyhashmap::CopyHashMap, + debug_fn::debug_fn, + errorfmt::ErrorFmt, + numcell::NumCell, stack::Stack, + timer::{TimerError, TimerFd}, }, xkbcommon::{XkbCommonError, XkbKeymap}, }, @@ -63,7 +67,7 @@ pub(super) struct ConfigProxyHandler { } pub(super) struct TimerData { - timer: Timer, + timer: TimerFd, id: u64, name: Rc, _handler: SpawnedFuture<()>, @@ -288,13 +292,13 @@ impl ConfigProxyHandler { return Ok(()); } let id = self.timer_ids.fetch_add(1); - let timer = self.state.eng.timer(c::CLOCK_BOOTTIME)?; + let timer = TimerFd::new(c::CLOCK_BOOTTIME)?; let handler = { let timer = timer.clone(); let slf = self.clone(); self.state.eng.spawn(async move { loop { - match timer.expired().await { + match timer.expired(&slf.state.ring).await { Ok(_) => slf.send(&ServerMessage::TimerExpired { timer: jay_config::Timer(id), }), @@ -1067,7 +1071,7 @@ enum CphError { #[error("Could not process a `{0}` request")] FailedRequest(&'static str, #[source] Box), #[error(transparent)] - AsyncError(#[from] AsyncError), + TimerError(#[from] TimerError), } trait WithRequestName { diff --git a/src/tasks/idle.rs b/src/tasks/idle.rs index 334afcf4..5787de03 100644 --- a/src/tasks/idle.rs +++ b/src/tasks/idle.rs @@ -1,9 +1,11 @@ use { crate::{ - async_engine::{AsyncError, Timer}, backend::Backend, state::State, - utils::errorfmt::ErrorFmt, + utils::{ + errorfmt::ErrorFmt, + timer::{TimerError, TimerFd}, + }, }, futures_util::{select, FutureExt}, std::{rc::Rc, time::Duration}, @@ -14,7 +16,7 @@ pub async fn idle(state: Rc, backend: Rc) { if !backend.supports_idle() { return; } - let timer = match state.eng.timer(c::CLOCK_MONOTONIC) { + let timer = match TimerFd::new(c::CLOCK_MONOTONIC) { Ok(t) => t, Err(e) => { log::error!("Could not create idle timer: {}", ErrorFmt(e)); @@ -38,7 +40,7 @@ pub async fn idle(state: Rc, backend: Rc) { struct Idle { state: Rc, backend: Rc, - timer: Timer, + timer: TimerFd, idle: bool, dead: bool, is_inhibited: bool, @@ -49,14 +51,14 @@ impl Idle { async fn run(&mut self) { while !self.dead { select! { - res = self.timer.expired().fuse() => self.handle_expired(res), + res = self.timer.expired(&self.state.ring).fuse() => self.handle_expired(res), _ = self.state.idle.change.triggered().fuse() => self.handle_idle_changes(), } } log::error!("Due to the above error, monitors will no longer be (de)activated.") } - fn handle_expired(&mut self, res: Result) { + fn handle_expired(&mut self, res: Result) { if let Err(e) = res { log::error!("Could not wait for idle timer to expire: {}", ErrorFmt(e)); self.dead = true; diff --git a/src/utils.rs b/src/utils.rs index 284803d1..4ecf2b3d 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -26,6 +26,7 @@ pub mod scroller; pub mod smallmap; pub mod stack; pub mod syncqueue; +pub mod timer; pub mod tri; pub mod trim; pub mod unlink_on_drop; diff --git a/src/utils/timer.rs b/src/utils/timer.rs new file mode 100644 index 00000000..a0041ac0 --- /dev/null +++ b/src/utils/timer.rs @@ -0,0 +1,65 @@ +use { + crate::{ + io_uring::{IoUring, IoUringError}, + utils::oserror::OsError, + }, + std::{rc::Rc, time::Duration}, + thiserror::Error, + uapi::{c, OwnedFd}, +}; + +#[derive(Debug, Error)] +pub enum TimerError { + #[error("Could not create a timer")] + CreateTimer(#[source] OsError), + #[error("Could not read from a timer")] + TimerReadError(#[source] OsError), + #[error("Could not set a timer")] + SetTimer(#[source] OsError), + #[error("The io-uring returned an error")] + IoUringError(#[from] IoUringError), +} + +#[derive(Clone)] +pub struct TimerFd { + fd: Rc, +} + +impl TimerFd { + pub fn new(clock_id: c::c_int) -> Result { + let fd = match uapi::timerfd_create(clock_id, c::TFD_CLOEXEC | c::TFD_NONBLOCK) { + Ok(fd) => Rc::new(fd), + Err(e) => return Err(TimerError::CreateTimer(e.into())), + }; + Ok(Self { fd }) + } + + pub async fn expired(&self, ring: &IoUring) -> Result { + ring.readable(&self.fd).await?; + let mut buf = 0u64; + if let Err(e) = uapi::read(self.fd.raw(), &mut buf) { + return Err(TimerError::TimerReadError(e.into())); + } + Ok(buf) + } + + pub fn program( + &self, + initial: Option, + periodic: Option, + ) -> Result<(), TimerError> { + let mut timerspec: c::itimerspec = uapi::pod_zeroed(); + if let Some(init) = initial { + timerspec.it_value.tv_sec = init.as_secs() as _; + timerspec.it_value.tv_nsec = init.subsec_nanos() as _; + if let Some(per) = periodic { + timerspec.it_interval.tv_sec = per.as_secs() as _; + timerspec.it_interval.tv_nsec = per.subsec_nanos() as _; + } + } + if let Err(e) = uapi::timerfd_settime(self.fd.raw(), 0, &timerspec) { + return Err(TimerError::SetTimer(e.into())); + } + Ok(()) + } +}