1
0
Fork 0
forked from wry/wry

config: add async tasks and polling infrastructure

This commit is contained in:
Julian Orth 2024-03-05 18:28:15 +01:00
parent 7fb68561e8
commit d4d76c0ef3
13 changed files with 613 additions and 13 deletions

View file

@ -5,12 +5,13 @@ use {
_private::{
bincode_ops,
ipc::{ClientMessage, InitMessage, Response, ServerMessage},
logging, Config, ConfigEntry, ConfigEntryGen, WireMode, VERSION,
logging, Config, ConfigEntry, ConfigEntryGen, PollableId, WireMode, VERSION,
},
exec::Command,
input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat},
keyboard::Keymap,
logging::LogLevel,
tasks::JoinSlot,
theme::{colors::Colorable, sized::Resizable, Color},
timer::Timer,
video::{
@ -20,13 +21,22 @@ use {
Axis, Direction, ModifiedKeySym, PciId, Workspace,
},
bincode::Options,
futures_util::task::ArcWake,
std::{
cell::{Cell, RefCell},
collections::{hash_map::Entry, HashMap},
collections::{hash_map::Entry, HashMap, VecDeque},
future::Future,
mem,
ops::Deref,
pin::Pin,
ptr,
rc::Rc,
slice,
sync::{
atomic::{AtomicBool, Ordering::Relaxed},
Arc, Mutex,
},
task::{Context, Poll, Waker},
time::Duration,
},
};
@ -50,6 +60,40 @@ pub(crate) struct Client {
on_idle: RefCell<Option<Rc<dyn Fn()>>>,
bufs: RefCell<Vec<Vec<u8>>>,
reload: Cell<bool>,
read_interests: RefCell<HashMap<PollableId, Interest>>,
write_interests: RefCell<HashMap<PollableId, Interest>>,
tasks: Tasks,
}
struct Interest {
result: Option<Result<(), String>>,
waker: Option<Waker>,
}
#[derive(Default)]
struct Tasks {
last_id: Cell<u64>,
ready_front: RefCell<VecDeque<u64>>,
ready_back: Arc<TasksBackBuffer>,
tasks: RefCell<HashMap<u64, Rc<RefCell<Task>>>>,
}
#[derive(Default)]
struct TasksBackBuffer {
any: AtomicBool,
tasks: Mutex<VecDeque<u64>>,
}
impl TasksBackBuffer {
fn append(&self, task: u64) {
self.tasks.lock().unwrap().push_back(task);
self.any.store(true, Relaxed);
}
}
struct Task {
task: Pin<Box<dyn Future<Output = ()>>>,
waker: Waker,
}
impl Drop for Client {
@ -138,6 +182,9 @@ pub unsafe extern "C" fn init(
on_idle: Default::default(),
bufs: Default::default(),
reload: Cell::new(false),
read_interests: Default::default(),
write_interests: Default::default(),
tasks: Default::default(),
});
let init = slice::from_raw_parts(init, size);
client.handle_init_msg(init);
@ -729,7 +776,122 @@ impl Client {
})
}
pub fn create_pollable(&self, fd: i32) -> Result<PollableId, String> {
let res = self.send_with_response(&ClientMessage::AddPollable { fd });
get_response!(
res,
Err("Compositor did not send a response".to_string()),
AddPollable { id }
);
id
}
pub fn remove_pollable(&self, id: PollableId) {
self.send(&ClientMessage::RemovePollable { id });
self.write_interests.borrow_mut().remove(&id);
self.read_interests.borrow_mut().remove(&id);
}
pub fn poll_io(
&self,
pollable: PollableId,
writable: bool,
ctx: &mut Context<'_>,
) -> Poll<Result<(), String>> {
let interests = match writable {
true => &self.write_interests,
false => &self.read_interests,
};
let mut interests = interests.borrow_mut();
match interests.entry(pollable) {
Entry::Occupied(mut o) => {
let interest = o.get_mut();
if interest.result.is_some() {
Poll::Ready(o.remove().result.unwrap())
} else {
interest.waker = Some(ctx.waker().clone());
Poll::Pending
}
}
Entry::Vacant(v) => {
self.send(&ClientMessage::AddInterest { pollable, writable });
v.insert(Interest {
result: None,
waker: Some(ctx.waker().clone()),
});
Poll::Pending
}
}
}
fn handle_msg(&self, msg: &[u8]) {
self.handle_msg2(msg);
self.dispatch_futures();
}
fn dispatch_futures(&self) {
let futures = &self.tasks;
if !futures.ready_back.any.load(Relaxed) {
return;
}
let mut ready = futures.ready_front.borrow_mut();
loop {
mem::swap(&mut *ready, &mut *futures.ready_back.tasks.lock().unwrap());
futures.ready_back.any.store(false, Relaxed);
while let Some(id) = ready.pop_front() {
let fut = futures.tasks.borrow_mut().get(&id).cloned();
if let Some(fut) = fut {
let mut fut = fut.borrow_mut();
let fut = &mut *fut;
if let Poll::Ready(()) =
fut.task.as_mut().poll(&mut Context::from_waker(&fut.waker))
{
futures.tasks.borrow_mut().remove(&id);
}
}
}
if !futures.ready_back.any.load(Relaxed) {
return;
}
}
}
pub fn spawn_task<T: 'static>(&self, f: impl Future<Output = T> + 'static) -> Rc<JoinSlot<T>> {
struct Waker(Arc<TasksBackBuffer>, u64);
impl ArcWake for Waker {
fn wake_by_ref(arc_self: &Arc<Self>) {
arc_self.0.append(arc_self.1);
}
}
let tasks = &self.tasks;
let id = tasks.last_id.get() + 1;
tasks.last_id.set(id);
let waker = futures_util::task::waker(Arc::new(Waker(tasks.ready_back.clone(), id)));
tasks.ready_back.append(id);
let slot = Rc::new(JoinSlot {
task_id: id,
slot: Cell::new(None),
waker: Cell::new(None),
});
let slot2 = slot.clone();
let task = Rc::new(RefCell::new(Task {
task: Box::pin(async move {
slot2.slot.set(Some(f.await));
if let Some(waker) = slot2.waker.take() {
waker.wake();
}
}),
waker,
}));
tasks.tasks.borrow_mut().insert(id, task);
slot
}
pub fn abort_task(&self, id: u64) {
self.tasks.tasks.borrow_mut().remove(&id);
}
fn handle_msg2(&self, msg: &[u8]) {
let res = bincode_ops().deserialize::<ServerMessage>(msg);
let msg = match res {
Ok(msg) => msg,
@ -813,6 +975,19 @@ impl Client {
handler();
}
}
ServerMessage::InterestReady { id, writable, res } => {
let interests = match writable {
true => &self.write_interests,
false => &self.read_interests,
};
let mut interests = interests.borrow_mut();
if let Some(interest) = interests.get_mut(&id) {
interest.result = Some(res);
if let Some(waker) = interest.waker.take() {
waker.wake();
}
}
}
}
}

View file

@ -7,7 +7,7 @@ use {
timer::Timer,
video::{connector_type::ConnectorType, Connector, DrmDevice, GfxApi, Transform},
Axis, Direction, PciId, Workspace,
_private::WireMode,
_private::{PollableId, WireMode},
},
serde::{Deserialize, Serialize},
std::time::Duration,
@ -57,6 +57,11 @@ pub enum ServerMessage {
},
Idle,
DevicesEnumerated,
InterestReady {
id: PollableId,
writable: bool,
res: Result<(), String>,
},
}
#[derive(Serialize, Deserialize, Debug)]
@ -360,6 +365,16 @@ pub enum ClientMessage<'a> {
connector: Connector,
mode: WireMode,
},
AddPollable {
fd: i32,
},
RemovePollable {
id: PollableId,
},
AddInterest {
pollable: PollableId,
writable: bool,
},
}
#[derive(Serialize, Deserialize, Debug)]
@ -465,6 +480,9 @@ pub enum Response {
ConnectorModes {
modes: Vec<WireMode>,
},
AddPollable {
id: Result<PollableId, String>,
},
}
#[derive(Serialize, Deserialize, Debug)]

View file

@ -0,0 +1,15 @@
use std::{
error::Error,
fmt::{Display, Formatter},
};
#[derive(Debug)]
pub struct StringError(pub String);
impl Display for StringError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
impl Error for StringError {}