ev3dev_lang_rust/wait.rs
1//! Utility functions for cpu efficient `wait` commands.
2//! Uses the `libc::epoll_wait` that only works on linux systems.
3
4#[cfg(target_os = "linux")]
5use libc;
6use std::os::unix::io::RawFd;
7use std::time::{Duration, Instant};
8
9/// Wait for until a condition `cond` is `true` or the `timeout` is reached.
10/// If the `timeout` is `None` it will wait an infinite time.
11/// The condition is checked when the `file` has changed.
12///
13/// # Arguments
14/// * `file` - Listen to changes in this file
15/// * `cond` - Condition that should become true
16/// * `timeout` - Maximal timeout to wait for the condition or file changes
17///
18/// # Example
19/// ```
20/// use std::fs::File;
21/// use std::os::unix::io::AsRawFd;
22/// use std::time::Duration;
23///
24/// use ev3dev_lang_rust::wait;
25///
26/// if let Ok(file) = File::open("...") {
27/// let cond = || {
28/// // ...
29/// true
30/// };
31/// let timeout = Duration::from_millis(2000);
32///
33/// wait::wait(file.as_raw_fd(), cond, Some(timeout));
34/// }
35/// ```
36pub fn wait<F>(fd: RawFd, cond: F, timeout: Option<Duration>) -> bool
37where
38 F: Fn() -> bool,
39{
40 if cond() {
41 return true;
42 }
43
44 let start = Instant::now();
45
46 let mut t = timeout;
47
48 loop {
49 let wait_timeout = match t {
50 Some(duration) => duration.as_millis() as i32,
51 None => -1,
52 };
53 wait_file_changes(fd, wait_timeout);
54
55 if let Some(duration) = timeout {
56 let elapsed = start.elapsed();
57 if elapsed >= duration {
58 return false;
59 }
60 t = Some(duration - elapsed);
61 }
62
63 if cond() {
64 return true;
65 }
66 }
67}
68
69/// Wrapper for `libc::epoll_wait`
70#[cfg(target_os = "linux")]
71fn wait_file_changes(fd: RawFd, timeout: i32) -> bool {
72 let mut buf: [libc::epoll_event; 10] = [libc::epoll_event { events: 0, u64: 0 }; 10];
73
74 let result = unsafe {
75 libc::epoll_wait(
76 fd,
77 buf.as_mut_ptr() as *mut libc::epoll_event,
78 buf.len() as i32,
79 timeout,
80 ) as i32
81 };
82
83 result > 0
84}
85
86/// Stub method for non linux os's
87#[cfg(not(target_os = "linux"))]
88fn wait_file_changes(_fd: RawFd, _timeout: i32) -> bool {
89 std::thread::sleep(Duration::from_millis(100));
90 false
91}