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}