mirror of https://github.com/stjepang/smol
Merge pull request #133 from dignifiedquire/isolate-nix
refactor: replace nix with libc
This commit is contained in:
commit
c5e5c25952
|
@ -44,7 +44,7 @@ features = ["rt-threaded"]
|
|||
optional = true
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix = "0.17.0"
|
||||
libc = "0.2.70"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
wepoll-binding = "2.0.2"
|
||||
|
|
|
@ -678,7 +678,7 @@ impl Async<TcpStream> {
|
|||
socket.connect(&addr.into()).or_else(|err| {
|
||||
// Check for EINPROGRESS on Unix and WSAEWOULDBLOCK on Windows.
|
||||
#[cfg(unix)]
|
||||
let in_progress = err.raw_os_error() == Some(nix::libc::EINPROGRESS);
|
||||
let in_progress = err.raw_os_error() == Some(libc::EINPROGRESS);
|
||||
#[cfg(windows)]
|
||||
let in_progress = err.kind() == io::ErrorKind::WouldBlock;
|
||||
|
||||
|
@ -1006,7 +1006,7 @@ impl Async<UnixStream> {
|
|||
socket
|
||||
.connect(&socket2::SockAddr::unix(path)?)
|
||||
.or_else(|err| {
|
||||
if err.raw_os_error() == Some(nix::libc::EINPROGRESS) {
|
||||
if err.raw_os_error() == Some(libc::EINPROGRESS) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
|
|
|
@ -114,19 +114,20 @@ fn notifier() -> io::Result<(Socket, Socket)> {
|
|||
#[cfg(target_os = "linux")]
|
||||
mod linux {
|
||||
use super::*;
|
||||
use nix::sys::eventfd::{eventfd, EfdFlags};
|
||||
use crate::sys::eventfd::eventfd;
|
||||
use crate::sys::unistd;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
pub(crate) struct EventFd(std::os::unix::io::RawFd);
|
||||
|
||||
impl EventFd {
|
||||
pub fn new() -> Result<Self, std::io::Error> {
|
||||
let fd = eventfd(0, EfdFlags::EFD_CLOEXEC | EfdFlags::EFD_NONBLOCK).map_err(io_err)?;
|
||||
let fd = eventfd(0, libc::EFD_CLOEXEC | libc::EFD_NONBLOCK)?;
|
||||
Ok(EventFd(fd))
|
||||
}
|
||||
|
||||
pub fn try_clone(&self) -> Result<EventFd, io::Error> {
|
||||
nix::unistd::dup(self.0).map(EventFd).map_err(io_err)
|
||||
unistd::dup(self.0).map(EventFd)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,28 +139,21 @@ mod linux {
|
|||
|
||||
impl Drop for EventFd {
|
||||
fn drop(&mut self) {
|
||||
let _ = nix::unistd::close(self.0);
|
||||
}
|
||||
}
|
||||
|
||||
fn io_err(err: nix::Error) -> io::Error {
|
||||
match err {
|
||||
nix::Error::Sys(code) => code.into(),
|
||||
err => io::Error::new(io::ErrorKind::Other, Box::new(err)),
|
||||
let _ = unistd::close(self.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for &EventFd {
|
||||
#[inline]
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
|
||||
nix::unistd::read(self.0, buf).map_err(io_err)
|
||||
unistd::read(self.0, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for &EventFd {
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, std::io::Error> {
|
||||
nix::unistd::write(self.0, buf).map_err(io_err)
|
||||
unistd::write(self.0, buf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -122,6 +122,7 @@ mod context;
|
|||
mod io_event;
|
||||
mod reactor;
|
||||
mod run;
|
||||
mod sys;
|
||||
mod task;
|
||||
mod thread_local;
|
||||
mod throttle;
|
||||
|
|
120
src/reactor.rs
120
src/reactor.rs
|
@ -32,13 +32,14 @@ use std::time::{Duration, Instant};
|
|||
|
||||
use crossbeam_queue::ArrayQueue;
|
||||
use futures_util::future;
|
||||
#[cfg(unix)]
|
||||
use nix::fcntl::{fcntl, FcntlArg, OFlag};
|
||||
use once_cell::sync::Lazy;
|
||||
use slab::Slab;
|
||||
#[cfg(windows)]
|
||||
use socket2::Socket;
|
||||
|
||||
#[cfg(unix)]
|
||||
use crate::sys::fcntl::{fcntl, FcntlArg};
|
||||
|
||||
use crate::io_event::IoEvent;
|
||||
|
||||
/// The reactor.
|
||||
|
@ -103,9 +104,9 @@ impl Reactor {
|
|||
// Put the I/O handle in non-blocking mode.
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let flags = fcntl(raw, FcntlArg::F_GETFL).map_err(io_err)?;
|
||||
let flags = OFlag::from_bits_truncate(flags) | OFlag::O_NONBLOCK;
|
||||
fcntl(raw, FcntlArg::F_SETFL(flags)).map_err(io_err)?;
|
||||
let flags = fcntl(raw, FcntlArg::F_GETFL)?;
|
||||
let flags = flags | libc::O_NONBLOCK;
|
||||
fcntl(raw, FcntlArg::F_SETFL(flags))?;
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
|
@ -429,15 +430,6 @@ impl Source {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts a [`nix::Error`] into [`io::Error`].
|
||||
#[cfg(unix)]
|
||||
fn io_err(err: nix::Error) -> io::Error {
|
||||
match err {
|
||||
nix::Error::Sys(code) => code.into(),
|
||||
err => io::Error::new(io::ErrorKind::Other, Box::new(err)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw bindings to epoll (Linux, Android, illumos).
|
||||
#[cfg(any(target_os = "linux", target_os = "android", target_os = "illumos"))]
|
||||
mod sys {
|
||||
|
@ -446,24 +438,22 @@ mod sys {
|
|||
use std::os::unix::io::RawFd;
|
||||
use std::time::Duration;
|
||||
|
||||
use nix::sys::epoll::{
|
||||
epoll_create1, epoll_ctl, epoll_wait, EpollCreateFlags, EpollEvent, EpollFlags, EpollOp,
|
||||
use crate::sys::epoll::{
|
||||
epoll_create1, epoll_ctl, epoll_wait, EpollEvent, EpollFlags, EpollOp,
|
||||
};
|
||||
|
||||
use super::io_err;
|
||||
|
||||
pub struct Reactor(RawFd);
|
||||
impl Reactor {
|
||||
pub fn new() -> io::Result<Reactor> {
|
||||
let epoll_fd = epoll_create1(EpollCreateFlags::EPOLL_CLOEXEC).map_err(io_err)?;
|
||||
let epoll_fd = epoll_create1()?;
|
||||
Ok(Reactor(epoll_fd))
|
||||
}
|
||||
pub fn register(&self, fd: RawFd, key: usize) -> io::Result<()> {
|
||||
let ev = &mut EpollEvent::new(EpollFlags::empty(), key as u64);
|
||||
epoll_ctl(self.0, EpollOp::EpollCtlAdd, fd, Some(ev)).map_err(io_err)
|
||||
let ev = &mut EpollEvent::new(0, key as u64);
|
||||
epoll_ctl(self.0, EpollOp::EpollCtlAdd, fd, Some(ev))
|
||||
}
|
||||
pub fn reregister(&self, fd: RawFd, key: usize, read: bool, write: bool) -> io::Result<()> {
|
||||
let mut flags = EpollFlags::EPOLLONESHOT;
|
||||
let mut flags = libc::EPOLLONESHOT;
|
||||
if read {
|
||||
flags |= read_flags();
|
||||
}
|
||||
|
@ -471,10 +461,10 @@ mod sys {
|
|||
flags |= write_flags();
|
||||
}
|
||||
let ev = &mut EpollEvent::new(flags, key as u64);
|
||||
epoll_ctl(self.0, EpollOp::EpollCtlMod, fd, Some(ev)).map_err(io_err)
|
||||
epoll_ctl(self.0, EpollOp::EpollCtlMod, fd, Some(ev))
|
||||
}
|
||||
pub fn deregister(&self, fd: RawFd) -> io::Result<()> {
|
||||
epoll_ctl(self.0, EpollOp::EpollCtlDel, fd, None).map_err(io_err)
|
||||
epoll_ctl(self.0, EpollOp::EpollCtlDel, fd, None)
|
||||
}
|
||||
pub fn wait(&self, events: &mut Events, timeout: Option<Duration>) -> io::Result<usize> {
|
||||
let timeout_ms = timeout
|
||||
|
@ -487,15 +477,15 @@ mod sys {
|
|||
})
|
||||
.and_then(|t| t.as_millis().try_into().ok())
|
||||
.unwrap_or(-1);
|
||||
events.len = epoll_wait(self.0, &mut events.list, timeout_ms).map_err(io_err)?;
|
||||
events.len = epoll_wait(self.0, &mut events.list, timeout_ms)?;
|
||||
Ok(events.len)
|
||||
}
|
||||
}
|
||||
fn read_flags() -> EpollFlags {
|
||||
EpollFlags::EPOLLIN | EpollFlags::EPOLLRDHUP
|
||||
libc::EPOLLIN | libc::EPOLLRDHUP
|
||||
}
|
||||
fn write_flags() -> EpollFlags {
|
||||
EpollFlags::EPOLLOUT
|
||||
libc::EPOLLOUT
|
||||
}
|
||||
|
||||
pub struct Events {
|
||||
|
@ -510,8 +500,8 @@ mod sys {
|
|||
}
|
||||
pub fn iter(&self) -> impl Iterator<Item = Event> + '_ {
|
||||
self.list[..self.len].iter().map(|ev| Event {
|
||||
readable: ev.events().intersects(read_flags()),
|
||||
writable: ev.events().intersects(write_flags()),
|
||||
readable: (ev.events() & read_flags()) > 0,
|
||||
writable: (ev.events() & write_flags()) > 0,
|
||||
key: ev.data() as usize,
|
||||
})
|
||||
}
|
||||
|
@ -537,64 +527,46 @@ mod sys {
|
|||
use std::os::unix::io::RawFd;
|
||||
use std::time::Duration;
|
||||
|
||||
use nix::errno::Errno;
|
||||
use nix::fcntl::{fcntl, FcntlArg, FdFlag};
|
||||
use nix::libc;
|
||||
use nix::sys::event::{kevent_ts, kqueue, EventFilter, EventFlag, FilterFlag, KEvent};
|
||||
|
||||
use super::io_err;
|
||||
use crate::sys::event::{kevent_ts, kqueue, FilterFlag, KEvent};
|
||||
use crate::sys::fcntl::{fcntl, FcntlArg};
|
||||
|
||||
pub struct Reactor(RawFd);
|
||||
impl Reactor {
|
||||
pub fn new() -> io::Result<Reactor> {
|
||||
let fd = kqueue().map_err(io_err)?;
|
||||
fcntl(fd, FcntlArg::F_SETFD(FdFlag::FD_CLOEXEC)).map_err(io_err)?;
|
||||
let fd = kqueue()?;
|
||||
fcntl(fd, FcntlArg::F_SETFD(libc::FD_CLOEXEC))?;
|
||||
Ok(Reactor(fd))
|
||||
}
|
||||
pub fn register(&self, _fd: RawFd, _key: usize) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
pub fn reregister(&self, fd: RawFd, key: usize, read: bool, write: bool) -> io::Result<()> {
|
||||
let mut read_flags = EventFlag::EV_ONESHOT | EventFlag::EV_RECEIPT;
|
||||
let mut write_flags = EventFlag::EV_ONESHOT | EventFlag::EV_RECEIPT;
|
||||
let mut read_flags = libc::EV_ONESHOT | libc::EV_RECEIPT;
|
||||
let mut write_flags = libc::EV_ONESHOT | libc::EV_RECEIPT;
|
||||
if read {
|
||||
read_flags |= EventFlag::EV_ADD;
|
||||
read_flags |= libc::EV_ADD;
|
||||
} else {
|
||||
read_flags |= EventFlag::EV_DELETE;
|
||||
read_flags |= libc::EV_DELETE;
|
||||
}
|
||||
if write {
|
||||
write_flags |= EventFlag::EV_ADD;
|
||||
write_flags |= libc::EV_ADD;
|
||||
} else {
|
||||
write_flags |= EventFlag::EV_DELETE;
|
||||
write_flags |= libc::EV_DELETE;
|
||||
}
|
||||
let udata = key as _;
|
||||
let changelist = [
|
||||
KEvent::new(
|
||||
fd as _,
|
||||
EventFilter::EVFILT_READ,
|
||||
read_flags,
|
||||
FFLAGS,
|
||||
0,
|
||||
udata,
|
||||
),
|
||||
KEvent::new(
|
||||
fd as _,
|
||||
EventFilter::EVFILT_WRITE,
|
||||
write_flags,
|
||||
FFLAGS,
|
||||
0,
|
||||
udata,
|
||||
),
|
||||
KEvent::new(fd as _, libc::EVFILT_READ, read_flags, FFLAGS, 0, udata),
|
||||
KEvent::new(fd as _, libc::EVFILT_WRITE, write_flags, FFLAGS, 0, udata),
|
||||
];
|
||||
let mut eventlist = changelist;
|
||||
kevent_ts(self.0, &changelist, &mut eventlist, None).map_err(io_err)?;
|
||||
kevent_ts(self.0, &changelist, &mut eventlist, None)?;
|
||||
for ev in &eventlist {
|
||||
// Explanation for ignoring EPIPE: https://github.com/tokio-rs/mio/issues/582
|
||||
let (flags, data) = (ev.flags(), ev.data());
|
||||
if flags.contains(EventFlag::EV_ERROR)
|
||||
if (flags & libc::EV_ERROR) == 1
|
||||
&& data != 0
|
||||
&& data != Errno::ENOENT as _
|
||||
&& data != Errno::EPIPE as _
|
||||
&& data != libc::ENOENT as _
|
||||
&& data != libc::EPIPE as _
|
||||
{
|
||||
return Err(io::Error::from_raw_os_error(data as _));
|
||||
}
|
||||
|
@ -602,16 +574,16 @@ mod sys {
|
|||
Ok(())
|
||||
}
|
||||
pub fn deregister(&self, fd: RawFd) -> io::Result<()> {
|
||||
let flags = EventFlag::EV_RECEIPT | EventFlag::EV_DELETE;
|
||||
let flags = libc::EV_RECEIPT | libc::EV_DELETE;
|
||||
let changelist = [
|
||||
KEvent::new(fd as _, EventFilter::EVFILT_WRITE, flags, FFLAGS, 0, 0),
|
||||
KEvent::new(fd as _, EventFilter::EVFILT_READ, flags, FFLAGS, 0, 0),
|
||||
KEvent::new(fd as _, libc::EVFILT_WRITE, flags, FFLAGS, 0, 0),
|
||||
KEvent::new(fd as _, libc::EVFILT_READ, flags, FFLAGS, 0, 0),
|
||||
];
|
||||
let mut eventlist = changelist;
|
||||
kevent_ts(self.0, &changelist, &mut eventlist, None).map_err(io_err)?;
|
||||
kevent_ts(self.0, &changelist, &mut eventlist, None)?;
|
||||
for ev in &eventlist {
|
||||
let (flags, data) = (ev.flags(), ev.data());
|
||||
if flags.contains(EventFlag::EV_ERROR) && data != 0 && data != Errno::ENOENT as _ {
|
||||
if (flags & libc::EV_ERROR == 1) && data != 0 && data != libc::ENOENT as _ {
|
||||
return Err(io::Error::from_raw_os_error(data as _));
|
||||
}
|
||||
}
|
||||
|
@ -622,11 +594,11 @@ mod sys {
|
|||
tv_sec: t.as_secs() as libc::time_t,
|
||||
tv_nsec: t.subsec_nanos() as libc::c_long,
|
||||
});
|
||||
events.len = kevent_ts(self.0, &[], &mut events.list, timeout).map_err(io_err)?;
|
||||
events.len = kevent_ts(self.0, &[], &mut events.list, timeout)?;
|
||||
Ok(events.len)
|
||||
}
|
||||
}
|
||||
const FFLAGS: FilterFlag = FilterFlag::empty();
|
||||
const FFLAGS: FilterFlag = 0;
|
||||
|
||||
pub struct Events {
|
||||
list: Box<[KEvent]>,
|
||||
|
@ -634,16 +606,16 @@ mod sys {
|
|||
}
|
||||
impl Events {
|
||||
pub fn new() -> Events {
|
||||
let flags = EventFlag::empty();
|
||||
let event = KEvent::new(0, EventFilter::EVFILT_USER, flags, FFLAGS, 0, 0);
|
||||
let flags = 0;
|
||||
let event = KEvent::new(0, libc::EVFILT_USER, flags, FFLAGS, 0, 0);
|
||||
let list = vec![event; 1000].into_boxed_slice();
|
||||
let len = 0;
|
||||
Events { list, len }
|
||||
}
|
||||
pub fn iter(&self) -> impl Iterator<Item = Event> + '_ {
|
||||
self.list[..self.len].iter().map(|ev| Event {
|
||||
readable: ev.filter() == EventFilter::EVFILT_READ,
|
||||
writable: ev.filter() == EventFilter::EVFILT_WRITE,
|
||||
readable: ev.filter() == libc::EVFILT_READ,
|
||||
writable: ev.filter() == libc::EVFILT_WRITE,
|
||||
key: ev.udata() as usize,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,414 @@
|
|||
#[cfg(target_os = "linux")]
|
||||
pub mod eventfd {
|
||||
use super::check_err;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
pub type EfdFlags = libc::c_int;
|
||||
|
||||
pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd, std::io::Error> {
|
||||
let res = unsafe { libc::eventfd(initval, flags) };
|
||||
|
||||
check_err(res).map(|r| r as RawFd)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod unistd {
|
||||
use super::check_err;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
pub fn close(fd: RawFd) -> Result<(), std::io::Error> {
|
||||
let res = unsafe { libc::close(fd) };
|
||||
|
||||
check_err(res).map(drop)
|
||||
}
|
||||
|
||||
pub fn dup(oldfd: RawFd) -> Result<RawFd, std::io::Error> {
|
||||
let res = unsafe { libc::dup(oldfd) };
|
||||
check_err(res)
|
||||
}
|
||||
|
||||
pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize, std::io::Error> {
|
||||
let res = unsafe {
|
||||
libc::read(
|
||||
fd,
|
||||
buf.as_mut_ptr() as *mut libc::c_void,
|
||||
buf.len() as libc::size_t,
|
||||
)
|
||||
};
|
||||
|
||||
check_err(res as _).map(|r| r as usize)
|
||||
}
|
||||
|
||||
pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize, std::io::Error> {
|
||||
let res = unsafe {
|
||||
libc::write(
|
||||
fd,
|
||||
buf.as_ptr() as *const libc::c_void,
|
||||
buf.len() as libc::size_t,
|
||||
)
|
||||
};
|
||||
|
||||
check_err(res as _).map(|r| r as usize)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub mod fcntl {
|
||||
use super::check_err;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
pub type OFlag = libc::c_int;
|
||||
pub type FdFlag = libc::c_int;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(dead_code)]
|
||||
/// Arguments passed to `fcntl`.
|
||||
pub enum FcntlArg {
|
||||
F_GETFL,
|
||||
F_SETFL(OFlag),
|
||||
F_SETFD(FdFlag),
|
||||
}
|
||||
|
||||
/// Thin wrapper around `libc::fcntl`.
|
||||
///
|
||||
/// See [`fcntl(2)`](http://man7.org/linux/man-pages/man2/fcntl.2.html) for details.
|
||||
pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<libc::c_int, std::io::Error> {
|
||||
let res = unsafe {
|
||||
match arg {
|
||||
FcntlArg::F_GETFL => libc::fcntl(fd, libc::F_GETFL),
|
||||
FcntlArg::F_SETFL(flag) => libc::fcntl(fd, libc::F_SETFL, flag),
|
||||
FcntlArg::F_SETFD(flag) => libc::fcntl(fd, libc::F_SETFD, flag),
|
||||
}
|
||||
};
|
||||
check_err(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn check_err(res: libc::c_int) -> Result<libc::c_int, std::io::Error> {
|
||||
if res == -1 {
|
||||
return Err(std::io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly",
|
||||
))]
|
||||
/// Kqueue.
|
||||
pub mod event {
|
||||
use super::check_err;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[allow(non_camel_case_types)]
|
||||
type type_of_nchanges = libc::c_int;
|
||||
#[cfg(target_os = "netbsd")]
|
||||
#[allow(non_camel_case_types)]
|
||||
type type_of_nchanges = libc::size_t;
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
#[allow(non_camel_case_types)]
|
||||
type type_of_event_filter = u32;
|
||||
#[cfg(not(target_os = "netbsd"))]
|
||||
#[allow(non_camel_case_types)]
|
||||
type type_of_event_filter = i16;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
#[allow(non_camel_case_types)]
|
||||
type type_of_udata = *mut libc::c_void;
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos"
|
||||
))]
|
||||
#[allow(non_camel_case_types)]
|
||||
type type_of_data = libc::intptr_t;
|
||||
#[cfg(any(target_os = "netbsd"))]
|
||||
#[allow(non_camel_case_types)]
|
||||
type type_of_udata = libc::intptr_t;
|
||||
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
|
||||
#[allow(non_camel_case_types)]
|
||||
type type_of_data = libc::int64_t;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct KEvent(libc::kevent);
|
||||
|
||||
unsafe impl Send for KEvent {}
|
||||
|
||||
impl KEvent {
|
||||
pub fn new(
|
||||
ident: libc::uintptr_t,
|
||||
filter: EventFilter,
|
||||
flags: EventFlag,
|
||||
fflags: FilterFlag,
|
||||
data: libc::intptr_t,
|
||||
udata: libc::intptr_t,
|
||||
) -> KEvent {
|
||||
KEvent(libc::kevent {
|
||||
ident,
|
||||
filter: filter as type_of_event_filter,
|
||||
flags,
|
||||
fflags,
|
||||
data: data as type_of_data,
|
||||
udata: udata as type_of_udata,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn filter(&self) -> EventFilter {
|
||||
unsafe { std::mem::transmute(self.0.filter as type_of_event_filter) }
|
||||
}
|
||||
|
||||
pub fn flags(&self) -> EventFlag {
|
||||
self.0.flags
|
||||
}
|
||||
|
||||
pub fn data(&self) -> libc::intptr_t {
|
||||
self.0.data as libc::intptr_t
|
||||
}
|
||||
|
||||
pub fn udata(&self) -> libc::intptr_t {
|
||||
self.0.udata as libc::intptr_t
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
pub type EventFlag = u16;
|
||||
#[cfg(any(target_os = "netbsd"))]
|
||||
pub type EventFlag = u32;
|
||||
|
||||
pub type FilterFlag = u32;
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
pub type EventFilter = u32;
|
||||
#[cfg(not(target_os = "netbsd"))]
|
||||
pub type EventFilter = i16;
|
||||
|
||||
pub fn kqueue() -> Result<RawFd, std::io::Error> {
|
||||
let res = unsafe { libc::kqueue() };
|
||||
|
||||
check_err(res)
|
||||
}
|
||||
|
||||
pub fn kevent_ts(
|
||||
kq: RawFd,
|
||||
changelist: &[KEvent],
|
||||
eventlist: &mut [KEvent],
|
||||
timeout_opt: Option<libc::timespec>,
|
||||
) -> Result<usize, std::io::Error> {
|
||||
let res = unsafe {
|
||||
libc::kevent(
|
||||
kq,
|
||||
changelist.as_ptr() as *const libc::kevent,
|
||||
changelist.len() as type_of_nchanges,
|
||||
eventlist.as_mut_ptr() as *mut libc::kevent,
|
||||
eventlist.len() as type_of_nchanges,
|
||||
if let Some(ref timeout) = timeout_opt {
|
||||
timeout as *const libc::timespec
|
||||
} else {
|
||||
std::ptr::null()
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
check_err(res).map(|r| r as usize)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android", target_os = "illumos"))]
|
||||
/// Epoll.
|
||||
pub mod epoll {
|
||||
use super::check_err;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
||||
#[macro_use]
|
||||
mod dlsym {
|
||||
// Based on https://github.com/tokio-rs/mio/blob/v0.6.x/src/sys/unix/dlsym.rs
|
||||
// I feel very sad including this code, but I have not found a better way
|
||||
// to check for the existence of a symbol in Rust.
|
||||
|
||||
use std::marker;
|
||||
use std::mem;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
macro_rules! dlsym {
|
||||
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
|
||||
#[allow(bad_style)]
|
||||
static $name: $crate::sys::epoll::dlsym::DlSym<unsafe extern fn($($t),*) -> $ret> =
|
||||
$crate::sys::epoll::dlsym::DlSym {
|
||||
name: concat!(stringify!($name), "\0"),
|
||||
addr: std::sync::atomic::AtomicUsize::new(0),
|
||||
_marker: std::marker::PhantomData,
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
pub struct DlSym<F> {
|
||||
pub name: &'static str,
|
||||
pub addr: AtomicUsize,
|
||||
pub _marker: marker::PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<F> DlSym<F> {
|
||||
pub fn get(&self) -> Option<&F> {
|
||||
assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
|
||||
unsafe {
|
||||
if self.addr.load(Ordering::SeqCst) == 0 {
|
||||
self.addr.store(fetch(self.name), Ordering::SeqCst);
|
||||
}
|
||||
if self.addr.load(Ordering::SeqCst) == 1 {
|
||||
None
|
||||
} else {
|
||||
mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn fetch(name: &str) -> usize {
|
||||
assert_eq!(name.as_bytes()[name.len() - 1], 0);
|
||||
match libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize {
|
||||
0 => 1,
|
||||
n => n,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[repr(i32)]
|
||||
pub enum EpollOp {
|
||||
EpollCtlAdd = libc::EPOLL_CTL_ADD,
|
||||
EpollCtlDel = libc::EPOLL_CTL_DEL,
|
||||
EpollCtlMod = libc::EPOLL_CTL_MOD,
|
||||
}
|
||||
|
||||
pub type EpollFlags = libc::c_int;
|
||||
|
||||
pub fn epoll_create1() -> Result<RawFd, std::io::Error> {
|
||||
// According to libuv, `EPOLL_CLOEXEC` is not defined on Android API <
|
||||
// 21. But `EPOLL_CLOEXEC` is an alias for `O_CLOEXEC` on that platform,
|
||||
// so we use it instead.
|
||||
#[cfg(target_os = "android")]
|
||||
const CLOEXEC: libc::c_int = libc::O_CLOEXEC;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
const CLOEXEC: libc::c_int = libc::EPOLL_CLOEXEC;
|
||||
|
||||
let fd = unsafe {
|
||||
// Emulate epoll_create1 if not available.
|
||||
|
||||
dlsym!(fn epoll_create1(libc::c_int) -> libc::c_int);
|
||||
match epoll_create1.get() {
|
||||
Some(epoll_create1_fn) => check_err(epoll_create1_fn(CLOEXEC))?,
|
||||
None => {
|
||||
let fd = check_err(libc::epoll_create(1024))?;
|
||||
drop(set_cloexec(fd));
|
||||
fd
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
unsafe fn set_cloexec(fd: libc::c_int) -> Result<(), std::io::Error> {
|
||||
let flags = libc::fcntl(fd, libc::F_GETFD);
|
||||
check_err(libc::fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC)).map(|_| ())
|
||||
}
|
||||
|
||||
pub fn epoll_ctl<'a, T>(
|
||||
epfd: RawFd,
|
||||
op: EpollOp,
|
||||
fd: RawFd,
|
||||
event: T,
|
||||
) -> Result<(), std::io::Error>
|
||||
where
|
||||
T: Into<Option<&'a mut EpollEvent>>,
|
||||
{
|
||||
let mut event: Option<&mut EpollEvent> = event.into();
|
||||
if event.is_none() && op != EpollOp::EpollCtlDel {
|
||||
Err(std::io::Error::from_raw_os_error(libc::EINVAL))
|
||||
} else {
|
||||
let res = unsafe {
|
||||
if let Some(ref mut event) = event {
|
||||
libc::epoll_ctl(epfd, op as libc::c_int, fd, &mut event.event)
|
||||
} else {
|
||||
libc::epoll_ctl(epfd, op as libc::c_int, fd, std::ptr::null_mut())
|
||||
}
|
||||
};
|
||||
check_err(res).map(drop)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn epoll_wait(
|
||||
epfd: RawFd,
|
||||
events: &mut [EpollEvent],
|
||||
timeout_ms: isize,
|
||||
) -> Result<usize, std::io::Error> {
|
||||
let res = unsafe {
|
||||
libc::epoll_wait(
|
||||
epfd,
|
||||
events.as_mut_ptr() as *mut libc::epoll_event,
|
||||
events.len() as libc::c_int,
|
||||
timeout_ms as libc::c_int,
|
||||
)
|
||||
};
|
||||
|
||||
check_err(res).map(|r| r as usize)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct EpollEvent {
|
||||
event: libc::epoll_event,
|
||||
}
|
||||
|
||||
impl EpollEvent {
|
||||
pub fn new(events: EpollFlags, data: u64) -> Self {
|
||||
EpollEvent {
|
||||
event: libc::epoll_event {
|
||||
events: events as u32,
|
||||
u64: data,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty() -> Self {
|
||||
unsafe { std::mem::zeroed::<EpollEvent>() }
|
||||
}
|
||||
|
||||
pub fn events(&self) -> EpollFlags {
|
||||
self.event.events as libc::c_int
|
||||
}
|
||||
|
||||
pub fn data(&self) -> u64 {
|
||||
self.event.u64
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue