1use std::io;
2use std::time::Duration;
3
4#[cfg(unix)]
5use std::os::unix::io::RawFd;
6
7#[cfg(unix)]
12pub struct EventPair {
13 daw_to_host: [RawFd; 2],
14 host_to_daw: [RawFd; 2],
15}
16
17#[cfg(windows)]
18pub struct EventPair {
19 daw_to_host: *mut std::ffi::c_void,
20 host_to_daw: *mut std::ffi::c_void,
21 daw_to_host_name: String,
22 host_to_daw_name: String,
23}
24
25unsafe impl Send for EventPair {}
26unsafe impl Sync for EventPair {}
27
28#[cfg(unix)]
29impl EventPair {
30 pub fn new() -> io::Result<Self> {
32 let mut daw_to_host = [0; 2];
33 let mut host_to_daw = [0; 2];
34 if unsafe { libc::pipe(daw_to_host.as_mut_ptr()) } != 0 {
35 return Err(io::Error::last_os_error());
36 }
37 if unsafe { libc::pipe(host_to_daw.as_mut_ptr()) } != 0 {
38 unsafe {
39 libc::close(daw_to_host[0]);
40 libc::close(daw_to_host[1]);
41 }
42 return Err(io::Error::last_os_error());
43 }
44 Ok(Self {
45 daw_to_host,
46 host_to_daw,
47 })
48 }
49
50 pub unsafe fn from_fds(daw_to_host_read: RawFd, host_to_daw_write: RawFd) -> Self {
54 let mut pair = Self {
55 daw_to_host: [daw_to_host_read, -1],
56 host_to_daw: [-1, host_to_daw_write],
57 };
58 pair.close_host_unused();
59 pair
60 }
61
62 pub fn daw_write_fd(&self) -> RawFd {
63 self.daw_to_host[1]
64 }
65
66 pub fn daw_read_fd(&self) -> RawFd {
67 self.host_to_daw[0]
68 }
69
70 pub fn host_read_fd(&self) -> RawFd {
71 self.daw_to_host[0]
72 }
73
74 pub fn host_write_fd(&self) -> RawFd {
75 self.host_to_daw[1]
76 }
77
78 pub fn signal_host(&self) -> io::Result<()> {
80 write_byte(self.daw_to_host[1])
81 }
82
83 pub fn wait_host(&self, timeout: Duration) -> io::Result<()> {
85 read_byte(self.host_to_daw[0], timeout)
86 }
87
88 pub fn wait_daw(&self, timeout: Duration) -> io::Result<()> {
90 read_byte(self.daw_to_host[0], timeout)
91 }
92
93 pub fn signal_daw(&self) -> io::Result<()> {
95 write_byte(self.host_to_daw[1])
96 }
97
98 pub fn close_daw_unused(&mut self) {
100 unsafe {
101 libc::close(self.daw_to_host[0]);
102 libc::close(self.host_to_daw[1]);
103 }
104 self.daw_to_host[0] = -1;
105 self.host_to_daw[1] = -1;
106 }
107
108 pub fn close_host_unused(&mut self) {
110 unsafe {
111 libc::close(self.daw_to_host[1]);
112 libc::close(self.host_to_daw[0]);
113 }
114 self.daw_to_host[1] = -1;
115 self.host_to_daw[0] = -1;
116 }
117}
118
119#[cfg(unix)]
120impl Drop for EventPair {
121 fn drop(&mut self) {
122 unsafe {
123 libc::close(self.daw_to_host[0]);
124 libc::close(self.daw_to_host[1]);
125 libc::close(self.host_to_daw[0]);
126 libc::close(self.host_to_daw[1]);
127 }
128 }
129}
130
131#[cfg(unix)]
132fn write_byte(fd: RawFd) -> io::Result<()> {
133 let buf = [1u8];
134 let n = unsafe { libc::write(fd, buf.as_ptr().cast(), 1) };
135 if n < 0 {
136 Err(io::Error::last_os_error())
137 } else {
138 Ok(())
139 }
140}
141
142#[cfg(unix)]
143fn read_byte(fd: RawFd, timeout: Duration) -> io::Result<()> {
144 let mut pfd = libc::pollfd {
145 fd,
146 events: libc::POLLIN,
147 revents: 0,
148 };
149 let ms = timeout.as_millis().clamp(0, i32::MAX as u128) as i32;
150 let rc = unsafe { libc::poll(&mut pfd, 1, ms) };
151 if rc < 0 {
152 return Err(io::Error::last_os_error());
153 }
154 if rc == 0 {
155 return Err(io::Error::new(io::ErrorKind::TimedOut, "poll timeout"));
156 }
157 let mut buf = [0u8; 1];
158 let n = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), 1) };
159 if n < 0 {
160 Err(io::Error::last_os_error())
161 } else {
162 Ok(())
163 }
164}
165
166#[cfg(windows)]
167impl EventPair {
168 pub fn new() -> io::Result<Self> {
170 use windows_sys::Win32::Foundation::GetLastError;
171 use windows_sys::Win32::System::Threading::CreateEventW;
172
173 let pid = std::process::id();
174 let nonce = std::time::SystemTime::now()
175 .duration_since(std::time::UNIX_EPOCH)
176 .unwrap_or_default()
177 .as_nanos();
178 let daw_to_host_name = format!("Local\\maolan-d2h-{}-{}", pid, nonce);
179 let host_to_daw_name = format!("Local\\maolan-h2d-{}-{}", pid, nonce);
180
181 let d2h_wide: Vec<u16> = daw_to_host_name
182 .encode_utf16()
183 .chain(std::iter::once(0))
184 .collect();
185 let h2d_wide: Vec<u16> = host_to_daw_name
186 .encode_utf16()
187 .chain(std::iter::once(0))
188 .collect();
189
190 let daw_to_host = unsafe { CreateEventW(std::ptr::null_mut(), 0, 0, d2h_wide.as_ptr()) };
191 if daw_to_host.is_null() {
192 return Err(io::Error::new(
193 io::ErrorKind::Other,
194 format!("CreateEventW failed: {}", unsafe { GetLastError() }),
195 ));
196 }
197 let host_to_daw = unsafe { CreateEventW(std::ptr::null_mut(), 0, 0, h2d_wide.as_ptr()) };
198 if host_to_daw.is_null() {
199 unsafe { windows_sys::Win32::Foundation::CloseHandle(daw_to_host) };
200 return Err(io::Error::new(
201 io::ErrorKind::Other,
202 format!("CreateEventW failed: {}", unsafe { GetLastError() }),
203 ));
204 }
205
206 Ok(Self {
207 daw_to_host,
208 host_to_daw,
209 daw_to_host_name,
210 host_to_daw_name,
211 })
212 }
213
214 pub fn from_names(daw_to_host_name: &str, host_to_daw_name: &str) -> io::Result<Self> {
216 use windows_sys::Win32::Foundation::GetLastError;
217 use windows_sys::Win32::System::Threading::OpenEventW;
218
219 let d2h_wide: Vec<u16> = daw_to_host_name
220 .encode_utf16()
221 .chain(std::iter::once(0))
222 .collect();
223 let h2d_wide: Vec<u16> = host_to_daw_name
224 .encode_utf16()
225 .chain(std::iter::once(0))
226 .collect();
227
228 let daw_to_host = unsafe {
229 OpenEventW(
230 windows_sys::Win32::System::Threading::EVENT_ALL_ACCESS,
231 0,
232 d2h_wide.as_ptr(),
233 )
234 };
235 if daw_to_host.is_null() {
236 return Err(io::Error::new(
237 io::ErrorKind::Other,
238 format!("OpenEventW failed: {}", unsafe { GetLastError() }),
239 ));
240 }
241 let host_to_daw = unsafe {
242 OpenEventW(
243 windows_sys::Win32::System::Threading::EVENT_ALL_ACCESS,
244 0,
245 h2d_wide.as_ptr(),
246 )
247 };
248 if host_to_daw.is_null() {
249 unsafe { windows_sys::Win32::Foundation::CloseHandle(daw_to_host) };
250 return Err(io::Error::new(
251 io::ErrorKind::Other,
252 format!("OpenEventW failed: {}", unsafe { GetLastError() }),
253 ));
254 }
255
256 Ok(Self {
257 daw_to_host,
258 host_to_daw,
259 daw_to_host_name: daw_to_host_name.to_string(),
260 host_to_daw_name: host_to_daw_name.to_string(),
261 })
262 }
263
264 pub fn daw_to_host_name(&self) -> &str {
265 &self.daw_to_host_name
266 }
267
268 pub fn host_to_daw_name(&self) -> &str {
269 &self.host_to_daw_name
270 }
271
272 pub fn signal_host(&self) -> io::Result<()> {
274 use windows_sys::Win32::Foundation::GetLastError;
275 use windows_sys::Win32::System::Threading::SetEvent;
276 if unsafe { SetEvent(self.daw_to_host) } == 0 {
277 return Err(io::Error::new(
278 io::ErrorKind::Other,
279 format!("SetEvent failed: {}", unsafe { GetLastError() }),
280 ));
281 }
282 Ok(())
283 }
284
285 pub fn wait_host(&self, timeout: Duration) -> io::Result<()> {
287 self.wait_object(self.host_to_daw, timeout)
288 }
289
290 pub fn wait_daw(&self, timeout: Duration) -> io::Result<()> {
292 self.wait_object(self.daw_to_host, timeout)
293 }
294
295 pub fn wait_daw_with_message_pump(&self, timeout: Duration) -> io::Result<()> {
297 use windows_sys::Win32::Foundation::{GetLastError, WAIT_OBJECT_0, WAIT_TIMEOUT};
298 use windows_sys::Win32::UI::WindowsAndMessaging::{
299 DispatchMessageW, MSG, MsgWaitForMultipleObjects, PM_REMOVE, PeekMessageW, QS_ALLINPUT,
300 TranslateMessage,
301 };
302
303 let start = std::time::Instant::now();
304 let handles = [self.daw_to_host];
305 let ms_total = timeout.as_millis().clamp(0, u32::MAX as u128) as u32;
306
307 loop {
308 let elapsed = start.elapsed().as_millis().clamp(0, u32::MAX as u128) as u32;
309 let remaining = ms_total.saturating_sub(elapsed);
310
311 let rc = unsafe {
312 MsgWaitForMultipleObjects(1, handles.as_ptr(), 0, remaining, QS_ALLINPUT)
313 };
314
315 if rc == WAIT_OBJECT_0 {
316 return Ok(());
317 } else if rc == WAIT_OBJECT_0 + 1 {
318 unsafe {
319 let mut msg: MSG = std::mem::zeroed();
320 while PeekMessageW(&mut msg, std::ptr::null_mut(), 0, 0, PM_REMOVE) != 0 {
321 TranslateMessage(&msg);
322 DispatchMessageW(&msg);
323 }
324 }
325 } else if rc == WAIT_TIMEOUT {
326 return Err(io::Error::new(
327 io::ErrorKind::TimedOut,
328 "MsgWaitForMultipleObjects timeout",
329 ));
330 } else {
331 return Err(io::Error::new(
332 io::ErrorKind::Other,
333 format!("MsgWaitForMultipleObjects failed: {}", unsafe {
334 GetLastError()
335 }),
336 ));
337 }
338 }
339 }
340
341 pub fn signal_daw(&self) -> io::Result<()> {
343 use windows_sys::Win32::Foundation::GetLastError;
344 use windows_sys::Win32::System::Threading::SetEvent;
345 if unsafe { SetEvent(self.host_to_daw) } == 0 {
346 return Err(io::Error::new(
347 io::ErrorKind::Other,
348 format!("SetEvent failed: {}", unsafe { GetLastError() }),
349 ));
350 }
351 Ok(())
352 }
353
354 pub fn close_daw_unused(&mut self) {}
356
357 pub fn close_host_unused(&mut self) {}
359
360 fn wait_object(&self, handle: *mut std::ffi::c_void, timeout: Duration) -> io::Result<()> {
361 use windows_sys::Win32::Foundation::{GetLastError, WAIT_OBJECT_0, WAIT_TIMEOUT};
362 use windows_sys::Win32::System::Threading::WaitForSingleObject;
363
364 let ms = timeout.as_millis().clamp(0, u32::MAX as u128) as u32;
365 let rc = unsafe { WaitForSingleObject(handle, ms) };
366 if rc == WAIT_OBJECT_0 {
367 Ok(())
368 } else if rc == WAIT_TIMEOUT {
369 Err(io::Error::new(
370 io::ErrorKind::TimedOut,
371 "WaitForSingleObject timeout",
372 ))
373 } else {
374 Err(io::Error::new(
375 io::ErrorKind::Other,
376 format!("WaitForSingleObject failed: {}", unsafe { GetLastError() }),
377 ))
378 }
379 }
380}
381
382#[cfg(windows)]
383impl Drop for EventPair {
384 fn drop(&mut self) {
385 use windows_sys::Win32::Foundation::CloseHandle;
386 if !self.daw_to_host.is_null() {
387 unsafe { CloseHandle(self.daw_to_host) };
388 }
389 if !self.host_to_daw.is_null() {
390 unsafe { CloseHandle(self.host_to_daw) };
391 }
392 }
393}