#[cfg(any(target_os = "linux", target_os = "android"))]
mod eventfd {
use std::fs::File;
use std::io::{self, Read, Write};
use std::mem;
use std::os::unix::io::FromRawFd;
use crate::event;
use crate::os::{Interests, RegisterOption};
use crate::sys::Selector;
#[derive(Debug)]
pub struct Awakener {
fd: File,
}
impl Awakener {
pub fn new(selector: &Selector, id: event::Id) -> io::Result<Awakener> {
let fd = unsafe { libc::eventfd(0, libc::EFD_CLOEXEC | libc::EFD_NONBLOCK) };
if fd == -1 {
return Err(io::Error::last_os_error());
}
selector.register(fd, id, Interests::READABLE, RegisterOption::EDGE)?;
Ok(Awakener {
fd: unsafe { File::from_raw_fd(fd) },
})
}
pub fn try_clone(&self) -> io::Result<Awakener> {
self.fd.try_clone().map(|fd| Awakener { fd })
}
pub fn wake(&self) -> io::Result<()> {
let buf: [u8; 8] = unsafe { mem::transmute(1u64) };
match (&self.fd).write(&buf) {
Ok(_) => Ok(()),
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.reset()?;
self.wake()
},
Err(err) => Err(err),
}
}
fn reset(&self) -> io::Result<()> {
let mut buf: [u8; 8] = [0; 8];
match (&self.fd).read(&mut buf) {
Ok(_) => Ok(()),
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Ok(()),
Err(err) => Err(err),
}
}
}
}
#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::eventfd::Awakener;
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
mod kqueue {
use std::io;
use crate::event;
use crate::sys::Selector;
#[derive(Debug)]
pub struct Awakener {
selector: Selector,
id: event::Id,
}
impl Awakener {
pub fn new(selector: &Selector, id: event::Id) -> io::Result<Awakener> {
selector.try_clone().and_then(|selector| {
selector.setup_awakener(id)
.map(|()| Awakener { selector, id })
})
}
pub fn try_clone(&self) -> io::Result<Awakener> {
self.selector.try_clone().map(|selector| Awakener {
selector,
id: self.id,
})
}
pub fn wake(&self) -> io::Result<()> {
self.selector.wake(self.id)
}
}
}
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
pub use self::kqueue::Awakener;
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
mod pipe {
use std::fs::File;
use std::io::{self, Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
use crate::event;
use crate::os::{Interests, RegisterOption};
use crate::sys::Selector;
use crate::unix::new_pipe;
#[derive(Debug)]
pub struct Awakener {
sender: File,
receiver: File,
}
impl Awakener {
pub fn new(selector: &Selector, id: event::Id) -> io::Result<Awakener> {
let (sender, receiver) = new_pipe()?;
selector.register(receiver.as_raw_fd(), id, Interests::READABLE, RegisterOption::EDGE)?;
Ok(Awakener {
sender: unsafe { File::from_raw_fd(sender.into_raw_fd()) },
receiver: unsafe { File::from_raw_fd(receiver.into_raw_fd()) },
})
}
pub fn try_clone(&self) -> io::Result<Awakener> {
Ok(Awakener {
sender: self.sender.try_clone()?,
receiver: self.receiver.try_clone()?,
})
}
pub fn wake(&self) -> io::Result<()> {
match (&self.sender).write(&[1]) {
Ok(_) => Ok(()),
Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => {
self.empty();
self.wake()
},
Err(ref err) if err.kind() == io::ErrorKind::Interrupted => self.wake(),
Err(err) => Err(err)
}
}
fn empty(&self) {
let mut buf = [0; 4096];
loop {
match (&self.receiver).read(&mut buf) {
Ok(n) if n > 0 => continue,
_ => return,
}
}
}
}
}
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
pub use self::pipe::Awakener;