Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove watcher, pin better #16

Merged
merged 2 commits into from
Aug 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 1 addition & 4 deletions lefthk-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "lefthk-core"
version = "0.1.4"
edition = "2018"
edition = "2021"
license = "BSD-3-Clause"
readme = "README.md"
repository = "https://github.com/leftwm/lefthk"
Expand All @@ -17,8 +17,5 @@ tokio = { version = "1.14.0", features = ["fs", "io-util", "macros", "net", "rt-
x11-dl = "2.19.1"
xdg = "2.4.0"

[features]
watcher = []

[dev-dependencies]
tempfile = "3.2.0"
75 changes: 0 additions & 75 deletions lefthk-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,78 +46,3 @@ pub struct Keybind {
pub trait Config {
fn mapped_bindings(&self) -> Vec<Keybind>;
}

#[cfg(feature = "watcher")]
pub mod watcher {
use crate::errors::{Error, Result};
use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify};
use std::os::unix::prelude::AsRawFd;
use std::path::Path;
use std::sync::Arc;
use tokio::sync::{oneshot, Notify};
use tokio::time::Duration;

pub struct Watcher {
fd: Inotify,
task_notify: Arc<Notify>,
_task_guard: oneshot::Receiver<()>,
}

impl Watcher {
pub fn new(config_file: &Path) -> Result<Watcher> {
const INOTIFY: mio::Token = mio::Token(0);
let fd = Inotify::init(InitFlags::all())?;
let mut flags = AddWatchFlags::empty();
flags.insert(AddWatchFlags::IN_MODIFY);
let _wd = fd.add_watch(config_file, flags)?;

let (guard, _task_guard) = oneshot::channel::<()>();
let notify = Arc::new(Notify::new());
let task_notify = notify.clone();
let mut poll = mio::Poll::new()?;
let mut events = mio::Events::with_capacity(1);
poll.registry().register(
&mut mio::unix::SourceFd(&fd.as_raw_fd()),
INOTIFY,
mio::Interest::READABLE,
)?;
let timeout = Duration::from_millis(50);
tokio::task::spawn_blocking(move || loop {
if guard.is_closed() {
return;
}

if let Err(err) = poll.poll(&mut events, Some(timeout)) {
log::warn!("Inotify socket poll failed with {:?}", err);
continue;
}

events
.iter()
.filter(|event| INOTIFY == event.token())
.for_each(|_| notify.notify_one());
});
Ok(Self {
fd,
task_notify,
_task_guard,
})
}

pub fn refresh_watch(&self, config_file: &Path) -> Error {
let mut flags = AddWatchFlags::empty();
flags.insert(AddWatchFlags::IN_MODIFY);
let _wd = self.fd.add_watch(config_file, flags)?;
Ok(())
}

pub fn has_events(&self) -> bool {
self.fd.read_events().is_ok()
}

/// Wait until readable.
pub async fn wait_readable(&mut self) {
self.task_notify.notified().await;
}
}
}
2 changes: 0 additions & 2 deletions lefthk-core/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ pub enum LeftError {
NoConfigFound,
#[error("No value set for execution.")]
ValueNotFound,
#[error("Config watcher dropped.")]
WatcherDropped,
#[error("X failed status error.")]
XFailedStatus,
}
25 changes: 0 additions & 25 deletions lefthk-core/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,6 @@ pub(crate) mod test {
}
}

/// Config Testing
#[cfg(test)]
#[cfg(feature = "watcher")]
mod config {
use super::test::temp_path;
use crate::config::watcher::Watcher;
use tokio::{fs, io::AsyncWriteExt};

#[tokio::test]
async fn check_watcher() {
let config_file = temp_path().await.unwrap();
let watcher = Watcher::new(&config_file).unwrap();

let mut file = fs::OpenOptions::new()
.write(true)
.open(&config_file)
.await
.unwrap();
file.write_all(b"\n").await.unwrap();
file.flush().await.unwrap();

assert!(watcher.has_events());
}
}

/// IPC Testing
#[cfg(test)]
mod ipc {
Expand Down
92 changes: 6 additions & 86 deletions lefthk-core/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,13 @@ use crate::config::{self, Keybind};
use crate::errors::{self, Error, LeftError};
use crate::ipc::Pipe;
use crate::xkeysym_lookup;
use crate::xwrap::{self, XWrap};
#[cfg(feature = "watcher")]
use std::path::PathBuf;
use crate::xwrap::XWrap;
use std::process::{Command, Stdio};
use x11_dl::xlib;
use xdg::BaseDirectories;

pub struct Worker {
pub keybinds: Vec<Keybind>,
#[cfg(feature = "watcher")]
pub config_file: PathBuf,
pub base_directory: BaseDirectories,
pub xwrap: XWrap,
pub children: Children,
Expand All @@ -30,81 +26,6 @@ impl Drop for Worker {
}

impl Worker {
#[cfg(feature = "watcher")]
pub fn new(
keybinds: Vec<Keybind>,
config_file: PathBuf,
base_directory: BaseDirectories,
) -> Self {
Self {
keybinds,
config_file,
base_directory,
xwrap: XWrap::new(),
children: Children::new(),
reload_requested: false,
kill_requested: false,
chord_keybinds: None,
chord_elapsed: false,
}
}

#[cfg(feature = "watcher")]
pub async fn event_loop(&mut self) {
use crate::config::watcher::Watcher;

self.xwrap.grab_keys(&self.keybinds);
let mut watcher = errors::exit_on_error!(Watcher::new(&self.config_file));
let pipe_name = Pipe::pipe_name();
let pipe_file = errors::exit_on_error!(self.base_directory.place_runtime_file(pipe_name));
let mut pipe = errors::exit_on_error!(Pipe::new(pipe_file).await);
loop {
if self.kill_requested || self.reload_requested {
break;
}

if self.chord_elapsed {
self.xwrap.grab_keys(&self.keybinds);
self.chord_keybinds = None;
self.chord_elapsed = false;
}

let task_notify = xwrap::wait_readable(self.xwrap.task_notify.clone());
tokio::pin!(task_notify);

tokio::select! {
_ = self.children.wait_readable() => {
self.children.reap();
continue;
}
_ = &mut task_notify => {
let event_in_queue = self.xwrap.queue_len();
for _ in 0..event_in_queue {
let xlib_event = self.xwrap.get_next_event();
self.handle_event(&xlib_event);
}
continue;
}
_ = watcher.wait_readable(), if cfg!(watcher) => {
if watcher.has_events() {
errors::exit_on_error!(watcher.refresh_watch(&self.config_file));
self.reload_requested = true;
}
continue;
}
Some(command) = pipe.read_command() => {
match command {
config::Command::Reload => self.reload_requested = true,
config::Command::Kill => self.kill_requested = true,
_ => (),
}
continue;
}
}
}
}

#[cfg(not(feature = "watcher"))]
pub fn new(keybinds: Vec<Keybind>, base_directory: BaseDirectories) -> Self {
Self {
keybinds,
Expand All @@ -118,7 +39,6 @@ impl Worker {
}
}

#[cfg(not(feature = "watcher"))]
pub async fn event_loop(&mut self) {
self.xwrap.grab_keys(&self.keybinds);
let pipe_name = Pipe::pipe_name();
Expand All @@ -134,18 +54,18 @@ impl Worker {
self.chord_keybinds = None;
self.chord_elapsed = false;
}

let task_notify = xwrap::wait_readable(self.xwrap.task_notify.clone());
tokio::pin!(task_notify);
println!("1");

tokio::select! {
_ = self.children.wait_readable() => {
self.children.reap();
continue;
}
_ = &mut task_notify => {
_ = self.xwrap.wait_readable() => {
println!("2");
let event_in_queue = self.xwrap.queue_len();
for _ in 0..event_in_queue {
println!("3");
let xlib_event = self.xwrap.get_next_event();
self.handle_event(&xlib_event);
}
Expand All @@ -169,7 +89,7 @@ impl Worker {
xlib::MappingNotify => self.mapping_notify(&mut xlib::XMappingEvent::from(xlib_event)),
_ => return,
};
let _ = errors::log_on_error!(error);
errors::log_on_error!(error);
}

fn key_press(&mut self, event: &xlib::XKeyEvent) -> Error {
Expand Down
15 changes: 10 additions & 5 deletions lefthk-core/src/xwrap.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::config::Keybind;
use crate::errors::{self, Error, LeftError};
use crate::xkeysym_lookup;
use std::future::Future;
use std::os::raw::{c_int, c_ulong};
use std::pin::Pin;
use std::ptr;
use std::sync::Arc;
use tokio::sync::{oneshot, Notify};
Expand Down Expand Up @@ -44,7 +46,7 @@ impl XWrap {
SERVER,
mio::Interest::READABLE,
));
let timeout = Duration::from_millis(50);
let timeout = Duration::from_millis(100);
tokio::task::spawn_blocking(move || loop {
if guard.is_closed() {
return;
Expand Down Expand Up @@ -187,9 +189,12 @@ impl XWrap {
pub fn queue_len(&self) -> i32 {
unsafe { (self.xlib.XPending)(self.display) }
}
}

/// Wait until readable.
pub async fn wait_readable(task_notify: Arc<Notify>) {
task_notify.notified().await;
/// Wait until readable.
pub fn wait_readable(&mut self) -> Pin<Box<dyn Future<Output = ()>>> {
let task_notify = self.task_notify.clone();
Box::pin(async move {
task_notify.notified().await;
})
}
}
5 changes: 1 addition & 4 deletions lefthk/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "lefthk"
version = "0.1.4"
edition = "2018"
edition = "2021"
license = "BSD-3-Clause"
readme = "README.md"
repository = "https://github.com/leftwm/lefthk"
Expand All @@ -19,8 +19,5 @@ thiserror = "1.0.30"
tokio = { version = "1.14.0", features = ["fs", "io-util", "macros", "net", "rt-multi-thread", "sync", "time"] }
xdg = "2.4.0"

[features]
watcher = ["lefthk-core/watcher"]

[dev-dependencies]
tempfile = "3.2.0"
2 changes: 1 addition & 1 deletion lefthk/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, fs, path::Path};
use xdg::BaseDirectories;

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
pub enum Command {
Chord,
Execute,
Expand Down
2 changes: 0 additions & 2 deletions lefthk/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ pub enum LeftError {
NoConfigFound,
#[error("No value set for execution.")]
ValueNotFound,
#[error("Config watcher dropped.")]
WatcherDropped,
#[error("X failed status error.")]
XFailedStatus,
}
6 changes: 0 additions & 6 deletions lefthk/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ fn main() {
pretty_env_logger::init();
let mut old_config = None;
let path = errors::exit_on_error!(BaseDirectories::with_prefix("lefthk"));
#[cfg(feature = "watcher")]
let config_file = errors::exit_on_error!(path.place_config_file("config.kdl"));
loop {
let config = match config::load() {
Ok(config) => config,
Expand All @@ -54,11 +52,7 @@ fn main() {
let completed = std::panic::catch_unwind(|| {
let rt = errors::return_on_error!(tokio::runtime::Runtime::new());
let _rt_guard = rt.enter();
#[cfg(feature = "watcher")]
let mut worker =
Worker::new(config.mapped_bindings(), config_file.clone(), path.clone());

#[cfg(not(feature = "watcher"))]
let mut worker = Worker::new(config.mapped_bindings(), path.clone());

rt.block_on(worker.event_loop());
Expand Down