Skip to content

Commit

Permalink
Use the polling crate in xclock_utc
Browse files Browse the repository at this point in the history
  • Loading branch information
notgull committed Apr 9, 2023
1 parent b94ec26 commit 7050a5b
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 72 deletions.
3 changes: 3 additions & 0 deletions x11rb/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ winapi-wsapoll = "0.1.1"
version = "0.3"
features = ["winsock2"]

[dev-dependencies]
polling = "2.7.0"

[features]
# Without this feature, all uses of `unsafe` in the crate are forbidden via
# #![deny(unsafe_code)]. This has the effect of disabling the XCB FFI bindings.
Expand Down
106 changes: 34 additions & 72 deletions x11rb/examples/xclock_utc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::convert::TryFrom;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};

use polling::{Event as PollingEvent, Poller};

use x11rb::atom_manager;
use x11rb::connection::Connection;
use x11rb::errors::{ConnectionError, ReplyOrIdError};
Expand Down Expand Up @@ -166,87 +167,39 @@ fn redraw(
Ok(())
}

#[cfg(unix)]
fn poll_with_timeout(
poller: &Poller,
conn: &RustConnection,
timeout: Duration,
) -> Result<(), Box<dyn std::error::Error>> {
use std::os::raw::c_int;
use std::os::unix::io::AsRawFd;
// Add interest in the connection's stream.
poller.add(conn.stream(), PollingEvent::readable(1))?;

use nix::poll::{poll, PollFd, PollFlags};
// Remove it if we time out.
let _guard = CallOnDrop(|| {
poller.delete(conn.stream()).ok();
});

let start_instant = Instant::now();
let fd = conn.stream().as_raw_fd();
let mut poll_fds = [PollFd::new(fd, PollFlags::POLLIN)];
// Wait for events.
let mut event = Vec::with_capacity(1);
let target = Instant::now() + timeout;
loop {
let timeout_millis = timeout
.checked_sub(start_instant.elapsed())
.map(|remaining| c_int::try_from(remaining.as_millis()).unwrap_or(c_int::max_value()))
.unwrap_or(0);
match poll(&mut poll_fds, timeout_millis) {
Ok(_) => {
if poll_fds[0]
.revents()
.unwrap_or_else(PollFlags::empty)
.contains(PollFlags::POLLIN)
{
break;
}
}
// try again
Err(nix::Error::EINTR) => {}
Err(e) => return Err(e.into()),
}
if start_instant.elapsed() >= timeout {
break;
}
}
// We do not really care about the result of poll. Either there was a timeout, in which case we
// try to handle events (there are none) and then redraw. Or there was an event, in which case
// we handle it and then still redraw.
Ok(())
}
let remaining = target.saturating_duration_since(Instant::now());
poller.wait(&mut event, Some(remaining))?;

#[cfg(windows)]
fn poll_with_timeout(
conn: &RustConnection,
timeout: Duration,
) -> Result<(), Box<dyn std::error::Error>> {
use std::os::windows::io::AsRawSocket;

use winapi::shared::minwindef::INT;
use winapi::um::winsock2::{POLLRDNORM, SOCKET, WSAPOLLFD};
use winapi_wsapoll::wsa_poll;

let start_instant = Instant::now();
let raw_socket = conn.stream().as_raw_socket();
let mut poll_fds = [WSAPOLLFD {
fd: raw_socket as SOCKET,
events: POLLRDNORM,
revents: 0,
}];
loop {
let timeout_millis = timeout
.checked_sub(start_instant.elapsed())
.map(|remaining| INT::try_from(remaining.as_millis()).unwrap_or(INT::max_value()))
.unwrap_or(0);
match wsa_poll(&mut poll_fds, timeout_millis) {
Ok(_) => {
if (poll_fds[0].revents & POLLRDNORM) != 0 {
break;
}
}
Err(e) => return Err(e.into()),
// If we received an event, we're done.
if event.contains(&PollingEvent::readable(1)) {
return Ok(());
}
if start_instant.elapsed() >= timeout {
break;

// If our timeout expired, we're done.
if Instant::now() >= target {
// We do not really care about the result of poll. Either there was a timeout, in which case we
// try to handle events (there are none) and then redraw. Or there was an event, in which case
// we handle it and then still redraw.
return Ok(());
}
}
// We do not really care about the result of poll. Either there was a timeout, in which case we
// try to handle events (there are none) and then redraw. Or there was an event, in which case
// we handle it and then still redraw.
Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
Expand All @@ -255,6 +208,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// The following is only needed for start_timeout_thread(), which is used for 'tests'
let conn1 = std::sync::Arc::new(conn);
let conn = &*conn1;
let poller = Poller::new()?;

let screen = &conn.setup().roots[screen_num];
let atoms = Atoms::new(conn)?.reply()?;
Expand All @@ -270,7 +224,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
conn.flush()?;

loop {
poll_with_timeout(conn, Duration::from_millis(1_000))?;
poll_with_timeout(&poller, conn, Duration::from_millis(1_000))?;
while let Some(event) = conn.poll_for_event()? {
println!("{:?})", event);
match event {
Expand Down Expand Up @@ -313,3 +267,11 @@ fn get_time() -> (u8, u8, u8) {
}

include!("integration_test_util/util.rs");

struct CallOnDrop<F: FnMut()>(F);

impl<F: FnMut()> Drop for CallOnDrop<F> {
fn drop(&mut self) {
(self.0)();
}
}

0 comments on commit 7050a5b

Please sign in to comment.