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_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<Self>, clock_id: c::c_int) -> Result<Timer, AsyncError> {
Timer::new(self, clock_id)
}
pub fn clear(&self) {
for (_, fd) in self.fds.lock().drain() {
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 {
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<String>,
_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<Self>),
#[error(transparent)]
AsyncError(#[from] AsyncError),
TimerError(#[from] TimerError),
}
trait WithRequestName {

View file

@ -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<State>, backend: Rc<dyn Backend>) {
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<State>, backend: Rc<dyn Backend>) {
struct Idle {
state: Rc<State>,
backend: Rc<dyn Backend>,
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<u64, AsyncError>) {
fn handle_expired(&mut self, res: Result<u64, TimerError>) {
if let Err(e) = res {
log::error!("Could not wait for idle timer to expire: {}", ErrorFmt(e));
self.dead = true;

View file

@ -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;

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(())
}
}