async: move timer out of async engine
This commit is contained in:
parent
dcdd91c0b0
commit
4d8a340cd0
6 changed files with 86 additions and 76 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
65
src/utils/timer.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue