route_manager/unix/
shutdown.rs1use crate::RouteListener;
2use std::io;
3use std::os::fd::AsRawFd;
4use std::sync::atomic::{AtomicBool, Ordering};
5use std::sync::Arc;
6
7#[cfg(any(target_os = "linux", target_os = "freebsd"))]
8pub(crate) struct EventFd(std::fs::File);
9#[cfg(any(target_os = "linux", target_os = "freebsd"))]
10impl EventFd {
11 pub(crate) fn new() -> io::Result<Self> {
12 #[cfg(not(target_os = "espidf"))]
13 let flags = libc::EFD_CLOEXEC | libc::EFD_NONBLOCK;
14 #[cfg(target_os = "espidf")]
16 let flags = 0;
17 let event_fd = unsafe { libc::eventfd(0, flags) };
18 if event_fd < 0 {
19 return Err(io::Error::last_os_error());
20 }
21 use std::os::fd::FromRawFd;
22 let file = unsafe { std::fs::File::from_raw_fd(event_fd) };
23 Ok(Self(file))
24 }
25 fn wake(&self) -> io::Result<()> {
26 use std::io::Write;
27 let buf: [u8; 8] = 1u64.to_ne_bytes();
28 match (&self.0).write_all(&buf) {
29 Ok(_) => Ok(()),
30 Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Ok(()),
31 Err(err) => Err(err),
32 }
33 }
34 fn as_event_fd(&self) -> libc::c_int {
35 self.0.as_raw_fd() as _
36 }
37}
38#[cfg(target_os = "macos")]
39struct EventFd(libc::c_int, libc::c_int);
40#[cfg(target_os = "macos")]
41impl EventFd {
42 fn new() -> io::Result<Self> {
43 let mut fds: [libc::c_int; 2] = [0; 2];
44 if unsafe { libc::pipe(fds.as_mut_ptr()) } == -1 {
45 return Err(io::Error::last_os_error());
46 }
47 let read_fd = fds[0];
48 let write_fd = fds[1];
49 Ok(Self(read_fd, write_fd))
50 }
51 fn wake(&self) -> io::Result<()> {
52 let buf: [u8; 8] = 1u64.to_ne_bytes();
53 let res = unsafe { libc::write(self.1, buf.as_ptr() as *const libc::c_void, buf.len()) };
54 if res == -1 {
55 Err(io::Error::last_os_error())
56 } else {
57 Ok(())
58 }
59 }
60 fn as_event_fd(&self) -> libc::c_int {
61 self.0
62 }
63}
64#[cfg(target_os = "macos")]
65impl Drop for EventFd {
66 fn drop(&mut self) {
67 unsafe {
68 let _ = libc::close(self.0);
69 let _ = libc::close(self.1);
70 }
71 }
72}
73impl RouteListener {
74 pub(crate) fn wait(&self) -> io::Result<()> {
75 let fd = self.as_raw_fd() as libc::c_int;
76
77 let event_fd = self.shutdown_handle.event_fd.as_event_fd();
78 let mut readfds: libc::fd_set = unsafe { std::mem::zeroed() };
79 unsafe {
80 libc::FD_SET(fd, &mut readfds);
81 libc::FD_SET(event_fd, &mut readfds);
82 }
83 let result = unsafe {
84 libc::select(
85 fd.max(event_fd) + 1,
86 &mut readfds,
87 std::ptr::null_mut(),
88 std::ptr::null_mut(),
89 std::ptr::null_mut(),
90 )
91 };
92 if self.shutdown_handle.is_shutdown.load(Ordering::Relaxed) {
93 return Err(io::Error::new(io::ErrorKind::Interrupted, "shutdown"));
94 }
95 if result == -1 {
96 return Err(io::Error::last_os_error());
97 }
98 if result == 0 {
99 return Err(io::Error::from(io::ErrorKind::TimedOut));
100 }
101 Ok(())
102 }
103 pub fn shutdown_handle(&self) -> io::Result<RouteListenerShutdown> {
105 Ok(self.shutdown_handle.clone())
106 }
107}
108
109#[derive(Clone)]
111pub struct RouteListenerShutdown {
112 is_shutdown: Arc<AtomicBool>,
113 event_fd: Arc<EventFd>,
114}
115impl RouteListenerShutdown {
116 pub(crate) fn new() -> io::Result<Self> {
117 Ok(Self {
118 is_shutdown: Arc::new(Default::default()),
119 event_fd: Arc::new(EventFd::new()?),
120 })
121 }
122 pub fn shutdown(&self) -> io::Result<()> {
124 self.is_shutdown.store(true, Ordering::Relaxed);
125 self.event_fd.wake()
126 }
127}