runtime: replace epoll by io-uring
This commit is contained in:
parent
98cc85e2d3
commit
9416efeabe
21 changed files with 173 additions and 742 deletions
|
|
@ -1,7 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::SpawnedFuture,
|
async_engine::SpawnedFuture,
|
||||||
event_loop::EventLoopError,
|
|
||||||
state::State,
|
state::State,
|
||||||
utils::{errorfmt::ErrorFmt, oserror::OsError, xrd::xrd},
|
utils::{errorfmt::ErrorFmt, oserror::OsError, xrd::xrd},
|
||||||
},
|
},
|
||||||
|
|
@ -30,8 +29,6 @@ pub enum AcceptorError {
|
||||||
BindFailed(#[source] OsError),
|
BindFailed(#[source] OsError),
|
||||||
#[error("All wayland addresses in the range 0..1000 are already in use")]
|
#[error("All wayland addresses in the range 0..1000 are already in use")]
|
||||||
AddressesInUse,
|
AddressesInUse,
|
||||||
#[error("The event loop caused an error")]
|
|
||||||
EventLoopError(#[from] EventLoopError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Acceptor {
|
pub struct Acceptor {
|
||||||
|
|
@ -205,5 +202,5 @@ async fn accept(fd: Rc<OwnedFd>, state: Rc<State>, secure: bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.el.stop();
|
state.ring.stop();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,15 @@
|
||||||
mod ae_fd;
|
|
||||||
mod ae_queue;
|
|
||||||
mod ae_task;
|
mod ae_task;
|
||||||
mod ae_yield;
|
mod ae_yield;
|
||||||
|
|
||||||
pub use {
|
pub use {crate::async_engine::ae_yield::Yield, ae_task::SpawnedFuture};
|
||||||
crate::async_engine::ae_yield::Yield,
|
|
||||||
ae_fd::{AsyncFd, FdStatus},
|
|
||||||
ae_task::SpawnedFuture,
|
|
||||||
};
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
event_loop::{EventLoop, EventLoopError},
|
async_engine::ae_task::Runnable,
|
||||||
utils::{copyhashmap::CopyHashMap, numcell::NumCell},
|
utils::{array, numcell::NumCell, syncqueue::SyncQueue},
|
||||||
},
|
},
|
||||||
ae_fd::AsyncFdData,
|
std::{cell::RefCell, collections::VecDeque, future::Future, rc::Rc, task::Waker},
|
||||||
ae_queue::{DispatchQueue, Dispatcher},
|
|
||||||
std::{
|
|
||||||
cell::{Cell, RefCell},
|
|
||||||
future::Future,
|
|
||||||
rc::Rc,
|
|
||||||
},
|
|
||||||
thiserror::Error,
|
|
||||||
uapi::OwnedFd,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum AsyncError {
|
|
||||||
#[error("The event loop caused an error")]
|
|
||||||
EventLoopError(#[from] EventLoopError),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
pub enum Phase {
|
pub enum Phase {
|
||||||
EventHandling,
|
EventHandling,
|
||||||
|
|
@ -40,70 +20,88 @@ pub enum Phase {
|
||||||
const NUM_PHASES: usize = 4;
|
const NUM_PHASES: usize = 4;
|
||||||
|
|
||||||
pub struct AsyncEngine {
|
pub struct AsyncEngine {
|
||||||
el: Rc<EventLoop>,
|
num_queued: NumCell<usize>,
|
||||||
queue: Rc<DispatchQueue>,
|
queues: [SyncQueue<Runnable>; NUM_PHASES],
|
||||||
fds: CopyHashMap<i32, Rc<AsyncFdData>>,
|
iteration: NumCell<u64>,
|
||||||
|
yields: SyncQueue<Waker>,
|
||||||
|
stash: RefCell<VecDeque<Runnable>>,
|
||||||
|
yield_stash: RefCell<VecDeque<Waker>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncEngine {
|
impl AsyncEngine {
|
||||||
pub fn install(el: &Rc<EventLoop>) -> Result<Rc<Self>, AsyncError> {
|
pub fn new() -> Rc<Self> {
|
||||||
let queue = Dispatcher::install(el)?;
|
Rc::new(Self {
|
||||||
Ok(Rc::new(Self {
|
num_queued: Default::default(),
|
||||||
el: el.clone(),
|
queues: array::from_fn(|_| Default::default()),
|
||||||
queue,
|
iteration: Default::default(),
|
||||||
fds: CopyHashMap::new(),
|
yields: Default::default(),
|
||||||
}))
|
stash: Default::default(),
|
||||||
}
|
yield_stash: Default::default(),
|
||||||
|
|
||||||
pub fn clear(&self) {
|
|
||||||
for (_, fd) in self.fds.lock().drain() {
|
|
||||||
fd.readers.take();
|
|
||||||
fd.writers.take();
|
|
||||||
}
|
|
||||||
self.queue.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spawn<T, F: Future<Output = T> + 'static>(&self, f: F) -> SpawnedFuture<T> {
|
|
||||||
self.queue.spawn(Phase::EventHandling, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spawn2<T, F: Future<Output = T> + 'static>(
|
|
||||||
&self,
|
|
||||||
phase: Phase,
|
|
||||||
f: F,
|
|
||||||
) -> SpawnedFuture<T> {
|
|
||||||
self.queue.spawn(phase, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fd(self: &Rc<Self>, fd: &Rc<OwnedFd>) -> Result<AsyncFd, AsyncError> {
|
|
||||||
let data = if let Some(afd) = self.fds.get(&fd.raw()) {
|
|
||||||
afd.ref_count.fetch_add(1);
|
|
||||||
afd
|
|
||||||
} else {
|
|
||||||
let id = self.el.id();
|
|
||||||
let afd = Rc::new(AsyncFdData {
|
|
||||||
ref_count: NumCell::new(1),
|
|
||||||
fd: fd.clone(),
|
|
||||||
id,
|
|
||||||
el: self.el.clone(),
|
|
||||||
write_registered: Cell::new(false),
|
|
||||||
read_registered: Cell::new(false),
|
|
||||||
readers: RefCell::new(vec![]),
|
|
||||||
writers: RefCell::new(vec![]),
|
|
||||||
});
|
|
||||||
self.el.insert(id, Some(fd.raw()), 0, afd.clone())?;
|
|
||||||
afd
|
|
||||||
};
|
|
||||||
Ok(AsyncFd {
|
|
||||||
engine: self.clone(),
|
|
||||||
data,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn yield_now(&self) -> Yield {
|
pub fn clear(&self) {
|
||||||
Yield {
|
self.stash.borrow_mut().clear();
|
||||||
iteration: self.queue.iteration(),
|
self.yield_stash.borrow_mut().clear();
|
||||||
queue: self.queue.clone(),
|
self.yields.take();
|
||||||
|
for queue in &self.queues {
|
||||||
|
queue.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn spawn<T, F: Future<Output = T> + 'static>(self: &Rc<Self>, f: F) -> SpawnedFuture<T> {
|
||||||
|
self.spawn_(Phase::EventHandling, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn2<T, F: Future<Output = T> + 'static>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
phase: Phase,
|
||||||
|
f: F,
|
||||||
|
) -> SpawnedFuture<T> {
|
||||||
|
self.spawn_(phase, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn yield_now(self: &Rc<Self>) -> Yield {
|
||||||
|
Yield {
|
||||||
|
iteration: self.iteration(),
|
||||||
|
queue: self.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dispatch(&self) {
|
||||||
|
let mut stash = self.stash.borrow_mut();
|
||||||
|
let mut yield_stash = self.yield_stash.borrow_mut();
|
||||||
|
while self.num_queued.get() > 0 {
|
||||||
|
self.iteration.fetch_add(1);
|
||||||
|
let mut phase = 0;
|
||||||
|
while phase < NUM_PHASES as usize {
|
||||||
|
self.queues[phase].swap(&mut *stash);
|
||||||
|
if stash.is_empty() {
|
||||||
|
phase += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
self.num_queued.fetch_sub(stash.len());
|
||||||
|
for runnable in stash.drain(..) {
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.yields.swap(&mut *yield_stash);
|
||||||
|
for waker in yield_stash.drain(..) {
|
||||||
|
waker.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&self, runnable: Runnable, phase: Phase) {
|
||||||
|
self.queues[phase as usize].push(runnable);
|
||||||
|
self.num_queued.fetch_add(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_yield(&self, waker: Waker) {
|
||||||
|
self.yields.push(waker);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn iteration(&self) -> u64 {
|
||||||
|
self.iteration.get()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,196 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
async_engine::{AsyncEngine, AsyncError},
|
|
||||||
event_loop::{EventLoop, EventLoopDispatcher, EventLoopError, EventLoopId},
|
|
||||||
utils::numcell::NumCell,
|
|
||||||
},
|
|
||||||
std::{
|
|
||||||
cell::{Cell, RefCell},
|
|
||||||
error::Error,
|
|
||||||
fmt::{Debug, Formatter},
|
|
||||||
future::Future,
|
|
||||||
pin::Pin,
|
|
||||||
rc::Rc,
|
|
||||||
task::{Context, Poll, Waker},
|
|
||||||
},
|
|
||||||
uapi::{c, OwnedFd},
|
|
||||||
};
|
|
||||||
|
|
||||||
type Queue = RefCell<Vec<(Waker, Rc<Cell<Option<FdStatus>>>)>>;
|
|
||||||
|
|
||||||
pub(super) struct AsyncFdData {
|
|
||||||
pub(super) ref_count: NumCell<u64>,
|
|
||||||
pub(super) fd: Rc<OwnedFd>,
|
|
||||||
pub(super) id: EventLoopId,
|
|
||||||
pub(super) el: Rc<EventLoop>,
|
|
||||||
pub(super) write_registered: Cell<bool>,
|
|
||||||
pub(super) read_registered: Cell<bool>,
|
|
||||||
pub(super) readers: Queue,
|
|
||||||
pub(super) writers: Queue,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsyncFdData {
|
|
||||||
fn update_interests(&self) -> Result<(), EventLoopError> {
|
|
||||||
let mut events = 0;
|
|
||||||
if self.write_registered.get() {
|
|
||||||
events |= c::EPOLLOUT;
|
|
||||||
}
|
|
||||||
if self.read_registered.get() {
|
|
||||||
events |= c::EPOLLIN;
|
|
||||||
}
|
|
||||||
let res = self.el.modify(self.id, events);
|
|
||||||
if res.is_err() {
|
|
||||||
if let Err(e) = self.el.remove(self.id) {
|
|
||||||
log::error!(
|
|
||||||
"Fatal error: Cannot remove file descriptor from event loop: {:?}",
|
|
||||||
e
|
|
||||||
);
|
|
||||||
self.el.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll(
|
|
||||||
&self,
|
|
||||||
woken: &Rc<Cell<Option<FdStatus>>>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
registered: impl Fn(&AsyncFdData) -> &Cell<bool>,
|
|
||||||
queue: impl Fn(&AsyncFdData) -> &Queue,
|
|
||||||
) -> Poll<Result<FdStatus, AsyncError>> {
|
|
||||||
if let Some(status) = woken.get() {
|
|
||||||
return Poll::Ready(Ok(status));
|
|
||||||
}
|
|
||||||
if !registered(self).get() {
|
|
||||||
registered(self).set(true);
|
|
||||||
if let Err(e) = self.update_interests() {
|
|
||||||
return Poll::Ready(Err(AsyncError::EventLoopError(e)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queue(self)
|
|
||||||
.borrow_mut()
|
|
||||||
.push((cx.waker().clone(), woken.clone()));
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EventLoopDispatcher for AsyncFdData {
|
|
||||||
fn dispatch(self: Rc<Self>, _fd: Option<i32>, events: i32) -> Result<(), Box<dyn Error>> {
|
|
||||||
let mut status = FdStatus::Ok;
|
|
||||||
if events & (c::EPOLLERR | c::EPOLLHUP) != 0 {
|
|
||||||
status = FdStatus::Err;
|
|
||||||
if let Err(e) = self.el.remove(self.id) {
|
|
||||||
return Err(Box::new(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut woke_any = false;
|
|
||||||
if events & c::EPOLLIN != 0 || status == FdStatus::Err {
|
|
||||||
let mut readers = self.readers.borrow_mut();
|
|
||||||
woke_any |= !readers.is_empty();
|
|
||||||
for (waker, woken) in readers.drain(..) {
|
|
||||||
woken.set(Some(status));
|
|
||||||
waker.wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if events & c::EPOLLOUT != 0 || status == FdStatus::Err {
|
|
||||||
let mut writers = self.writers.borrow_mut();
|
|
||||||
woke_any |= !writers.is_empty();
|
|
||||||
for (waker, woken) in writers.drain(..) {
|
|
||||||
woken.set(Some(status));
|
|
||||||
waker.wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !woke_any && status == FdStatus::Ok {
|
|
||||||
self.read_registered.set(false);
|
|
||||||
self.write_registered.set(false);
|
|
||||||
if let Err(e) = self.update_interests() {
|
|
||||||
return Err(Box::new(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AsyncFd {
|
|
||||||
pub(super) engine: Rc<AsyncEngine>,
|
|
||||||
pub(super) data: Rc<AsyncFdData>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for AsyncFd {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.debug_struct("AsyncFd").finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for AsyncFd {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
self.data.ref_count.fetch_add(1);
|
|
||||||
Self {
|
|
||||||
engine: self.engine.clone(),
|
|
||||||
data: self.data.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for AsyncFd {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if self.data.ref_count.fetch_sub(1) == 1 {
|
|
||||||
self.engine.fds.remove(&self.data.fd.raw());
|
|
||||||
let _ = self.data.el.remove(self.data.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsyncFd {
|
|
||||||
pub fn raw(&self) -> i32 {
|
|
||||||
self.data.fd.raw()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn readable(&self) -> AsyncFdReadable {
|
|
||||||
AsyncFdReadable {
|
|
||||||
fd: self,
|
|
||||||
woken: Rc::new(Cell::new(None)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn writable(&self) -> AsyncFdWritable {
|
|
||||||
AsyncFdWritable {
|
|
||||||
fd: self,
|
|
||||||
woken: Rc::new(Cell::new(None)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub enum FdStatus {
|
|
||||||
Ok,
|
|
||||||
Err,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AsyncFdReadable<'a> {
|
|
||||||
fd: &'a AsyncFd,
|
|
||||||
woken: Rc<Cell<Option<FdStatus>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Future for AsyncFdReadable<'a> {
|
|
||||||
type Output = Result<FdStatus, AsyncError>;
|
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
||||||
let data = &self.fd.data;
|
|
||||||
data.poll(&self.woken, cx, |d| &d.read_registered, |d| &d.readers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AsyncFdWritable<'a> {
|
|
||||||
fd: &'a AsyncFd,
|
|
||||||
woken: Rc<Cell<Option<FdStatus>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Future for AsyncFdWritable<'a> {
|
|
||||||
type Output = Result<FdStatus, AsyncError>;
|
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
||||||
let data = &self.fd.data;
|
|
||||||
data.poll(&self.woken, cx, |d| &d.write_registered, |d| &d.writers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,115 +0,0 @@
|
||||||
use {
|
|
||||||
crate::{
|
|
||||||
async_engine::{ae_task::Runnable, AsyncError, Phase, NUM_PHASES},
|
|
||||||
event_loop::{EventLoop, EventLoopDispatcher, EventLoopId},
|
|
||||||
utils::{array, numcell::NumCell, syncqueue::SyncQueue},
|
|
||||||
},
|
|
||||||
std::{
|
|
||||||
cell::{Cell, RefCell},
|
|
||||||
collections::VecDeque,
|
|
||||||
error::Error,
|
|
||||||
rc::Rc,
|
|
||||||
task::Waker,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub(super) struct Dispatcher {
|
|
||||||
queue: Rc<DispatchQueue>,
|
|
||||||
stash: RefCell<VecDeque<Runnable>>,
|
|
||||||
yield_stash: RefCell<VecDeque<Waker>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatcher {
|
|
||||||
pub fn install(el: &Rc<EventLoop>) -> Result<Rc<DispatchQueue>, AsyncError> {
|
|
||||||
let id = el.id();
|
|
||||||
let queue = Rc::new(DispatchQueue {
|
|
||||||
id,
|
|
||||||
el: el.clone(),
|
|
||||||
dispatch_scheduled: Cell::new(false),
|
|
||||||
num_queued: Default::default(),
|
|
||||||
queues: array::from_fn(|_| Default::default()),
|
|
||||||
iteration: Default::default(),
|
|
||||||
yields: Default::default(),
|
|
||||||
});
|
|
||||||
let slf = Rc::new(Dispatcher {
|
|
||||||
queue: queue.clone(),
|
|
||||||
stash: Default::default(),
|
|
||||||
yield_stash: Default::default(),
|
|
||||||
});
|
|
||||||
el.insert(id, None, 0, slf)?;
|
|
||||||
Ok(queue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EventLoopDispatcher for Dispatcher {
|
|
||||||
fn dispatch(self: Rc<Self>, _fd: Option<i32>, _events: i32) -> Result<(), Box<dyn Error>> {
|
|
||||||
let mut stash = self.stash.borrow_mut();
|
|
||||||
let mut yield_stash = self.yield_stash.borrow_mut();
|
|
||||||
while self.queue.num_queued.get() > 0 {
|
|
||||||
self.queue.iteration.fetch_add(1);
|
|
||||||
let mut phase = 0;
|
|
||||||
while phase < NUM_PHASES as usize {
|
|
||||||
self.queue.queues[phase].swap(&mut *stash);
|
|
||||||
if stash.is_empty() {
|
|
||||||
phase += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
self.queue.num_queued.fetch_sub(stash.len());
|
|
||||||
for runnable in stash.drain(..) {
|
|
||||||
runnable.run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.queue.yields.swap(&mut *yield_stash);
|
|
||||||
for waker in yield_stash.drain(..) {
|
|
||||||
waker.wake();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.queue.dispatch_scheduled.set(false);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Dispatcher {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let _ = self.queue.el.remove(self.queue.id);
|
|
||||||
for queue in &self.queue.queues {
|
|
||||||
queue.swap(&mut VecDeque::new());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) struct DispatchQueue {
|
|
||||||
dispatch_scheduled: Cell<bool>,
|
|
||||||
id: EventLoopId,
|
|
||||||
el: Rc<EventLoop>,
|
|
||||||
num_queued: NumCell<usize>,
|
|
||||||
queues: [SyncQueue<Runnable>; NUM_PHASES],
|
|
||||||
iteration: NumCell<u64>,
|
|
||||||
yields: SyncQueue<Waker>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DispatchQueue {
|
|
||||||
pub fn clear(&self) {
|
|
||||||
self.yields.take();
|
|
||||||
for queue in &self.queues {
|
|
||||||
queue.take();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&self, runnable: Runnable, phase: Phase) {
|
|
||||||
self.queues[phase as usize].push(runnable);
|
|
||||||
self.num_queued.fetch_add(1);
|
|
||||||
if !self.dispatch_scheduled.get() {
|
|
||||||
let _ = self.el.schedule(self.id);
|
|
||||||
self.dispatch_scheduled.set(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_yield(&self, waker: Waker) {
|
|
||||||
self.yields.push(waker);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iteration(&self) -> u64 {
|
|
||||||
self.iteration.get()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{ae_queue::DispatchQueue, Phase},
|
async_engine::{AsyncEngine, Phase},
|
||||||
utils::{
|
utils::{
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
ptr_ext::{MutPtrExt, PtrExt},
|
ptr_ext::{MutPtrExt, PtrExt},
|
||||||
|
|
@ -94,7 +94,7 @@ struct Task<T, F: Future<Output = T>> {
|
||||||
state: NumCell<u32>,
|
state: NumCell<u32>,
|
||||||
data: UnsafeCell<TaskData<T, F>>,
|
data: UnsafeCell<TaskData<T, F>>,
|
||||||
waker: Cell<Option<Waker>>,
|
waker: Cell<Option<Waker>>,
|
||||||
queue: Rc<DispatchQueue>,
|
queue: Rc<AsyncEngine>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct Runnable {
|
pub(super) struct Runnable {
|
||||||
|
|
@ -119,8 +119,8 @@ impl Drop for Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DispatchQueue {
|
impl AsyncEngine {
|
||||||
pub(super) fn spawn<T, F: Future<Output = T>>(
|
pub(super) fn spawn_<T, F: Future<Output = T>>(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
phase: Phase,
|
phase: Phase,
|
||||||
f: F,
|
f: F,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::async_engine::ae_queue::DispatchQueue,
|
crate::async_engine::AsyncEngine,
|
||||||
std::{
|
std::{
|
||||||
future::Future,
|
future::Future,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
|
|
@ -10,7 +10,7 @@ use {
|
||||||
|
|
||||||
pub struct Yield {
|
pub struct Yield {
|
||||||
pub(super) iteration: u64,
|
pub(super) iteration: u64,
|
||||||
pub(super) queue: Rc<DispatchQueue>,
|
pub(super) queue: Rc<AsyncEngine>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for Yield {
|
impl Future for Yield {
|
||||||
|
|
|
||||||
|
|
@ -289,7 +289,7 @@ impl XBackend {
|
||||||
"Fatal error: Could not handle an event from the X server: {}",
|
"Fatal error: Could not handle an event from the X server: {}",
|
||||||
ErrorFmt(e)
|
ErrorFmt(e)
|
||||||
);
|
);
|
||||||
self.state.el.stop();
|
self.state.ring.stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -851,7 +851,7 @@ impl XBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_destroy(&self, event: &Event) -> Result<(), XBackendError> {
|
fn handle_destroy(&self, event: &Event) -> Result<(), XBackendError> {
|
||||||
self.state.el.stop();
|
self.state.ring.stop();
|
||||||
let event: DestroyNotify = event.parse()?;
|
let event: DestroyNotify = event.parse()?;
|
||||||
let output = match self.outputs.remove(&event.event) {
|
let output = match self.outputs.remove(&event.event) {
|
||||||
Some(o) => o,
|
Some(o) => o,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::AsyncError,
|
|
||||||
client::ClientId,
|
client::ClientId,
|
||||||
object::{Interface, ObjectId},
|
object::{Interface, ObjectId},
|
||||||
utils::buffd::{BufFdError, MsgParserError},
|
utils::buffd::{BufFdError, MsgParserError},
|
||||||
|
|
@ -12,8 +11,6 @@ use {
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ClientError {
|
pub enum ClientError {
|
||||||
#[error("An error occurred in the async engine")]
|
|
||||||
Async(#[from] AsyncError),
|
|
||||||
#[error("An error occurred reading from/writing to the client")]
|
#[error("An error occurred reading from/writing to the client")]
|
||||||
Io(#[from] BufFdError),
|
Io(#[from] BufFdError),
|
||||||
#[error("An error occurred while processing a request")]
|
#[error("An error occurred while processing a request")]
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::it::test_backend::TestBackend;
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
acceptor::{Acceptor, AcceptorError},
|
acceptor::{Acceptor, AcceptorError},
|
||||||
async_engine::{AsyncEngine, AsyncError, Phase, SpawnedFuture},
|
async_engine::{AsyncEngine, Phase, SpawnedFuture},
|
||||||
backend::{self, Backend},
|
backend::{self, Backend},
|
||||||
backends::{
|
backends::{
|
||||||
dummy::{DummyBackend, DummyOutput},
|
dummy::{DummyBackend, DummyOutput},
|
||||||
|
|
@ -14,7 +14,6 @@ use {
|
||||||
clientmem::{self, ClientMemError},
|
clientmem::{self, ClientMemError},
|
||||||
config::ConfigProxy,
|
config::ConfigProxy,
|
||||||
dbus::Dbus,
|
dbus::Dbus,
|
||||||
event_loop::{EventLoop, EventLoopError},
|
|
||||||
forker,
|
forker,
|
||||||
globals::Globals,
|
globals::Globals,
|
||||||
ifs::{wl_output::WlOutputGlobal, wl_surface::NoneSurfaceExt},
|
ifs::{wl_output::WlOutputGlobal, wl_surface::NoneSurfaceExt},
|
||||||
|
|
@ -76,16 +75,12 @@ fn create_forker() -> Rc<ForkerProxy> {
|
||||||
pub enum CompositorError {
|
pub enum CompositorError {
|
||||||
#[error("The client acceptor caused an error")]
|
#[error("The client acceptor caused an error")]
|
||||||
AcceptorError(#[from] AcceptorError),
|
AcceptorError(#[from] AcceptorError),
|
||||||
#[error("The event loop caused an error")]
|
|
||||||
EventLoopError(#[from] EventLoopError),
|
|
||||||
#[error("The signal handler caused an error")]
|
#[error("The signal handler caused an error")]
|
||||||
SighandError(#[from] SighandError),
|
SighandError(#[from] SighandError),
|
||||||
#[error("The clientmem subsystem caused an error")]
|
#[error("The clientmem subsystem caused an error")]
|
||||||
ClientmemError(#[from] ClientMemError),
|
ClientmemError(#[from] ClientMemError),
|
||||||
#[error("The timer subsystem caused an error")]
|
#[error("The timer subsystem caused an error")]
|
||||||
WheelError(#[from] WheelError),
|
WheelError(#[from] WheelError),
|
||||||
#[error("The async subsystem caused an error")]
|
|
||||||
AsyncError(#[from] AsyncError),
|
|
||||||
#[error("The render backend caused an error")]
|
#[error("The render backend caused an error")]
|
||||||
RenderError(#[from] RenderError),
|
RenderError(#[from] RenderError),
|
||||||
#[error("Could not create an io-uring")]
|
#[error("Could not create an io-uring")]
|
||||||
|
|
@ -114,12 +109,11 @@ fn start_compositor2(
|
||||||
leaks::init();
|
leaks::init();
|
||||||
render::init()?;
|
render::init()?;
|
||||||
clientmem::init()?;
|
clientmem::init()?;
|
||||||
let el = EventLoop::new()?;
|
|
||||||
let xkb_ctx = XkbContext::new().unwrap();
|
let xkb_ctx = XkbContext::new().unwrap();
|
||||||
let xkb_keymap = xkb_ctx.keymap_from_str(include_str!("keymap.xkb")).unwrap();
|
let xkb_keymap = xkb_ctx.keymap_from_str(include_str!("keymap.xkb")).unwrap();
|
||||||
let engine = AsyncEngine::install(&el)?;
|
let engine = AsyncEngine::new();
|
||||||
let ring = IoUring::new(&engine, 32)?;
|
let ring = IoUring::new(&engine, 32)?;
|
||||||
let _signal_future = sighand::install(&el, &engine, &ring)?;
|
let _signal_future = sighand::install(&engine, &ring)?;
|
||||||
let wheel = Wheel::new(&engine, &ring)?;
|
let wheel = Wheel::new(&engine, &ring)?;
|
||||||
let (_run_toplevel_future, run_toplevel) = RunToplevel::install(&engine);
|
let (_run_toplevel_future, run_toplevel) = RunToplevel::install(&engine);
|
||||||
let node_ids = NodeIds::default();
|
let node_ids = NodeIds::default();
|
||||||
|
|
@ -129,7 +123,6 @@ fn start_compositor2(
|
||||||
forker: Default::default(),
|
forker: Default::default(),
|
||||||
default_keymap: xkb_keymap,
|
default_keymap: xkb_keymap,
|
||||||
eng: engine.clone(),
|
eng: engine.clone(),
|
||||||
el: el.clone(),
|
|
||||||
render_ctx: Default::default(),
|
render_ctx: Default::default(),
|
||||||
render_ctx_version: NumCell::new(1),
|
render_ctx_version: NumCell::new(1),
|
||||||
render_ctx_ever_initialized: Cell::new(false),
|
render_ctx_ever_initialized: Cell::new(false),
|
||||||
|
|
@ -186,7 +179,7 @@ fn start_compositor2(
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
data_offer_ids: Default::default(),
|
data_offer_ids: Default::default(),
|
||||||
drm_dev_ids: Default::default(),
|
drm_dev_ids: Default::default(),
|
||||||
ring,
|
ring: ring.clone(),
|
||||||
});
|
});
|
||||||
state.tracker.register(ClientId::from_raw(0));
|
state.tracker.register(ClientId::from_raw(0));
|
||||||
create_dummy_output(&state);
|
create_dummy_output(&state);
|
||||||
|
|
@ -200,7 +193,7 @@ fn start_compositor2(
|
||||||
forker.setenv(key.as_bytes(), val.as_bytes());
|
forker.setenv(key.as_bytes(), val.as_bytes());
|
||||||
}
|
}
|
||||||
let compositor = engine.spawn(start_compositor3(state.clone(), test_future));
|
let compositor = engine.spawn(start_compositor3(state.clone(), test_future));
|
||||||
el.run()?;
|
ring.run()?;
|
||||||
drop(compositor);
|
drop(compositor);
|
||||||
drop(acceptor_future);
|
drop(acceptor_future);
|
||||||
drop(acceptor);
|
drop(acceptor);
|
||||||
|
|
@ -222,7 +215,7 @@ async fn start_compositor3(state: Rc<State>, test_future: Option<TestFuture>) {
|
||||||
Some(b) => b,
|
Some(b) => b,
|
||||||
_ => {
|
_ => {
|
||||||
log::error!("Could not create a backend");
|
log::error!("Could not create a backend");
|
||||||
state.el.stop();
|
state.ring.stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -249,7 +242,7 @@ async fn start_compositor3(state: Rc<State>, test_future: Option<TestFuture>) {
|
||||||
Err(e) => log::error!("Backend failed: {}", ErrorFmt(e.deref())),
|
Err(e) => log::error!("Backend failed: {}", ErrorFmt(e.deref())),
|
||||||
_ => log::error!("Backend stopped without an error"),
|
_ => log::error!("Backend stopped without an error"),
|
||||||
}
|
}
|
||||||
state.el.stop();
|
state.ring.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_config(state: &Rc<State>, #[allow(unused_variables)] for_test: bool) -> ConfigProxy {
|
fn load_config(state: &Rc<State>, #[allow(unused_variables)] for_test: bool) -> ConfigProxy {
|
||||||
|
|
|
||||||
|
|
@ -768,7 +768,7 @@ impl ConfigProxyHandler {
|
||||||
|
|
||||||
fn handle_quit(&self) {
|
fn handle_quit(&self) {
|
||||||
log::info!("Quitting");
|
log::info!("Quitting");
|
||||||
self.state.el.stop();
|
self.state.ring.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_switch_to(&self, vtnr: u32) {
|
fn handle_switch_to(&self, vtnr: u32) {
|
||||||
|
|
|
||||||
|
|
@ -1,208 +0,0 @@
|
||||||
use {
|
|
||||||
crate::utils::{clonecell::UnsafeCellCloneSafe, copyhashmap::CopyHashMap, numcell::NumCell},
|
|
||||||
std::{
|
|
||||||
cell::{Cell, RefCell},
|
|
||||||
collections::VecDeque,
|
|
||||||
rc::Rc,
|
|
||||||
},
|
|
||||||
thiserror::Error,
|
|
||||||
uapi::{c, Errno, OwnedFd},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum EventLoopError {
|
|
||||||
#[error("Could not create an epoll fd: {0}")]
|
|
||||||
CreateFailed(crate::utils::oserror::OsError),
|
|
||||||
#[error("epoll_wait failed: {0}")]
|
|
||||||
WaitFailed(crate::utils::oserror::OsError),
|
|
||||||
#[error("A dispatcher returned a fatal error: {0}")]
|
|
||||||
DispatcherError(Box<dyn std::error::Error>),
|
|
||||||
#[error("Could not insert an fd to wait on: {0}")]
|
|
||||||
InsertFailed(crate::utils::oserror::OsError),
|
|
||||||
#[error("Could not modify an fd to wait on: {0}")]
|
|
||||||
ModifyFailed(crate::utils::oserror::OsError),
|
|
||||||
#[error("Could not remove an fd to wait on: {0}")]
|
|
||||||
RemoveFailed(crate::utils::oserror::OsError),
|
|
||||||
#[error("Entry is not registered")]
|
|
||||||
NoEntry,
|
|
||||||
#[error("Event loop is already destroyed")]
|
|
||||||
Destroyed,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
|
|
||||||
pub struct EventLoopId(u64);
|
|
||||||
|
|
||||||
pub trait EventLoopDispatcher {
|
|
||||||
fn dispatch(
|
|
||||||
self: Rc<Self>,
|
|
||||||
fd: Option<i32>,
|
|
||||||
events: i32,
|
|
||||||
) -> Result<(), Box<dyn std::error::Error>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct Entry {
|
|
||||||
fd: Option<i32>,
|
|
||||||
dispatcher: Rc<dyn EventLoopDispatcher>,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl UnsafeCellCloneSafe for Entry {}
|
|
||||||
|
|
||||||
pub struct EventLoop {
|
|
||||||
destroyed: Cell<bool>,
|
|
||||||
epoll: OwnedFd,
|
|
||||||
next_id: NumCell<u64>,
|
|
||||||
entries: CopyHashMap<u64, Entry>,
|
|
||||||
scheduled: RefCell<VecDeque<u64>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EventLoop {
|
|
||||||
pub fn new() -> Result<Rc<Self>, EventLoopError> {
|
|
||||||
let epoll = match uapi::epoll_create1(c::EPOLL_CLOEXEC) {
|
|
||||||
Ok(e) => e,
|
|
||||||
Err(e) => return Err(EventLoopError::CreateFailed(e.into())),
|
|
||||||
};
|
|
||||||
Ok(Rc::new(Self {
|
|
||||||
destroyed: Cell::new(false),
|
|
||||||
epoll,
|
|
||||||
next_id: NumCell::new(1),
|
|
||||||
entries: CopyHashMap::new(),
|
|
||||||
scheduled: RefCell::new(Default::default()),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_destroyed(&self) -> Result<(), EventLoopError> {
|
|
||||||
if self.destroyed.get() {
|
|
||||||
return Err(EventLoopError::Destroyed);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn id(&self) -> EventLoopId {
|
|
||||||
EventLoopId(self.next_id.fetch_add(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stop(&self) {
|
|
||||||
self.destroyed.set(true);
|
|
||||||
self.entries.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert(
|
|
||||||
&self,
|
|
||||||
id: EventLoopId,
|
|
||||||
fd: Option<i32>,
|
|
||||||
events: i32,
|
|
||||||
dispatcher: Rc<dyn EventLoopDispatcher>,
|
|
||||||
) -> Result<(), EventLoopError> {
|
|
||||||
self.check_destroyed()?;
|
|
||||||
let id = id.0;
|
|
||||||
if let Some(fd) = fd {
|
|
||||||
let event = c::epoll_event {
|
|
||||||
events: events as _,
|
|
||||||
u64: id,
|
|
||||||
};
|
|
||||||
if let Err(e) = uapi::epoll_ctl(self.epoll.raw(), c::EPOLL_CTL_ADD, fd, Some(&event)) {
|
|
||||||
return Err(EventLoopError::InsertFailed(e.into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.entries.set(id, Entry { fd, dispatcher });
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn modify(&self, id: EventLoopId, events: i32) -> Result<(), EventLoopError> {
|
|
||||||
self.check_destroyed()?;
|
|
||||||
let id = id.0;
|
|
||||||
let entry = match self.entries.get(&id) {
|
|
||||||
Some(e) => e,
|
|
||||||
None => return Err(EventLoopError::NoEntry),
|
|
||||||
};
|
|
||||||
if let Some(fd) = entry.fd {
|
|
||||||
let event = c::epoll_event {
|
|
||||||
events: events as _,
|
|
||||||
u64: id,
|
|
||||||
};
|
|
||||||
if let Err(e) = uapi::epoll_ctl(self.epoll.raw(), c::EPOLL_CTL_MOD, fd, Some(&event)) {
|
|
||||||
return Err(EventLoopError::ModifyFailed(e.into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove(&self, id: EventLoopId) -> Result<(), EventLoopError> {
|
|
||||||
self.check_destroyed()?;
|
|
||||||
let id = id.0;
|
|
||||||
let entry = match self.entries.remove(&id) {
|
|
||||||
Some(e) => e,
|
|
||||||
None => return Err(EventLoopError::NoEntry),
|
|
||||||
};
|
|
||||||
if let Some(fd) = entry.fd {
|
|
||||||
if let Err(e) = uapi::epoll_ctl(self.epoll.raw(), c::EPOLL_CTL_DEL, fd, None) {
|
|
||||||
if e.0 != c::ENOENT {
|
|
||||||
return Err(EventLoopError::RemoveFailed(e.into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn schedule(&self, id: EventLoopId) -> Result<(), EventLoopError> {
|
|
||||||
self.check_destroyed()?;
|
|
||||||
self.scheduled.borrow_mut().push_back(id.0);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&self) -> Result<(), EventLoopError> {
|
|
||||||
let res = self.run_();
|
|
||||||
self.stop();
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_(&self) -> Result<(), EventLoopError> {
|
|
||||||
self.check_destroyed()?;
|
|
||||||
let mut buf = [c::epoll_event { events: 0, u64: 0 }; 16];
|
|
||||||
'outer: while !self.destroyed.get() {
|
|
||||||
while let Some(id) = self.scheduled.borrow_mut().pop_front() {
|
|
||||||
if self.destroyed.get() {
|
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
if let Some(entry) = self.entries.get(&id) {
|
|
||||||
if let Err(e) = entry.dispatcher.clone().dispatch(entry.fd, 0) {
|
|
||||||
return Err(EventLoopError::DispatcherError(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if self.destroyed.get() {
|
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
let num = match uapi::epoll_wait(self.epoll.raw(), &mut buf, -1) {
|
|
||||||
Ok(n) => n,
|
|
||||||
Err(Errno(c::EINTR)) => continue,
|
|
||||||
Err(e) => return Err(EventLoopError::WaitFailed(e.into())),
|
|
||||||
};
|
|
||||||
for event in &buf[..num] {
|
|
||||||
if self.destroyed.get() {
|
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
let id = event.u64;
|
|
||||||
let entry = match self.entries.get(&id) {
|
|
||||||
Some(d) => d,
|
|
||||||
None => {
|
|
||||||
log::warn!(
|
|
||||||
"Client {} created an event but has already been removed",
|
|
||||||
id,
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if let Err(e) = entry
|
|
||||||
.dispatcher
|
|
||||||
.clone()
|
|
||||||
.dispatch(entry.fd, event.events as i32)
|
|
||||||
{
|
|
||||||
return Err(EventLoopError::DispatcherError(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -5,7 +5,6 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncEngine, SpawnedFuture},
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
compositor::{DISPLAY, WAYLAND_DISPLAY},
|
compositor::{DISPLAY, WAYLAND_DISPLAY},
|
||||||
event_loop::EventLoop,
|
|
||||||
forker::{
|
forker::{
|
||||||
clone3::{fork_with_pidfd, Forked},
|
clone3::{fork_with_pidfd, Forked},
|
||||||
io::{IoIn, IoOut},
|
io::{IoIn, IoOut},
|
||||||
|
|
@ -328,14 +327,13 @@ impl Forker {
|
||||||
let _ = Fd::new(socket).write_all(&msg);
|
let _ = Fd::new(socket).write_all(&msg);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
let el = EventLoop::new().unwrap();
|
let ae = AsyncEngine::new();
|
||||||
let ae = AsyncEngine::install(&el).unwrap();
|
|
||||||
let ring = IoUring::new(&ae, 32).unwrap();
|
let ring = IoUring::new(&ae, 32).unwrap();
|
||||||
let wheel = Wheel::new(&ae, &ring).unwrap();
|
let wheel = Wheel::new(&ae, &ring).unwrap();
|
||||||
let forker = Rc::new(Forker {
|
let forker = Rc::new(Forker {
|
||||||
socket,
|
socket,
|
||||||
ae: ae.clone(),
|
ae: ae.clone(),
|
||||||
ring,
|
ring: ring.clone(),
|
||||||
wheel,
|
wheel,
|
||||||
fds: RefCell::new(vec![]),
|
fds: RefCell::new(vec![]),
|
||||||
outgoing: Default::default(),
|
outgoing: Default::default(),
|
||||||
|
|
@ -343,7 +341,7 @@ impl Forker {
|
||||||
});
|
});
|
||||||
let _f1 = ae.spawn(forker.clone().incoming());
|
let _f1 = ae.spawn(forker.clone().incoming());
|
||||||
let _f2 = ae.spawn(forker.clone().outgoing());
|
let _f2 = ae.spawn(forker.clone().outgoing());
|
||||||
let _ = el.run();
|
let _ = ring.run();
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ impl JayCompositor {
|
||||||
fn quit(&self, parser: MsgParser<'_, '_>) -> Result<(), JayCompositorError> {
|
fn quit(&self, parser: MsgParser<'_, '_>) -> Result<(), JayCompositorError> {
|
||||||
let _req: Quit = self.client.parse(self, parser)?;
|
let _req: Quit = self.client.parse(self, parser)?;
|
||||||
log::info!("Quitting");
|
log::info!("Quitting");
|
||||||
self.client.state.el.stop();
|
self.client.state.ring.stop();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
132
src/io_uring.rs
132
src/io_uring.rs
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncEngine, AsyncError, AsyncFd, FdStatus, Phase, SpawnedFuture},
|
async_engine::AsyncEngine,
|
||||||
io_uring::{
|
io_uring::{
|
||||||
ops::{async_cancel::AsyncCancelTask, poll::PollTask, write::WriteTask},
|
ops::{async_cancel::AsyncCancelTask, poll::PollTask, write::WriteTask},
|
||||||
pending_result::PendingResults,
|
pending_result::PendingResults,
|
||||||
|
|
@ -33,7 +33,10 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
uapi::c::{self},
|
uapi::{
|
||||||
|
c::{self},
|
||||||
|
OwnedFd,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! map_err {
|
macro_rules! map_err {
|
||||||
|
|
@ -56,8 +59,6 @@ mod sys;
|
||||||
pub enum IoUringError {
|
pub enum IoUringError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
OsError(OsError),
|
OsError(OsError),
|
||||||
#[error("The async engine returned an error")]
|
|
||||||
AsyncError(#[from] AsyncError),
|
|
||||||
#[error("Could not create an io-uring")]
|
#[error("Could not create an io-uring")]
|
||||||
CreateUring(#[source] OsError),
|
CreateUring(#[source] OsError),
|
||||||
#[error("The kernel does not support the IORING_FEAT_NODROP feature")]
|
#[error("The kernel does not support the IORING_FEAT_NODROP feature")]
|
||||||
|
|
@ -70,6 +71,8 @@ pub enum IoUringError {
|
||||||
MapCqRing(#[source] OsError),
|
MapCqRing(#[source] OsError),
|
||||||
#[error("The io-uring has already been destroyed")]
|
#[error("The io-uring has already been destroyed")]
|
||||||
Destroyed,
|
Destroyed,
|
||||||
|
#[error("io_uring_enter failed")]
|
||||||
|
Enter(#[source] OsError),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IoUring {
|
pub struct IoUring {
|
||||||
|
|
@ -86,7 +89,7 @@ impl IoUring {
|
||||||
pub fn new(eng: &Rc<AsyncEngine>, entries: u32) -> Result<Rc<Self>, IoUringError> {
|
pub fn new(eng: &Rc<AsyncEngine>, entries: u32) -> Result<Rc<Self>, IoUringError> {
|
||||||
let mut params = io_uring_params::default();
|
let mut params = io_uring_params::default();
|
||||||
let fd = match io_uring_setup(entries, &mut params) {
|
let fd = match io_uring_setup(entries, &mut params) {
|
||||||
Ok(f) => Rc::new(f),
|
Ok(f) => f,
|
||||||
Err(e) => return Err(IoUringError::CreateUring(e.into())),
|
Err(e) => return Err(IoUringError::CreateUring(e.into())),
|
||||||
};
|
};
|
||||||
if !params.features.contains(IORING_FEAT_NODROP) {
|
if !params.features.contains(IORING_FEAT_NODROP) {
|
||||||
|
|
@ -172,10 +175,10 @@ impl IoUring {
|
||||||
.cast();
|
.cast();
|
||||||
std::slice::from_raw_parts(base, params.cq_entries as _)
|
std::slice::from_raw_parts(base, params.cq_entries as _)
|
||||||
};
|
};
|
||||||
let fd = eng.fd(&fd)?;
|
|
||||||
let data = Rc::new(IoUringData {
|
let data = Rc::new(IoUringData {
|
||||||
destroyed: Cell::new(false),
|
destroyed: Cell::new(false),
|
||||||
fd,
|
fd,
|
||||||
|
eng: eng.clone(),
|
||||||
_sqesmap_map: sqesmap_map,
|
_sqesmap_map: sqesmap_map,
|
||||||
_sqmap_map: sqmap_map,
|
_sqmap_map: sqmap_map,
|
||||||
sqmask,
|
sqmask,
|
||||||
|
|
@ -198,21 +201,26 @@ impl IoUring {
|
||||||
cached_writes: Default::default(),
|
cached_writes: Default::default(),
|
||||||
cached_cancels: Default::default(),
|
cached_cancels: Default::default(),
|
||||||
cached_polls: Default::default(),
|
cached_polls: Default::default(),
|
||||||
reader: Cell::new(None),
|
|
||||||
submitter: Cell::new(None),
|
|
||||||
});
|
});
|
||||||
let submitter = eng.spawn2(Phase::Present, data.clone().submit());
|
|
||||||
let reader = eng.spawn(data.clone().reader());
|
|
||||||
data.reader.set(Some(reader));
|
|
||||||
data.submitter.set(Some(submitter));
|
|
||||||
Ok(Rc::new(Self { ring: data }))
|
Ok(Rc::new(Self { ring: data }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn stop(&self) {
|
||||||
|
self.ring.kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&self) -> Result<(), IoUringError> {
|
||||||
|
let res = self.ring.run();
|
||||||
|
self.ring.kill();
|
||||||
|
res
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IoUringData {
|
struct IoUringData {
|
||||||
destroyed: Cell<bool>,
|
destroyed: Cell<bool>,
|
||||||
|
|
||||||
fd: AsyncFd,
|
fd: OwnedFd,
|
||||||
|
eng: Rc<AsyncEngine>,
|
||||||
|
|
||||||
_sqesmap_map: Mmapped,
|
_sqesmap_map: Mmapped,
|
||||||
_sqmap_map: Mmapped,
|
_sqmap_map: Mmapped,
|
||||||
|
|
@ -240,9 +248,6 @@ struct IoUringData {
|
||||||
cached_writes: Stack<Box<WriteTask>>,
|
cached_writes: Stack<Box<WriteTask>>,
|
||||||
cached_cancels: Stack<Box<AsyncCancelTask>>,
|
cached_cancels: Stack<Box<AsyncCancelTask>>,
|
||||||
cached_polls: Stack<Box<PollTask>>,
|
cached_polls: Stack<Box<PollTask>>,
|
||||||
|
|
||||||
reader: Cell<Option<SpawnedFuture<()>>>,
|
|
||||||
submitter: Cell<Option<SpawnedFuture<()>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe trait Task {
|
unsafe trait Task {
|
||||||
|
|
@ -256,20 +261,47 @@ unsafe trait Task {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IoUringData {
|
impl IoUringData {
|
||||||
async fn reader(self: Rc<Self>) {
|
fn run(&self) -> Result<(), IoUringError> {
|
||||||
|
let mut to_submit = 0;
|
||||||
loop {
|
loop {
|
||||||
if !self.dispatch_completions() {
|
loop {
|
||||||
match self.fd.readable().await {
|
self.eng.dispatch();
|
||||||
Err(e) => {
|
if self.destroyed.get() {
|
||||||
log::error!("Could not wait for the fd to become readable: {}", e);
|
return Ok(());
|
||||||
}
|
}
|
||||||
Ok(FdStatus::Err) => {
|
if !self.dispatch_completions() {
|
||||||
log::error!("Fd is in an error state");
|
break;
|
||||||
}
|
}
|
||||||
_ => continue,
|
}
|
||||||
|
to_submit += self.encode();
|
||||||
|
let res = if to_submit == 0 {
|
||||||
|
io_uring_enter(self.fd.raw(), 0, 1, IORING_ENTER_GETEVENTS)
|
||||||
|
} else if self.to_encode.is_empty() {
|
||||||
|
io_uring_enter(self.fd.raw(), to_submit as _, 1, IORING_ENTER_GETEVENTS)
|
||||||
|
} else {
|
||||||
|
io_uring_enter(self.fd.raw(), !0, 0, 0)
|
||||||
|
};
|
||||||
|
let mut submitted_any = false;
|
||||||
|
match res {
|
||||||
|
Ok(n) => {
|
||||||
|
if n > 0 {
|
||||||
|
submitted_any = true;
|
||||||
|
}
|
||||||
|
to_submit -= n;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
if !matches!(e.0, c::EAGAIN | c::EBUSY | c::EINTR) {
|
||||||
|
return Err(IoUringError::Enter(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if to_submit > 0 && !submitted_any {
|
||||||
|
let res = io_uring_enter(self.fd.raw(), 0, 1, IORING_ENTER_GETEVENTS);
|
||||||
|
if let Err(e) = res {
|
||||||
|
if e.0 != c::EINTR {
|
||||||
|
return Err(IoUringError::Enter(e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.kill();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -327,48 +359,6 @@ impl IoUringData {
|
||||||
encoded
|
encoded
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn submit(self: Rc<Self>) {
|
|
||||||
let mut to_submit = 0;
|
|
||||||
loop {
|
|
||||||
self.to_encode.non_empty().await;
|
|
||||||
to_submit += self.encode();
|
|
||||||
if to_submit == 0 {
|
|
||||||
match self.fd.writable().await {
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Could not write for fd to become writable: {}", ErrorFmt(e));
|
|
||||||
}
|
|
||||||
Ok(FdStatus::Err) => {
|
|
||||||
log::error!("Fd is in an error state");
|
|
||||||
}
|
|
||||||
_ => continue,
|
|
||||||
}
|
|
||||||
self.kill();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while to_submit > 0 {
|
|
||||||
let res = io_uring_enter(self.fd.raw(), to_submit as _, 0, 0);
|
|
||||||
match res {
|
|
||||||
Ok(0) => {
|
|
||||||
panic!("io_uring_enter returned 0");
|
|
||||||
}
|
|
||||||
Ok(n) => to_submit -= n,
|
|
||||||
Err(e) => match e.0 {
|
|
||||||
c::EAGAIN | c::EBUSY => {
|
|
||||||
log::debug!("waiting for completion events");
|
|
||||||
self.cqes_consumed.clear();
|
|
||||||
self.cqes_consumed.triggered().await;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
log::error!("io_uring_enter returned an error: {}", ErrorFmt(e));
|
|
||||||
self.kill();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id(&self) -> Cancellable {
|
fn id(&self) -> Cancellable {
|
||||||
Cancellable {
|
Cancellable {
|
||||||
id: self.id_raw(),
|
id: self.id_raw(),
|
||||||
|
|
@ -409,8 +399,6 @@ impl IoUringData {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kill(&self) {
|
fn kill(&self) {
|
||||||
self.reader.take();
|
|
||||||
self.submitter.take();
|
|
||||||
let mut to_cancel = vec![];
|
let mut to_cancel = vec![];
|
||||||
for task in self.tasks.lock().values() {
|
for task in self.tasks.lock().values() {
|
||||||
if !task.is_cancel() {
|
if !task.is_cancel() {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ mod config;
|
||||||
mod cursor;
|
mod cursor;
|
||||||
mod dbus;
|
mod dbus;
|
||||||
mod edid;
|
mod edid;
|
||||||
mod event_loop;
|
|
||||||
mod fixed;
|
mod fixed;
|
||||||
mod forker;
|
mod forker;
|
||||||
mod format;
|
mod format;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncEngine, SpawnedFuture},
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
event_loop::{EventLoop, EventLoopError},
|
|
||||||
io_uring::IoUring,
|
io_uring::IoUring,
|
||||||
utils::{errorfmt::ErrorFmt, oserror::OsError},
|
utils::{errorfmt::ErrorFmt, oserror::OsError},
|
||||||
},
|
},
|
||||||
|
|
@ -16,12 +15,9 @@ pub enum SighandError {
|
||||||
BlockFailed(#[source] OsError),
|
BlockFailed(#[source] OsError),
|
||||||
#[error("Could not create a signalfd")]
|
#[error("Could not create a signalfd")]
|
||||||
CreateFailed(#[source] OsError),
|
CreateFailed(#[source] OsError),
|
||||||
#[error("The event loop caused an error")]
|
|
||||||
EventLoopError(#[from] EventLoopError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install(
|
pub fn install(
|
||||||
el: &Rc<EventLoop>,
|
|
||||||
eng: &Rc<AsyncEngine>,
|
eng: &Rc<AsyncEngine>,
|
||||||
ring: &Rc<IoUring>,
|
ring: &Rc<IoUring>,
|
||||||
) -> Result<SpawnedFuture<()>, SighandError> {
|
) -> Result<SpawnedFuture<()>, SighandError> {
|
||||||
|
|
@ -36,10 +32,10 @@ pub fn install(
|
||||||
Ok(fd) => Rc::new(fd),
|
Ok(fd) => Rc::new(fd),
|
||||||
Err(e) => return Err(SighandError::CreateFailed(e.into())),
|
Err(e) => return Err(SighandError::CreateFailed(e.into())),
|
||||||
};
|
};
|
||||||
Ok(eng.spawn(handle_signals(fd, ring.clone(), el.clone())))
|
Ok(eng.spawn(handle_signals(fd, ring.clone())))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_signals(fd: Rc<OwnedFd>, ring: Rc<IoUring>, el: Rc<EventLoop>) {
|
async fn handle_signals(fd: Rc<OwnedFd>, ring: Rc<IoUring>) {
|
||||||
let mut siginfo: c::signalfd_siginfo = uapi::pod_zeroed();
|
let mut siginfo: c::signalfd_siginfo = uapi::pod_zeroed();
|
||||||
loop {
|
loop {
|
||||||
if let Err(e) = ring.readable(&fd).await {
|
if let Err(e) = ring.readable(&fd).await {
|
||||||
|
|
@ -66,7 +62,7 @@ async fn handle_signals(fd: Rc<OwnedFd>, ring: Rc<IoUring>, el: Rc<EventLoop>) {
|
||||||
log::info!("Received signal {}", sig);
|
log::info!("Received signal {}", sig);
|
||||||
if matches!(sig, c::SIGINT | c::SIGTERM) {
|
if matches!(sig, c::SIGINT | c::SIGTERM) {
|
||||||
log::info!("Exiting");
|
log::info!("Exiting");
|
||||||
el.stop();
|
ring.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ use {
|
||||||
config::ConfigProxy,
|
config::ConfigProxy,
|
||||||
cursor::ServerCursors,
|
cursor::ServerCursors,
|
||||||
dbus::Dbus,
|
dbus::Dbus,
|
||||||
event_loop::EventLoop,
|
|
||||||
forker::ForkerProxy,
|
forker::ForkerProxy,
|
||||||
globals::{Globals, GlobalsError, WaylandGlobal},
|
globals::{Globals, GlobalsError, WaylandGlobal},
|
||||||
ifs::{
|
ifs::{
|
||||||
|
|
@ -63,7 +62,6 @@ pub struct State {
|
||||||
pub forker: CloneCell<Option<Rc<ForkerProxy>>>,
|
pub forker: CloneCell<Option<Rc<ForkerProxy>>>,
|
||||||
pub default_keymap: Rc<XkbKeymap>,
|
pub default_keymap: Rc<XkbKeymap>,
|
||||||
pub eng: Rc<AsyncEngine>,
|
pub eng: Rc<AsyncEngine>,
|
||||||
pub el: Rc<EventLoop>,
|
|
||||||
pub render_ctx: CloneCell<Option<Rc<RenderContext>>>,
|
pub render_ctx: CloneCell<Option<Rc<RenderContext>>>,
|
||||||
pub render_ctx_version: NumCell<u32>,
|
pub render_ctx_version: NumCell<u32>,
|
||||||
pub render_ctx_ever_initialized: Cell<bool>,
|
pub render_ctx_ever_initialized: Cell<bool>,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncEngine, AsyncError, SpawnedFuture},
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
client::{EventFormatter, RequestParser},
|
client::{EventFormatter, RequestParser},
|
||||||
compositor::WAYLAND_DISPLAY,
|
compositor::WAYLAND_DISPLAY,
|
||||||
event_loop::{EventLoop, EventLoopError},
|
|
||||||
io_uring::{IoUring, IoUringError},
|
io_uring::{IoUring, IoUringError},
|
||||||
logger::Logger,
|
logger::Logger,
|
||||||
object::{ObjectId, WL_DISPLAY_ID},
|
object::{ObjectId, WL_DISPLAY_ID},
|
||||||
|
|
@ -44,12 +43,8 @@ use {
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ToolClientError {
|
pub enum ToolClientError {
|
||||||
#[error("Could not create an event loop")]
|
|
||||||
CreateEventLoop(#[source] EventLoopError),
|
|
||||||
#[error("Could not create a timer wheel")]
|
#[error("Could not create a timer wheel")]
|
||||||
CreateWheel(#[source] WheelError),
|
CreateWheel(#[source] WheelError),
|
||||||
#[error("Could not create an async engine")]
|
|
||||||
CreateEngine(#[source] AsyncError),
|
|
||||||
#[error("Could not create an io-uring")]
|
#[error("Could not create an io-uring")]
|
||||||
CreateRing(#[source] IoUringError),
|
CreateRing(#[source] IoUringError),
|
||||||
#[error("XDG_RUNTIME_DIR is not set")]
|
#[error("XDG_RUNTIME_DIR is not set")]
|
||||||
|
|
@ -78,7 +73,6 @@ pub enum ToolClientError {
|
||||||
|
|
||||||
pub struct ToolClient {
|
pub struct ToolClient {
|
||||||
pub logger: Arc<Logger>,
|
pub logger: Arc<Logger>,
|
||||||
pub el: Rc<EventLoop>,
|
|
||||||
pub ring: Rc<IoUring>,
|
pub ring: Rc<IoUring>,
|
||||||
pub wheel: Rc<Wheel>,
|
pub wheel: Rc<Wheel>,
|
||||||
pub eng: Rc<AsyncEngine>,
|
pub eng: Rc<AsyncEngine>,
|
||||||
|
|
@ -118,21 +112,14 @@ impl ToolClient {
|
||||||
f.await;
|
f.await;
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
});
|
});
|
||||||
if let Err(e) = self.el.run() {
|
if let Err(e) = self.ring.run() {
|
||||||
fatal!("A fatal error occurred: {}", ErrorFmt(e));
|
fatal!("A fatal error occurred: {}", ErrorFmt(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_new(level: Level) -> Result<Rc<Self>, ToolClientError> {
|
pub fn try_new(level: Level) -> Result<Rc<Self>, ToolClientError> {
|
||||||
let logger = Logger::install_stderr(level);
|
let logger = Logger::install_stderr(level);
|
||||||
let el = match EventLoop::new() {
|
let eng = AsyncEngine::new();
|
||||||
Ok(e) => e,
|
|
||||||
Err(e) => return Err(ToolClientError::CreateEventLoop(e)),
|
|
||||||
};
|
|
||||||
let eng = match AsyncEngine::install(&el) {
|
|
||||||
Ok(e) => e,
|
|
||||||
Err(e) => return Err(ToolClientError::CreateEngine(e)),
|
|
||||||
};
|
|
||||||
let ring = match IoUring::new(&eng, 32) {
|
let ring = match IoUring::new(&eng, 32) {
|
||||||
Ok(e) => e,
|
Ok(e) => e,
|
||||||
Err(e) => return Err(ToolClientError::CreateRing(e)),
|
Err(e) => return Err(ToolClientError::CreateRing(e)),
|
||||||
|
|
@ -174,7 +161,6 @@ impl ToolClient {
|
||||||
obj_ids.take(1);
|
obj_ids.take(1);
|
||||||
let slf = Rc::new(Self {
|
let slf = Rc::new(Self {
|
||||||
logger,
|
logger,
|
||||||
el,
|
|
||||||
ring,
|
ring,
|
||||||
wheel,
|
wheel,
|
||||||
eng,
|
eng,
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,10 @@ impl<T> AsyncQueue<T> {
|
||||||
mem::take(&mut *self.data.borrow_mut());
|
mem::take(&mut *self.data.borrow_mut());
|
||||||
self.waiter.take();
|
self.waiter.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.data.borrow_mut().is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AsyncQueuePop<'a, T> {
|
pub struct AsyncQueuePop<'a, T> {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncEngine, AsyncError, SpawnedFuture},
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
io_uring::IoUring,
|
io_uring::IoUring,
|
||||||
time::{Time, TimeError},
|
time::{Time, TimeError},
|
||||||
utils::{
|
utils::{
|
||||||
|
|
@ -28,8 +28,6 @@ pub enum WheelError {
|
||||||
CreateFailed(#[source] OsError),
|
CreateFailed(#[source] OsError),
|
||||||
#[error("Could not set the timerfd")]
|
#[error("Could not set the timerfd")]
|
||||||
SetFailed(#[source] OsError),
|
SetFailed(#[source] OsError),
|
||||||
#[error("An async error occurred")]
|
|
||||||
AsyncError(#[from] AsyncError),
|
|
||||||
#[error("Cannot determine the time")]
|
#[error("Cannot determine the time")]
|
||||||
TimeError(#[from] TimeError),
|
TimeError(#[from] TimeError),
|
||||||
#[error("The timer wheel is already destroyed")]
|
#[error("The timer wheel is already destroyed")]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ pub use crate::xcon::{
|
||||||
};
|
};
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncError, Phase, SpawnedFuture},
|
async_engine::{Phase, SpawnedFuture},
|
||||||
compositor::DISPLAY,
|
compositor::DISPLAY,
|
||||||
state::State,
|
state::State,
|
||||||
utils::{
|
utils::{
|
||||||
|
|
@ -87,8 +87,6 @@ pub enum XconError {
|
||||||
#[error("Server requires additional authentication: {0}")]
|
#[error("Server requires additional authentication: {0}")]
|
||||||
Authenticate(BString),
|
Authenticate(BString),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
AsyncError(#[from] AsyncError),
|
|
||||||
#[error(transparent)]
|
|
||||||
BufIoError(#[from] BufIoError),
|
BufIoError(#[from] BufIoError),
|
||||||
#[error("The server did not send a reply to a request")]
|
#[error("The server did not send a reply to a request")]
|
||||||
MissingReply,
|
MissingReply,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue