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}