1
0
Fork 0
forked from wry/wry

async: move timer out of async engine

This commit is contained in:
Julian Orth 2022-05-12 20:48:29 +02:00
parent dcdd91c0b0
commit 4d8a340cd0
6 changed files with 86 additions and 76 deletions

View file

@ -1,19 +1,17 @@
mod ae_fd; mod ae_fd;
mod ae_queue; mod ae_queue;
mod ae_task; mod ae_task;
mod ae_timer;
mod ae_yield; mod ae_yield;
pub use { pub use {
crate::async_engine::ae_yield::Yield, crate::async_engine::ae_yield::Yield,
ae_fd::{AsyncFd, FdStatus}, ae_fd::{AsyncFd, FdStatus},
ae_task::SpawnedFuture, ae_task::SpawnedFuture,
ae_timer::Timer,
}; };
use { use {
crate::{ crate::{
event_loop::{EventLoop, EventLoopError}, event_loop::{EventLoop, EventLoopError},
utils::{copyhashmap::CopyHashMap, numcell::NumCell, oserror::OsError}, utils::{copyhashmap::CopyHashMap, numcell::NumCell},
}, },
ae_fd::AsyncFdData, ae_fd::AsyncFdData,
ae_queue::{DispatchQueue, Dispatcher}, ae_queue::{DispatchQueue, Dispatcher},
@ -23,19 +21,13 @@ use {
rc::Rc, rc::Rc,
}, },
thiserror::Error, thiserror::Error,
uapi::{c, OwnedFd}, uapi::OwnedFd,
}; };
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum AsyncError { pub enum AsyncError {
#[error("The event loop caused an error")] #[error("The event loop caused an error")]
EventLoopError(#[from] EventLoopError), 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)] #[derive(Copy, Clone, Eq, PartialEq)]
@ -63,10 +55,6 @@ impl AsyncEngine {
})) }))
} }
pub fn timer(self: &Rc<Self>, clock_id: c::c_int) -> Result<Timer, AsyncError> {
Timer::new(self, clock_id)
}
pub fn clear(&self) { pub fn clear(&self) {
for (_, fd) in self.fds.lock().drain() { for (_, fd) in self.fds.lock().drain() {
fd.readers.take(); fd.readers.take();

View file

@ -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<AsyncEngine>, clock_id: c::c_int) -> Result<Self, AsyncError> {
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<u64, AsyncError> {
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<Duration>,
periodic: Option<Duration>,
) -> 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(())
}
}

View file

@ -1,6 +1,6 @@
use { use {
crate::{ crate::{
async_engine::{AsyncError, SpawnedFuture, Timer}, async_engine::SpawnedFuture,
backend::{ backend::{
self, ConnectorId, DrmDeviceId, InputDeviceAccelProfile, InputDeviceCapability, self, ConnectorId, DrmDeviceId, InputDeviceAccelProfile, InputDeviceCapability,
InputDeviceId, InputDeviceId,
@ -11,8 +11,12 @@ use {
state::{ConnectorData, DeviceHandlerData, DrmDevData, OutputData, State}, state::{ConnectorData, DeviceHandlerData, DrmDevData, OutputData, State},
tree::{ContainerNode, ContainerSplit, FloatNode, Node, NodeVisitorBase}, tree::{ContainerNode, ContainerSplit, FloatNode, Node, NodeVisitorBase},
utils::{ utils::{
copyhashmap::CopyHashMap, debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell, copyhashmap::CopyHashMap,
debug_fn::debug_fn,
errorfmt::ErrorFmt,
numcell::NumCell,
stack::Stack, stack::Stack,
timer::{TimerError, TimerFd},
}, },
xkbcommon::{XkbCommonError, XkbKeymap}, xkbcommon::{XkbCommonError, XkbKeymap},
}, },
@ -63,7 +67,7 @@ pub(super) struct ConfigProxyHandler {
} }
pub(super) struct TimerData { pub(super) struct TimerData {
timer: Timer, timer: TimerFd,
id: u64, id: u64,
name: Rc<String>, name: Rc<String>,
_handler: SpawnedFuture<()>, _handler: SpawnedFuture<()>,
@ -288,13 +292,13 @@ impl ConfigProxyHandler {
return Ok(()); return Ok(());
} }
let id = self.timer_ids.fetch_add(1); 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 handler = {
let timer = timer.clone(); let timer = timer.clone();
let slf = self.clone(); let slf = self.clone();
self.state.eng.spawn(async move { self.state.eng.spawn(async move {
loop { loop {
match timer.expired().await { match timer.expired(&slf.state.ring).await {
Ok(_) => slf.send(&ServerMessage::TimerExpired { Ok(_) => slf.send(&ServerMessage::TimerExpired {
timer: jay_config::Timer(id), timer: jay_config::Timer(id),
}), }),
@ -1067,7 +1071,7 @@ enum CphError {
#[error("Could not process a `{0}` request")] #[error("Could not process a `{0}` request")]
FailedRequest(&'static str, #[source] Box<Self>), FailedRequest(&'static str, #[source] Box<Self>),
#[error(transparent)] #[error(transparent)]
AsyncError(#[from] AsyncError), TimerError(#[from] TimerError),
} }
trait WithRequestName { trait WithRequestName {

View file

@ -1,9 +1,11 @@
use { use {
crate::{ crate::{
async_engine::{AsyncError, Timer},
backend::Backend, backend::Backend,
state::State, state::State,
utils::errorfmt::ErrorFmt, utils::{
errorfmt::ErrorFmt,
timer::{TimerError, TimerFd},
},
}, },
futures_util::{select, FutureExt}, futures_util::{select, FutureExt},
std::{rc::Rc, time::Duration}, std::{rc::Rc, time::Duration},
@ -14,7 +16,7 @@ pub async fn idle(state: Rc<State>, backend: Rc<dyn Backend>) {
if !backend.supports_idle() { if !backend.supports_idle() {
return; return;
} }
let timer = match state.eng.timer(c::CLOCK_MONOTONIC) { let timer = match TimerFd::new(c::CLOCK_MONOTONIC) {
Ok(t) => t, Ok(t) => t,
Err(e) => { Err(e) => {
log::error!("Could not create idle timer: {}", ErrorFmt(e)); log::error!("Could not create idle timer: {}", ErrorFmt(e));
@ -38,7 +40,7 @@ pub async fn idle(state: Rc<State>, backend: Rc<dyn Backend>) {
struct Idle { struct Idle {
state: Rc<State>, state: Rc<State>,
backend: Rc<dyn Backend>, backend: Rc<dyn Backend>,
timer: Timer, timer: TimerFd,
idle: bool, idle: bool,
dead: bool, dead: bool,
is_inhibited: bool, is_inhibited: bool,
@ -49,14 +51,14 @@ impl Idle {
async fn run(&mut self) { async fn run(&mut self) {
while !self.dead { while !self.dead {
select! { 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(), _ = self.state.idle.change.triggered().fuse() => self.handle_idle_changes(),
} }
} }
log::error!("Due to the above error, monitors will no longer be (de)activated.") log::error!("Due to the above error, monitors will no longer be (de)activated.")
} }
fn handle_expired(&mut self, res: Result<u64, AsyncError>) { fn handle_expired(&mut self, res: Result<u64, TimerError>) {
if let Err(e) = res { if let Err(e) = res {
log::error!("Could not wait for idle timer to expire: {}", ErrorFmt(e)); log::error!("Could not wait for idle timer to expire: {}", ErrorFmt(e));
self.dead = true; self.dead = true;

View file

@ -26,6 +26,7 @@ pub mod scroller;
pub mod smallmap; pub mod smallmap;
pub mod stack; pub mod stack;
pub mod syncqueue; pub mod syncqueue;
pub mod timer;
pub mod tri; pub mod tri;
pub mod trim; pub mod trim;
pub mod unlink_on_drop; pub mod unlink_on_drop;

65
src/utils/timer.rs Normal file
View file

@ -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<OwnedFd>,
}
impl TimerFd {
pub fn new(clock_id: c::c_int) -> Result<Self, TimerError> {
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<u64, TimerError> {
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<Duration>,
periodic: Option<Duration>,
) -> 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(())
}
}