diff options
| -rw-r--r-- | Cargo.lock | 23 | ||||
| -rw-r--r-- | Cargo.toml | 3 | ||||
| -rw-r--r-- | src/main.rs | 96 | ||||
| -rw-r--r-- | src/status_cmd.rs | 15 |
4 files changed, 73 insertions, 64 deletions
@@ -291,8 +291,9 @@ version = "0.1.3" dependencies = [ "anyhow", "clap", + "libc", "memchr", - "nix 0.26.2", + "nix", "pangocairo", "serde", "serde_json", @@ -357,18 +358,6 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nix" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", - "static_assertions", -] - -[[package]] -name = "nix" version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" @@ -617,12 +606,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -741,7 +724,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4acba2f832601f9f57e1ff86347af792e6dcb19f5b6155328faec87257bfa76" dependencies = [ - "nix 0.27.1", + "nix", "thiserror", "wayrs-scanner", ] @@ -14,7 +14,7 @@ hyprland = [] [dependencies] anyhow = "1" memchr = "2" -nix = { version = "0.26", default-features = false, features = ["fs", "poll"] } +nix = { version = "0.27", default-features = false, features = ["fs"] } pangocairo = "0.17" serde_json = "1" serde = { version = "1", features = ["derive"] } @@ -24,6 +24,7 @@ wayrs-client = "0.12" wayrs-protocols = { version = "0.12", features = ["wlr-layer-shell-unstable-v1", "viewporter", "fractional-scale-v1"] } wayrs-utils = { version = "0.10", features = ["cursor", "shm_alloc", "seats"] } clap = { version = "4.3.23", default-features = false, features = ["derive", "std", "help"] } +libc = "0.2.147" [profile.release] lto = "fat" diff --git a/src/main.rs b/src/main.rs index d2f69d1..fc525ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,14 +17,12 @@ mod text; mod utils; mod wm_info_provider; -use std::io::ErrorKind; -use std::os::unix::io::AsRawFd; +use std::io::{self, ErrorKind}; +use std::os::fd::{AsRawFd, RawFd}; use std::path::PathBuf; use clap::Parser; -use nix::errno::Errno; use nix::fcntl::OFlag; -use nix::poll::{poll, PollFd, PollFlags}; use signal_hook::consts::*; use wayrs_client::{Connection, IoMode}; @@ -48,21 +46,10 @@ fn main() -> anyhow::Result<()> { let mut state = State::new(&mut conn, &globals, args.config.as_deref()); conn.flush(IoMode::Blocking)?; - let mut fds = Vec::with_capacity(3); - fds.push(PollFd::new(conn.as_raw_fd(), PollFlags::POLLIN)); - fds.push(PollFd::new(sig_read, PollFlags::POLLIN)); - if let Some(cmd_fd) = state.status_cmd_fd() { - fds.push(PollFd::new(cmd_fd, PollFlags::POLLIN)); - } - loop { - match poll(&mut fds, -1) { - Ok(_) => (), - Err(Errno::EINTR) => continue, - Err(e) => bail!(e), - } + let poll = Poll::new(conn.as_raw_fd(), sig_read, state.status_cmd_fd())?; - if fds[0].any().unwrap_or(false) { + if poll.wayland { match conn.recv_events(IoMode::NonBlocking) { Ok(()) => { conn.dispatch_events(&mut state); @@ -73,31 +60,68 @@ fn main() -> anyhow::Result<()> { } } - if fds[1].any().unwrap_or(false) { - nix::unistd::read(sig_read, &mut [0; 1])?; + if poll.signal { + nix::unistd::read(sig_read.as_raw_fd(), &mut [0; 1])?; state.toggle_visibility(&mut conn); conn.flush(IoMode::Blocking)?; } - if fds.len() > 2 && fds[2].any().unwrap_or(false) { - match state - .shared_state - .status_cmd - .as_mut() - .unwrap() - .receive_blocks() - { - Ok(None) => (), - Ok(Some(blocks)) => { - state.set_blocks(&mut conn, blocks); - conn.flush(IoMode::Blocking)?; + if let Some(status_cmd) = &mut state.shared_state.status_cmd { + if poll.cmd { + match status_cmd.receive_blocks() { + Ok(None) => (), + Ok(Some(blocks)) => { + state.set_blocks(&mut conn, blocks); + conn.flush(IoMode::Blocking)?; + } + Err(e) => { + let _ = state.shared_state.status_cmd.take().unwrap().child.kill(); + state.set_error(&mut conn, e); + conn.flush(IoMode::Blocking)?; + } } - Err(e) => { - let _ = state.shared_state.status_cmd.take().unwrap().child.kill(); - fds.pop().unwrap(); - state.set_error(&mut conn, e); - conn.flush(IoMode::Blocking)?; + } + } + } +} + +struct Poll { + wayland: bool, + signal: bool, + cmd: bool, +} + +impl Poll { + fn new(wayland: RawFd, signal: RawFd, cmd: Option<RawFd>) -> io::Result<Self> { + let mut fds = [libc::pollfd { + fd: 0, + events: libc::POLLIN, + revents: 0, + }; 3]; + + fds[0].fd = wayland.as_raw_fd(); + fds[1].fd = signal.as_raw_fd(); + fds[2].fd = cmd.map_or(0, |cmd| cmd.as_raw_fd()); + + loop { + // nix' (0.27) poll() implementation is hard to work with because of the lifetimes. In + // particular, it makes reusing the same buffer across poll()s very hard. It is better + // to just call directly into the libc at this point, it's not that hard. At least it is + // safer that trying to trick nix by using `BorrowedFd::borrow_raw()`. + let result = + unsafe { libc::poll(fds.as_mut_ptr(), if cmd.is_some() { 3 } else { 2 }, -1) }; + + if result == -1 { + let err = io::Error::last_os_error(); + if err.kind() != ErrorKind::Interrupted { + return Err(io::Error::last_os_error()); } + } else { + return Ok(Self { + wayland: fds[0].revents & libc::POLLIN != 0, + signal: fds[1].revents & libc::POLLIN != 0, + cmd: fds[2].revents & libc::POLLIN != 0, + }); } } } diff --git a/src/status_cmd.rs b/src/status_cmd.rs index 539ee3a..217ddab 100644 --- a/src/status_cmd.rs +++ b/src/status_cmd.rs @@ -1,12 +1,9 @@ -use std::io::{BufWriter, Write}; +use std::io::{self, BufWriter, ErrorKind, Write}; use std::os::unix::io::{AsRawFd, RawFd}; use std::process::{Child, ChildStdin, ChildStdout, Command, Stdio}; use anyhow::Result; -use nix::errno::Errno; -use nix::libc; - use crate::i3bar_protocol::{Block, Event, Protocol}; #[derive(Debug)] @@ -44,7 +41,7 @@ impl StatusCmd { match read_to_vec(self.output.as_raw_fd(), &mut self.buf) { Ok(0) => bail!("status command exited"), Ok(_n) => (), - Err(Errno::EAGAIN) => return Ok(None), + Err(e) if e.kind() == ErrorKind::WouldBlock => return Ok(None), Err(e) => bail!(e), } @@ -68,7 +65,7 @@ impl StatusCmd { /// Read from a raw file descriptor to the vector. /// /// Appends data at the end of the buffer. Resizes vector as needed. -pub fn read_to_vec(fd: RawFd, buf: &mut Vec<u8>) -> nix::Result<usize> { +pub fn read_to_vec(fd: RawFd, buf: &mut Vec<u8>) -> io::Result<usize> { if buf.capacity() - buf.len() < 1024 { buf.reserve(buf.capacity().max(1024)); } @@ -81,7 +78,11 @@ pub fn read_to_vec(fd: RawFd, buf: &mut Vec<u8>) -> nix::Result<usize> { ) }; - let read = Errno::result(res)? as usize; + if res == -1 { + return Err(io::Error::last_os_error()); + } + + let read = res as usize; unsafe { buf.set_len(buf.len() + read) }; Ok(read) |
