1#![cfg(unix)]
5
6use crate::Event;
7use std::os::unix::prelude::*;
8
9pub type Inner = OwnedFd;
10
11fn while_eintr<F, R>(mut f: F) -> std::io::Result<R>
13where
14 F: FnMut() -> std::io::Result<R>,
15{
16 loop {
17 match f() {
18 Err(err) if err.raw_os_error() == Some(libc::EINTR) => {}
19 r => break r,
20 }
21 }
22}
23
24fn syscall_result<T: PartialOrd + Default>(result: T) -> std::io::Result<T> {
25 if result >= T::default() {
26 Ok(result)
27 } else {
28 Err(std::io::Error::last_os_error())
29 }
30}
31
32#[cfg(target_os = "linux")]
33mod eventfd {
34 use super::syscall_result;
35 use super::while_eintr;
36 use crate::Event;
37
38 use std::os::unix::prelude::*;
39
40 impl Event {
41 pub(crate) fn new_inner() -> std::io::Result<Self> {
42 let fd = unsafe {
46 let fd = syscall_result(libc::eventfd(0, libc::EFD_NONBLOCK | libc::EFD_CLOEXEC))?;
47 OwnedFd::from_raw_fd(fd)
48 };
49 Ok(Self(fd))
50 }
51
52 pub(crate) fn try_wait_inner(&self) -> bool {
53 let mut c: u64 = 0;
54 let n = while_eintr(|| unsafe {
56 syscall_result(libc::read(
57 self.0.as_raw_fd(),
58 std::ptr::from_mut(&mut c).cast::<std::ffi::c_void>(),
59 size_of_val(&c),
60 ))
61 });
62 match n {
63 Ok(n) => {
64 assert!(n == size_of_val(&c) as isize);
65 true
66 }
67 Err(err) => {
68 assert_eq!(err.raw_os_error(), Some(libc::EAGAIN));
69 false
70 }
71 }
72 }
73 }
74}
75
76#[cfg(not(target_os = "linux"))]
77mod fifo {
78 use super::syscall_result;
79 use super::while_eintr;
80 use crate::Event;
81 use std::fs::File;
82
83 use std::os::unix::prelude::*;
84
85 impl Event {
86 pub(crate) fn new_inner() -> std::io::Result<Self> {
88 let mut path = std::env::temp_dir();
90 let mut val = [0; 16];
91 getrandom::fill(&mut val).unwrap();
92 path.push(u128::from_ne_bytes(val).to_string());
93
94 let cpath = std::ffi::CString::new(path.as_os_str().as_bytes()).unwrap();
96 syscall_result(unsafe { libc::mkfifo(cpath.as_ptr(), 0o600) })?;
98
99 let fifo = File::options()
101 .read(true)
102 .write(true)
103 .custom_flags(libc::O_NONBLOCK)
104 .open(&path)?;
105
106 let _ = std::fs::remove_file(&path);
108 Ok(Self(fifo.into()))
109 }
110
111 pub(crate) fn try_wait_inner(&self) -> bool {
116 let mut c = [0u8; 512];
117 let n = while_eintr(|| unsafe {
119 syscall_result(libc::read(
120 self.0.as_raw_fd(),
121 c.as_mut_ptr().cast::<std::ffi::c_void>(),
122 size_of_val(&c),
123 ))
124 });
125 match n {
126 Ok(_) => true,
127 Err(err) => {
128 assert_eq!(err.raw_os_error(), Some(libc::EAGAIN));
129 false
130 }
131 }
132 }
133 }
134}
135
136impl Event {
137 pub(crate) fn signal_inner(&self) {
138 let c: u64 = 1;
139 let r = unsafe {
141 syscall_result(libc::write(
142 self.0.as_raw_fd(),
143 std::ptr::from_ref::<u64>(&c).cast::<libc::c_void>(),
144 size_of_val(&c),
145 ))
146 };
147 match r {
148 Ok(n) if n == size_of_val(&c) as isize => {}
149 Err(err) if err.raw_os_error() == Some(libc::EAGAIN) => {}
150 r => {
151 panic!("unexpected event write result: {:?}", r);
152 }
153 }
154 }
155
156 fn poll(&self) {
157 let mut pollfds = [libc::pollfd {
158 fd: self.0.as_raw_fd(),
159 events: libc::POLLIN,
160 revents: 0,
161 }];
162 while_eintr(|| unsafe { syscall_result(libc::poll(pollfds.as_mut_ptr(), 1, !0)) }).unwrap();
164 }
165
166 pub(crate) fn wait_inner(&self) {
167 while !self.try_wait_inner() {
168 self.poll();
169 }
170 }
171}
172
173impl Clone for Event {
174 fn clone(&self) -> Self {
175 Self(self.0.try_clone().expect("out of resources dup eventfd"))
176 }
177}
178
179impl From<OwnedFd> for Event {
180 fn from(fd: OwnedFd) -> Self {
181 Self(fd)
182 }
183}
184
185impl From<Event> for OwnedFd {
186 fn from(event: Event) -> Self {
187 event.0
188 }
189}
190
191impl AsFd for Event {
192 fn as_fd(&self) -> BorrowedFd<'_> {
193 self.0.as_fd()
194 }
195}
196
197#[cfg(feature = "mesh")]
198mesh_protobuf::os_resource!(Event, OwnedFd);