summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxVerevkin <maxxverrr@gmail.com>2023-08-29 18:57:19 +0300
committerMaxVerevkin <maxxverrr@gmail.com>2023-08-29 18:57:19 +0300
commit55b7f7e9b1000849cfa5f3d7cbcb8898f14ddef1 (patch)
treefa49f8e30264ce6266712da52f17e29485e0494e /src
parentbc20894d3758bdfefc82b2133b013e8c23dbfad1 (diff)
downloadi3bar-mango-55b7f7e9b1000849cfa5f3d7cbcb8898f14ddef1.tar.gz
update nix to 0.27 and reimplement polling with libc
Diffstat (limited to 'src')
-rw-r--r--src/main.rs96
-rw-r--r--src/status_cmd.rs15
2 files changed, 68 insertions, 43 deletions
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)