use crate::Error;
use core::mem::{self, MaybeUninit};
use core::ptr;
use crate::platform::inet_pton;
pub struct Waker {
pub fd: i32,
}
impl Drop for Waker {
fn drop(&mut self) {
unsafe { libc::close(self.fd) };
}
}
impl Waker {
pub fn new() -> Result<Self, Error> {
let fd = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
if fd == -1 {
return Err(Error::last_error());
}
let flags = unsafe { libc::fcntl(fd, libc::F_GETFL) } | libc::O_NONBLOCK;
unsafe { libc::fcntl(fd, libc::F_SETFL, flags) };
let mut addr = MaybeUninit::<libc::sockaddr_in>::zeroed();
let addrlen = mem::size_of::<libc::sockaddr_in>() as libc::socklen_t;
let addr = unsafe { addr.assume_init_mut() };
addr.sin_family = libc::AF_INET as libc::sa_family_t;
let paddr = ptr::addr_of_mut!(addr.sin_addr.s_addr) as *mut u8;
let local = b"127.0.0.1\0" as *const u8;
unsafe { inet_pton(libc::AF_INET, local, paddr) };
let ret = unsafe { libc::bind(fd, addr as *const _ as *const libc::sockaddr, addrlen) };
if ret != 0 {
unsafe { libc::close(fd) };
return Err(Error::last_error());
}
Ok(Self { fd })
}
pub fn wake(&self) {
let mut addr = MaybeUninit::<libc::sockaddr_in>::zeroed();
let mut addrlen = mem::size_of_val(&addr) as libc::socklen_t;
unsafe {
libc::getsockname(
self.fd,
addr.as_mut_ptr() as *mut libc::sockaddr,
ptr::addr_of_mut!(addrlen),
)
};
let msg = &self.fd as *const _ as *const libc::c_void;
let msglen = mem::size_of_val(&self.fd);
unsafe {
libc::sendto(
self.fd,
msg,
msglen,
0,
addr.as_ptr() as *const libc::sockaddr,
addrlen,
)
};
}
pub fn awaken(&self) -> bool {
let mut fd = [-1_i32; 2];
let size = unsafe {
libc::recv(
self.fd,
&mut fd as *mut _ as *mut libc::c_void,
mem::size_of_val(&fd),
0,
)
};
size as usize == mem::size_of::<i32>() && fd[0] == self.fd
}
}