hirun/channel/
linux.rs

1use super::{Notify, FULL, PARTIAL};
2use crate::Error;
3use core::mem::{self, MaybeUninit};
4use core::ptr;
5use core::time::Duration;
6
7#[repr(C)]
8pub struct EventFd {
9    fd: i32,
10}
11
12impl Default for EventFd {
13    fn default() -> Self {
14        let fd = unsafe { libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC) };
15        assert!(fd > -1, "EventFd::default {}", Error::last());
16        Self { fd }
17    }
18}
19
20impl EventFd {
21    fn write(&self, val: u64) -> isize {
22        unsafe {
23            libc::write(
24                self.fd,
25                ptr::addr_of!(val).cast::<libc::c_void>(),
26                mem::size_of_val(&val),
27            )
28        }
29    }
30
31    fn read(&self) -> u64 {
32        let mut val = 0_u64;
33        unsafe {
34            libc::read(
35                self.fd,
36                ptr::addr_of_mut!(val).cast::<libc::c_void>(),
37                mem::size_of_val(&val),
38            );
39        }
40        val
41    }
42
43    #[cfg(any(target_os = "linux", target_os = "android"))]
44    fn wait(&self, read: bool, timeout: Option<Duration>) -> Option<Duration> {
45        let mut tm = libc::timeval {
46            tv_sec: 0,
47            tv_usec: 0,
48        };
49        let mut set = MaybeUninit::<libc::fd_set>::zeroed();
50        unsafe {
51            libc::FD_SET(self.fd, set.as_mut_ptr());
52        }
53        let null_set = ptr::null_mut::<libc::fd_set>();
54        let tm_ptr = if let Some(timeout) = timeout {
55            tm.tv_sec = timeout.as_secs() as libc::time_t;
56            tm.tv_usec = timeout.subsec_micros() as libc::suseconds_t;
57            ptr::addr_of_mut!(tm)
58        } else {
59            ptr::null_mut::<libc::timeval>()
60        };
61
62        let (rd_set, wr_set) = if read {
63            (set.as_mut_ptr(), null_set)
64        } else {
65            (null_set, set.as_mut_ptr())
66        };
67        unsafe { libc::select(self.fd + 1, rd_set, wr_set, null_set, tm_ptr) };
68        if tm_ptr.is_null() {
69            None
70        } else {
71            Some(Duration::new(tm.tv_sec as u64, (tm.tv_usec * 1000) as u32))
72        }
73    }
74}
75
76impl Drop for EventFd {
77    fn drop(&mut self) {
78        unsafe { libc::close(self.fd) };
79    }
80}
81
82impl Notify for EventFd {
83    fn notify(&self, from: u8, to: u8) {
84        assert!(from != to);
85        if from == PARTIAL {
86            if to == FULL {
87                self.write(u64::MAX >> 1);
88            } else {
89                self.read();
90            }
91        } else if from == FULL {
92            self.read();
93            if to == PARTIAL {
94                self.write(u64::MAX >> 1);
95            }
96        } else if to == PARTIAL {
97            self.write(u64::MAX >> 1);
98        } else {
99            self.write(u64::MAX - 1);
100        }
101    }
102
103    fn wait_read(&self, timeout: Option<Duration>) -> Option<Duration> {
104        self.wait(true, timeout)
105    }
106
107    fn wait_write(&self, timeout: Option<Duration>) -> Option<Duration> {
108        self.wait(false, timeout)
109    }
110
111    fn read_fd_event(&self) -> (i32, bool) {
112        (self.fd, true)
113    }
114
115    fn write_fd_event(&self) -> (i32, bool) {
116        (self.fd, true)
117    }
118}