use std::sync::Mutex;
use smithay_client_toolkit::reexports::calloop::channel::Sender;
pub(crate) enum IngressMessage {
BgWritesQueued,
SelectionRead { token: u64, content: Option<String> },
}
static INGRESS_SENDER: Mutex<Option<Sender<IngressMessage>>> = Mutex::new(None);
pub(crate) fn install_ingress(sender: Sender<IngressMessage>) {
if let Ok(mut guard) = INGRESS_SENDER.lock() {
*guard = Some(sender);
}
}
pub(crate) struct IngressSender(Sender<IngressMessage>);
impl IngressSender {
pub(crate) fn send(self, message: IngressMessage) {
if self.0.send(message).is_err() {
log::debug!("ingress receiver is gone; waking through the ping instead");
crate::jobs::wake_loop();
}
}
}
pub(crate) fn sender_handle() -> Option<IngressSender> {
sender().map(IngressSender)
}
fn sender() -> Option<Sender<IngressMessage>> {
INGRESS_SENDER.lock().ok().and_then(|g| g.as_ref().cloned())
}
pub(crate) fn notify(message: IngressMessage) {
match sender() {
Some(tx) if tx.send(message).is_ok() => {}
_ => crate::jobs::wake_loop(),
}
}
pub(crate) fn reset_ingress() {
if let Ok(mut guard) = INGRESS_SENDER.lock() {
*guard = None;
}
}
#[cfg(test)]
mod tests {
use super::*;
use smithay_client_toolkit::reexports::calloop::ping::make_ping;
#[test]
fn giving_up_on_the_channel_hands_the_wakeup_to_the_ping() {
let _state = crate::jobs::wakeup_test_lock();
let (ping, _source) = make_ping().expect("ping");
let woken = (0..64).any(|_| {
reset_ingress(); crate::jobs::init_wakeup(ping.clone());
crate::jobs::mark_loop_awake();
notify(IngressMessage::BgWritesQueued);
crate::jobs::ping_in_flight()
});
assert!(
woken,
"the fallback must wake the loop it could not send to"
);
}
}