From 61fa94f41808c820ca6be95f722a0ef6efdc2a35 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Thu, 16 Feb 2023 15:24:49 +0100 Subject: Upgrade mio to 0.8.6 This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update rust/crates/mio For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md Test: TreeHugger Change-Id: I5a8f9771f053ac1d65c11d2cd25dae4345a475d0 --- .cargo_vcs_info.json | 2 +- Android.bp | 4 +-- CHANGELOG.md | 21 +++++++++++++++ Cargo.lock | 59 ++++++++++++++++++++++++----------------- Cargo.toml | 6 ++--- Cargo.toml.orig | 6 ++--- METADATA | 12 ++++----- README.md | 4 +-- src/interest.rs | 38 ++++++++++++++++---------- src/net/tcp/stream.rs | 2 +- src/sys/unix/net.rs | 56 ++++++++++++++++++-------------------- src/sys/unix/pipe.rs | 11 ++++---- src/sys/unix/selector/epoll.rs | 21 +++++++-------- src/sys/unix/selector/kqueue.rs | 53 ++++++++++++++++++------------------ src/sys/unix/selector/mod.rs | 8 +++--- src/sys/unix/tcp.rs | 13 ++++----- src/sys/unix/udp.rs | 20 +++++--------- src/sys/unix/uds/datagram.rs | 12 ++++----- src/sys/unix/uds/listener.rs | 25 +++++++---------- src/sys/unix/uds/stream.rs | 15 ++++------- src/sys/unix/waker.rs | 29 ++++++++------------ src/sys/windows/iocp.rs | 17 +++++------- src/sys/windows/net.rs | 25 ++++++++++------- src/sys/windows/tcp.rs | 13 +++------ src/sys/windows/udp.rs | 31 +++++++++------------- 25 files changed, 249 insertions(+), 254 deletions(-) diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index c60d385..30e5027 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "0accf7dc22f197245e6a1aa84096262cd6f6e4d4" + "sha1": "7ed74bf478230a0cfa7543901f6be6df8bb3602e" }, "path_in_vcs": "" } \ No newline at end of file diff --git a/Android.bp b/Android.bp index 660a924..eb6fed1 100644 --- a/Android.bp +++ b/Android.bp @@ -23,7 +23,7 @@ rust_library { host_supported: true, crate_name: "mio", cargo_env_compat: true, - cargo_pkg_version: "0.8.5", + cargo_pkg_version: "0.8.6", srcs: ["src/lib.rs"], edition: "2018", features: [ @@ -50,7 +50,7 @@ rust_test { host_supported: true, crate_name: "mio", cargo_env_compat: true, - cargo_pkg_version: "0.8.5", + cargo_pkg_version: "0.8.6", srcs: ["src/lib.rs"], test_suites: ["general-tests"], auto_gen_config: true, diff --git a/CHANGELOG.md b/CHANGELOG.md index 10d9154..e45a2b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +# 0.8.6 + +## Added + +* `Interest::PRIORITY` on Linux and Android, to trigger `Event::is_priority` + (https://github.com/tokio-rs/mio/pull/1647). + +## Changed + +* Updated windows-sys to 0.45 + (https://github.com/tokio-rs/mio/pull/1644). +* We started testing with sanitizers on the CI + (https://github.com/tokio-rs/mio/pull/1648). + +## Fixed + +* A number of potential fd leaks when setup resulted in an error right after + creation (https://github.com/tokio-rs/mio/pull/1636). +* Less truncating for timeout values in `Poll::poll` + (https://github.com/tokio-rs/mio/pull/1642). + # 0.8.5 ## Changed diff --git a/Cargo.lock b/Cargo.lock index 76cbc55..6a7d9ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "libc", @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.126" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "log" @@ -45,7 +45,7 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.5" +version = "0.8.6" dependencies = [ "env_logger", "libc", @@ -57,9 +57,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "rand" @@ -84,9 +84,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] @@ -99,9 +99,18 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -114,42 +123,42 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" diff --git a/Cargo.toml b/Cargo.toml index 7460010..fe4bc85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2018" name = "mio" -version = "0.8.5" +version = "0.8.6" authors = [ "Carl Lerche ", "Thomas de Zeeuw ", @@ -26,7 +26,7 @@ include = [ "src/**/*.rs", "examples/**/*.rs", ] -description = "Lightweight non-blocking IO" +description = "Lightweight non-blocking I/O." homepage = "https://github.com/tokio-rs/mio" readme = "README.md" keywords = [ @@ -116,7 +116,7 @@ version = "0.11.0" version = "0.2.121" [target."cfg(windows)".dependencies.windows-sys] -version = "0.42" +version = "0.45" features = [ "Win32_Foundation", "Win32_Networking_WinSock", diff --git a/Cargo.toml.orig b/Cargo.toml.orig index c5052a7..84eb63b 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -4,14 +4,14 @@ name = "mio" # When releasing to crates.io: # - Update CHANGELOG.md. # - Create git tag -version = "0.8.5" +version = "0.8.6" license = "MIT" authors = [ "Carl Lerche ", "Thomas de Zeeuw ", "Tokio Contributors ", ] -description = "Lightweight non-blocking IO" +description = "Lightweight non-blocking I/O." homepage = "https://github.com/tokio-rs/mio" repository = "https://github.com/tokio-rs/mio" readme = "README.md" @@ -49,7 +49,7 @@ log = "0.4.8" libc = "0.2.121" [target.'cfg(windows)'.dependencies.windows-sys] -version = "0.42" +version = "0.45" features = [ "Win32_Foundation", # Basic types eg HANDLE "Win32_Networking_WinSock", # winsock2 types/functions diff --git a/METADATA b/METADATA index 5d0b7d4..11a32f7 100644 --- a/METADATA +++ b/METADATA @@ -3,7 +3,7 @@ # For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md name: "mio" -description: "Lightweight non-blocking IO" +description: "Lightweight non-blocking I/O." third_party { url { type: HOMEPAGE @@ -11,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/mio/mio-0.8.5.crate" + value: "https://static.crates.io/crates/mio/mio-0.8.6.crate" } - version: "0.8.5" + version: "0.8.6" license_type: NOTICE last_upgrade_date { - year: 2022 - month: 12 - day: 12 + year: 2023 + month: 2 + day: 16 } } diff --git a/README.md b/README.md index c17f3d3..bebd2af 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Mio – Metal IO +# Mio – Metal I/O Mio is a fast, low-level I/O library for Rust focusing on non-blocking APIs and event notification for building high performance I/O apps with as little @@ -20,10 +20,8 @@ overhead as possible over the OS abstractions. **API documentation** -* [master](https://tokio-rs.github.io/mio/doc/mio/) * [v0.8](https://docs.rs/mio/^0.8) * [v0.7](https://docs.rs/mio/^0.7) -* [v0.6](https://docs.rs/mio/^0.6) This is a low level library, if you are looking for something easier to get started with, see [Tokio](https://tokio.rs). diff --git a/src/interest.rs b/src/interest.rs index 0aa0bda..50d1bf0 100644 --- a/src/interest.rs +++ b/src/interest.rs @@ -20,18 +20,9 @@ pub struct Interest(NonZeroU8); const READABLE: u8 = 0b0001; const WRITABLE: u8 = 0b0010; // The following are not available on all platforms. -#[cfg_attr( - not(any( - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos" - )), - allow(dead_code) -)] const AIO: u8 = 0b0100; -#[cfg_attr(not(target_os = "freebsd"), allow(dead_code))] const LIO: u8 = 0b1000; +const PRIORITY: u8 = 0b10000; impl Interest { /// Returns a `Interest` set representing readable interests. @@ -45,7 +36,7 @@ impl Interest { target_os = "dragonfly", target_os = "freebsd", target_os = "ios", - target_os = "macos" + target_os = "macos", ))] pub const AIO: Interest = Interest(unsafe { NonZeroU8::new_unchecked(AIO) }); @@ -53,6 +44,10 @@ impl Interest { #[cfg(target_os = "freebsd")] pub const LIO: Interest = Interest(unsafe { NonZeroU8::new_unchecked(LIO) }); + /// Returns a `Interest` set representing priority completion interests. + #[cfg(any(target_os = "linux", target_os = "android"))] + pub const PRIORITY: Interest = Interest(unsafe { NonZeroU8::new_unchecked(PRIORITY) }); + /// Add together two `Interest`. /// /// This does the same thing as the `BitOr` implementation, but is a @@ -104,15 +99,20 @@ impl Interest { (self.0.get() & WRITABLE) != 0 } - /// Returns true if `Interest` contains AIO readiness + /// Returns true if `Interest` contains AIO readiness. pub const fn is_aio(self) -> bool { (self.0.get() & AIO) != 0 } - /// Returns true if `Interest` contains LIO readiness + /// Returns true if `Interest` contains LIO readiness. pub const fn is_lio(self) -> bool { (self.0.get() & LIO) != 0 } + + /// Returns true if `Interest` contains priority readiness. + pub const fn is_priority(self) -> bool { + (self.0.get() & PRIORITY) != 0 + } } impl ops::BitOr for Interest { @@ -152,7 +152,7 @@ impl fmt::Debug for Interest { target_os = "dragonfly", target_os = "freebsd", target_os = "ios", - target_os = "macos" + target_os = "macos", ))] { if self.is_aio() { @@ -173,6 +173,16 @@ impl fmt::Debug for Interest { one = true } } + #[cfg(any(target_os = "linux", target_os = "android"))] + { + if self.is_priority() { + if one { + write!(fmt, " | ")? + } + write!(fmt, "PRIORITY")?; + one = true + } + } debug_assert!(one, "printing empty interests"); Ok(()) } diff --git a/src/net/tcp/stream.rs b/src/net/tcp/stream.rs index a7a9aa1..8a3f6a2 100644 --- a/src/net/tcp/stream.rs +++ b/src/net/tcp/stream.rs @@ -72,7 +72,7 @@ impl TcpStream { /// `ErrorKind::NotConnected` it means the stream is not yet connected, /// go back to step 3. If it returns an address it means the stream is /// connected, go to step 5. If another error is returned something - /// whent wrong. + /// went wrong. /// 5. Now the stream can be used. /// /// This may return a `WouldBlock` in which case the socket connection diff --git a/src/sys/unix/net.rs b/src/sys/unix/net.rs index 78f1387..2396ab9 100644 --- a/src/sys/unix/net.rs +++ b/src/sys/unix/net.rs @@ -20,43 +20,39 @@ pub(crate) fn new_socket(domain: libc::c_int, socket_type: libc::c_int) -> io::R target_os = "illumos", target_os = "linux", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", ))] let socket_type = socket_type | libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC; - // Gives a warning for platforms without SOCK_NONBLOCK. - #[allow(clippy::let_and_return)] - let socket = syscall!(socket(domain, socket_type, 0)); + let socket = syscall!(socket(domain, socket_type, 0))?; // Mimick `libstd` and set `SO_NOSIGPIPE` on apple systems. - #[cfg(target_vendor = "apple")] - let socket = socket.and_then(|socket| { - syscall!(setsockopt( - socket, - libc::SOL_SOCKET, - libc::SO_NOSIGPIPE, - &1 as *const libc::c_int as *const libc::c_void, - size_of::() as libc::socklen_t - )) - .map(|_| socket) - }); + #[cfg(any(target_os = "ios", target_os = "macos"))] + if let Err(err) = syscall!(setsockopt( + socket, + libc::SOL_SOCKET, + libc::SO_NOSIGPIPE, + &1 as *const libc::c_int as *const libc::c_void, + size_of::() as libc::socklen_t + )) { + let _ = syscall!(close(socket)); + return Err(err); + } // Darwin doesn't have SOCK_NONBLOCK or SOCK_CLOEXEC. #[cfg(any(target_os = "ios", target_os = "macos"))] - let socket = socket.and_then(|socket| { - // For platforms that don't support flags in socket, we need to - // set the flags ourselves. - syscall!(fcntl(socket, libc::F_SETFL, libc::O_NONBLOCK)) - .and_then(|_| syscall!(fcntl(socket, libc::F_SETFD, libc::FD_CLOEXEC)).map(|_| socket)) - .map_err(|e| { - // If either of the `fcntl` calls failed, ensure the socket is - // closed and return the error. - let _ = syscall!(close(socket)); - e - }) - }); + { + if let Err(err) = syscall!(fcntl(socket, libc::F_SETFL, libc::O_NONBLOCK)) { + let _ = syscall!(close(socket)); + return Err(err); + } + if let Err(err) = syscall!(fcntl(socket, libc::F_SETFD, libc::FD_CLOEXEC)) { + let _ = syscall!(close(socket)); + return Err(err); + } + } - socket + Ok(socket) } /// A type with the same memory layout as `libc::sockaddr`. Used in converting Rust level @@ -96,7 +92,7 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_ target_os = "ios", target_os = "macos", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", ))] sin_len: 0, }; @@ -120,7 +116,7 @@ pub(crate) fn socket_addr(addr: &SocketAddr) -> (SocketAddrCRepr, libc::socklen_ target_os = "ios", target_os = "macos", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", ))] sin6_len: 0, #[cfg(target_os = "illumos")] diff --git a/src/sys/unix/pipe.rs b/src/sys/unix/pipe.rs index 7a95b96..7b7e4db 100644 --- a/src/sys/unix/pipe.rs +++ b/src/sys/unix/pipe.rs @@ -176,7 +176,7 @@ pub fn new() -> io::Result<(Sender, Receiver)> { || libc::fcntl(*fd, libc::F_SETFD, libc::FD_CLOEXEC) != 0 { let err = io::Error::last_os_error(); - // Don't leak file descriptors. Can't handle error though. + // Don't leak file descriptors. Can't handle closing error though. let _ = libc::close(fds[0]); let _ = libc::close(fds[1]); return Err(err); @@ -188,19 +188,20 @@ pub fn new() -> io::Result<(Sender, Receiver)> { target_os = "android", target_os = "dragonfly", target_os = "freebsd", + target_os = "illumos", + target_os = "ios", target_os = "linux", + target_os = "macos", target_os = "netbsd", target_os = "openbsd", - target_os = "ios", - target_os = "macos", - target_os = "illumos", target_os = "redox", )))] compile_error!("unsupported target for `mio::unix::pipe`"); - // Safety: we just initialised the `fds` above. + // SAFETY: we just initialised the `fds` above. let r = unsafe { Receiver::from_raw_fd(fds[0]) }; let w = unsafe { Sender::from_raw_fd(fds[1]) }; + Ok((w, r)) } diff --git a/src/sys/unix/selector/epoll.rs b/src/sys/unix/selector/epoll.rs index 1256663..1809a2b 100644 --- a/src/sys/unix/selector/epoll.rs +++ b/src/sys/unix/selector/epoll.rs @@ -1,6 +1,6 @@ use crate::{Interest, Token}; -use libc::{EPOLLET, EPOLLIN, EPOLLOUT, EPOLLRDHUP}; +use libc::{EPOLLET, EPOLLIN, EPOLLOUT, EPOLLPRI, EPOLLRDHUP}; use log::error; use std::os::unix::io::{AsRawFd, RawFd}; #[cfg(debug_assertions)] @@ -88,16 +88,11 @@ impl Selector { let timeout = timeout .map(|to| { - let to_ms = to.as_millis(); - // as_millis() truncates, so round up to 1 ms as the documentation says can happen. - // This avoids turning submillisecond timeouts into immediate returns unless the - // caller explicitly requests that by specifying a zero timeout. - let to_ms = to_ms - + if to_ms == 0 && to.subsec_nanos() != 0 { - 1 - } else { - 0 - }; + // `Duration::as_millis` truncates, so round up. This avoids + // turning sub-millisecond timeouts into a zero timeout, unless + // the caller explicitly requests that by specifying a zero + // timeout. + let to_ms = (to + Duration::from_nanos(999_999)).as_millis(); cmp::min(MAX_SAFE_TIMEOUT, to_ms) as libc::c_int }) .unwrap_or(-1); @@ -182,6 +177,10 @@ fn interests_to_epoll(interests: Interest) -> u32 { kind |= EPOLLOUT; } + if interests.is_priority() { + kind |= EPOLLPRI; + } + kind as u32 } diff --git a/src/sys/unix/selector/kqueue.rs b/src/sys/unix/selector/kqueue.rs index 0be4281..1eedec0 100644 --- a/src/sys/unix/selector/kqueue.rs +++ b/src/sys/unix/selector/kqueue.rs @@ -21,7 +21,7 @@ type Count = libc::size_t; // Type of the `filter` field in the `kevent` structure. #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] type Filter = libc::c_short; -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(any(target_os = "ios", target_os = "macos"))] type Filter = i16; #[cfg(target_os = "netbsd")] type Filter = u32; @@ -29,7 +29,7 @@ type Filter = u32; // Type of the `flags` field in the `kevent` structure. #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))] type Flags = libc::c_ushort; -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(any(target_os = "ios", target_os = "macos"))] type Flags = u16; #[cfg(target_os = "netbsd")] type Flags = u32; @@ -63,15 +63,17 @@ pub struct Selector { impl Selector { pub fn new() -> io::Result { - syscall!(kqueue()) - .and_then(|kq| syscall!(fcntl(kq, libc::F_SETFD, libc::FD_CLOEXEC)).map(|_| kq)) - .map(|kq| Selector { - #[cfg(debug_assertions)] - id: NEXT_ID.fetch_add(1, Ordering::Relaxed), - kq, - #[cfg(debug_assertions)] - has_waker: AtomicBool::new(false), - }) + let kq = syscall!(kqueue())?; + let selector = Selector { + #[cfg(debug_assertions)] + id: NEXT_ID.fetch_add(1, Ordering::Relaxed), + kq, + #[cfg(debug_assertions)] + has_waker: AtomicBool::new(false), + }; + + syscall!(fcntl(kq, libc::F_SETFD, libc::FD_CLOEXEC))?; + Ok(selector) } pub fn try_clone(&self) -> io::Result { @@ -403,7 +405,7 @@ pub mod event { target_os = "dragonfly", target_os = "freebsd", target_os = "ios", - target_os = "macos" + target_os = "macos", ))] { event.filter == libc::EVFILT_AIO @@ -412,7 +414,7 @@ pub mod event { target_os = "dragonfly", target_os = "freebsd", target_os = "ios", - target_os = "macos" + target_os = "macos", )))] { false @@ -448,7 +450,7 @@ pub mod event { target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "macos" + target_os = "macos", ))] libc::EVFILT_FS, #[cfg(target_os = "freebsd")] @@ -457,7 +459,7 @@ pub mod event { target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "macos" + target_os = "macos", ))] libc::EVFILT_USER, #[cfg(target_os = "freebsd")] @@ -514,49 +516,49 @@ pub mod event { target_os = "dragonfly", target_os = "freebsd", target_os = "ios", - target_os = "macos" + target_os = "macos", ))] libc::NOTE_TRIGGER, #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "ios", - target_os = "macos" + target_os = "macos", ))] libc::NOTE_FFNOP, #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "ios", - target_os = "macos" + target_os = "macos", ))] libc::NOTE_FFAND, #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "ios", - target_os = "macos" + target_os = "macos", ))] libc::NOTE_FFOR, #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "ios", - target_os = "macos" + target_os = "macos", ))] libc::NOTE_FFCOPY, #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "ios", - target_os = "macos" + target_os = "macos", ))] libc::NOTE_FFCTRLMASK, #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "ios", - target_os = "macos" + target_os = "macos", ))] libc::NOTE_FFLAGSMASK, libc::NOTE_LOWAT, @@ -591,21 +593,21 @@ pub mod event { target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", ))] libc::NOTE_TRACK, #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", ))] libc::NOTE_TRACKERR, #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", ))] libc::NOTE_CHILD, #[cfg(any(target_os = "ios", target_os = "macos"))] @@ -633,7 +635,6 @@ pub mod event { #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))] libc::NOTE_NSECONDS, #[cfg(any(target_os = "ios", target_os = "macos"))] - #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))] libc::NOTE_ABSOLUTE, #[cfg(any(target_os = "ios", target_os = "macos"))] libc::NOTE_LEEWAY, diff --git a/src/sys/unix/selector/mod.rs b/src/sys/unix/selector/mod.rs index 9ae4c14..c06c7b1 100644 --- a/src/sys/unix/selector/mod.rs +++ b/src/sys/unix/selector/mod.rs @@ -17,20 +17,20 @@ pub(crate) use self::epoll::{event, Event, Events, Selector}; #[cfg(any( target_os = "dragonfly", target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", target_os = "ios", target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" ))] mod kqueue; #[cfg(any( target_os = "dragonfly", target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", target_os = "ios", target_os = "macos", - target_os = "netbsd", - target_os = "openbsd" ))] pub(crate) use self::kqueue::{event, Event, Events, Selector}; diff --git a/src/sys/unix/tcp.rs b/src/sys/unix/tcp.rs index c4d7e94..9513cc0 100644 --- a/src/sys/unix/tcp.rs +++ b/src/sys/unix/tcp.rs @@ -40,7 +40,7 @@ pub(crate) fn listen(socket: &net::TcpListener, backlog: u32) -> io::Result<()> } pub(crate) fn set_reuseaddr(socket: &net::TcpListener, reuseaddr: bool) -> io::Result<()> { - let val: libc::c_int = if reuseaddr { 1 } else { 0 }; + let val: libc::c_int = i32::from(reuseaddr); syscall!(setsockopt( socket.as_raw_fd(), libc::SOL_SOCKET, @@ -60,16 +60,13 @@ pub(crate) fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, #[cfg(any( // Android x86's seccomp profile forbids calls to `accept4(2)` // See https://github.com/tokio-rs/mio/issues/1445 for details - all( - not(target_arch="x86"), - target_os = "android" - ), + all(not(target_arch="x86"), target_os = "android"), target_os = "dragonfly", target_os = "freebsd", target_os = "illumos", target_os = "linux", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", ))] let stream = { syscall!(accept4( @@ -85,10 +82,10 @@ pub(crate) fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, // OSes inherit the non-blocking flag from the listener, so we just have to // set `CLOEXEC`. #[cfg(any( - all(target_arch = "x86", target_os = "android"), target_os = "ios", target_os = "macos", - target_os = "redox" + target_os = "redox", + all(target_arch = "x86", target_os = "android"), ))] let stream = { syscall!(accept( diff --git a/src/sys/unix/udp.rs b/src/sys/unix/udp.rs index 5a97cbd..843ae88 100644 --- a/src/sys/unix/udp.rs +++ b/src/sys/unix/udp.rs @@ -6,21 +6,13 @@ use std::net::{self, SocketAddr}; use std::os::unix::io::{AsRawFd, FromRawFd}; pub fn bind(addr: SocketAddr) -> io::Result { - // Gives a warning for non Apple platforms. - #[allow(clippy::let_and_return)] - let socket = new_ip_socket(addr, libc::SOCK_DGRAM); + let fd = new_ip_socket(addr, libc::SOCK_DGRAM)?; + let socket = unsafe { net::UdpSocket::from_raw_fd(fd) }; - socket.and_then(|socket| { - let (raw_addr, raw_addr_length) = socket_addr(&addr); - syscall!(bind(socket, raw_addr.as_ptr(), raw_addr_length)) - .map_err(|err| { - // Close the socket if we hit an error, ignoring the error - // from closing since we can't pass back two errors. - let _ = unsafe { libc::close(socket) }; - err - }) - .map(|_| unsafe { net::UdpSocket::from_raw_fd(socket) }) - }) + let (raw_addr, raw_addr_length) = socket_addr(&addr); + syscall!(bind(fd, raw_addr.as_ptr(), raw_addr_length))?; + + Ok(socket) } pub(crate) fn only_v6(socket: &net::UdpSocket) -> io::Result { diff --git a/src/sys/unix/uds/datagram.rs b/src/sys/unix/uds/datagram.rs index d3e5314..a5ada72 100644 --- a/src/sys/unix/uds/datagram.rs +++ b/src/sys/unix/uds/datagram.rs @@ -7,18 +7,18 @@ use std::os::unix::net; use std::path::Path; pub(crate) fn bind(path: &Path) -> io::Result { - let fd = new_socket(libc::AF_UNIX, libc::SOCK_DGRAM)?; - // Ensure the fd is closed. - let socket = unsafe { net::UnixDatagram::from_raw_fd(fd) }; let (sockaddr, socklen) = socket_addr(path)?; let sockaddr = &sockaddr as *const libc::sockaddr_un as *const _; - syscall!(bind(fd, sockaddr, socklen))?; + + let socket = unbound()?; + syscall!(bind(socket.as_raw_fd(), sockaddr, socklen))?; + Ok(socket) } pub(crate) fn unbound() -> io::Result { - new_socket(libc::AF_UNIX, libc::SOCK_DGRAM) - .map(|socket| unsafe { net::UnixDatagram::from_raw_fd(socket) }) + let fd = new_socket(libc::AF_UNIX, libc::SOCK_DGRAM)?; + Ok(unsafe { net::UnixDatagram::from_raw_fd(fd) }) } pub(crate) fn pair() -> io::Result<(net::UnixDatagram, net::UnixDatagram)> { diff --git a/src/sys/unix/uds/listener.rs b/src/sys/unix/uds/listener.rs index 79bd14e..3e33b30 100644 --- a/src/sys/unix/uds/listener.rs +++ b/src/sys/unix/uds/listener.rs @@ -7,19 +7,15 @@ use std::path::Path; use std::{io, mem}; pub(crate) fn bind(path: &Path) -> io::Result { - let socket = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?; let (sockaddr, socklen) = socket_addr(path)?; let sockaddr = &sockaddr as *const libc::sockaddr_un as *const libc::sockaddr; - syscall!(bind(socket, sockaddr, socklen)) - .and_then(|_| syscall!(listen(socket, 1024))) - .map_err(|err| { - // Close the socket if we hit an error, ignoring the error from - // closing since we can't pass back two errors. - let _ = unsafe { libc::close(socket) }; - err - }) - .map(|_| unsafe { net::UnixListener::from_raw_fd(socket) }) + let fd = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?; + let socket = unsafe { net::UnixListener::from_raw_fd(fd) }; + syscall!(bind(fd, sockaddr, socklen))?; + syscall!(listen(fd, 1024))?; + + Ok(socket) } pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, SocketAddr)> { @@ -45,10 +41,7 @@ pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, So target_os = "redox", // Android x86's seccomp profile forbids calls to `accept4(2)` // See https://github.com/tokio-rs/mio/issues/1445 for details - all( - target_arch = "x86", - target_os = "android" - ) + all(target_arch = "x86", target_os = "android"), )))] let socket = { let flags = libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC; @@ -62,10 +55,10 @@ pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, So }; #[cfg(any( - target_os = "ios", - target_os = "macos", target_os = "netbsd", target_os = "redox", + target_os = "ios", + target_os = "macos", all(target_arch = "x86", target_os = "android") ))] let socket = syscall!(accept( diff --git a/src/sys/unix/uds/stream.rs b/src/sys/unix/uds/stream.rs index 9ae4867..461917c 100644 --- a/src/sys/unix/uds/stream.rs +++ b/src/sys/unix/uds/stream.rs @@ -7,23 +7,18 @@ use std::os::unix::net; use std::path::Path; pub(crate) fn connect(path: &Path) -> io::Result { - let socket = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?; let (sockaddr, socklen) = socket_addr(path)?; let sockaddr = &sockaddr as *const libc::sockaddr_un as *const libc::sockaddr; - match syscall!(connect(socket, sockaddr, socklen)) { + let fd = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?; + let socket = unsafe { net::UnixStream::from_raw_fd(fd) }; + match syscall!(connect(fd, sockaddr, socklen)) { Ok(_) => {} Err(ref err) if err.raw_os_error() == Some(libc::EINPROGRESS) => {} - Err(e) => { - // Close the socket if we hit an error, ignoring the error - // from closing since we can't pass back two errors. - let _ = unsafe { libc::close(socket) }; - - return Err(e); - } + Err(e) => return Err(e), } - Ok(unsafe { net::UnixStream::from_raw_fd(socket) }) + Ok(socket) } pub(crate) fn pair() -> io::Result<(net::UnixStream, net::UnixStream)> { diff --git a/src/sys/unix/waker.rs b/src/sys/unix/waker.rs index de88e31..d8764c2 100644 --- a/src/sys/unix/waker.rs +++ b/src/sys/unix/waker.rs @@ -20,14 +20,11 @@ mod eventfd { impl Waker { pub fn new(selector: &Selector, token: Token) -> io::Result { - syscall!(eventfd(0, libc::EFD_CLOEXEC | libc::EFD_NONBLOCK)).and_then(|fd| { - // Turn the file descriptor into a file first so we're ensured - // it's closed when dropped, e.g. when register below fails. - let file = unsafe { File::from_raw_fd(fd) }; - selector - .register(fd, token, Interest::READABLE) - .map(|()| Waker { fd: file }) - }) + let fd = syscall!(eventfd(0, libc::EFD_CLOEXEC | libc::EFD_NONBLOCK))?; + let file = unsafe { File::from_raw_fd(fd) }; + + selector.register(fd, token, Interest::READABLE)?; + Ok(Waker { fd: file }) } pub fn wake(&self) -> io::Result<()> { @@ -82,11 +79,9 @@ mod kqueue { impl Waker { pub fn new(selector: &Selector, token: Token) -> io::Result { - selector.try_clone().and_then(|selector| { - selector - .setup_waker(token) - .map(|()| Waker { selector, token }) - }) + let selector = selector.try_clone()?; + selector.setup_waker(token)?; + Ok(Waker { selector, token }) } pub fn wake(&self) -> io::Result<()> { @@ -127,13 +122,11 @@ mod pipe { pub fn new(selector: &Selector, token: Token) -> io::Result { let mut fds = [-1; 2]; syscall!(pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK | libc::O_CLOEXEC))?; - // Turn the file descriptors into files first so we're ensured - // they're closed when dropped, e.g. when register below fails. let sender = unsafe { File::from_raw_fd(fds[1]) }; let receiver = unsafe { File::from_raw_fd(fds[0]) }; - selector - .register(fds[0], token, Interest::READABLE) - .map(|()| Waker { sender, receiver }) + + selector.register(fds[0], token, Interest::READABLE)?; + Ok(Waker { sender, receiver }) } pub fn wake(&self) -> io::Result<()> { diff --git a/src/sys/windows/iocp.rs b/src/sys/windows/iocp.rs index 142b6fc..262c8f2 100644 --- a/src/sys/windows/iocp.rs +++ b/src/sys/windows/iocp.rs @@ -224,17 +224,12 @@ impl CompletionStatus { #[inline] fn duration_millis(dur: Option) -> u32 { if let Some(dur) = dur { - let dur_ms = dur.as_millis(); - // as_millis() truncates, so round nonzero <1ms timeouts up to 1ms. This avoids turning - // submillisecond timeouts into immediate reutrns unless the caller explictly requests that - // by specifiying a zero timeout. - let dur_ms = dur_ms - + if dur_ms == 0 && dur.subsec_nanos() != 0 { - 1 - } else { - 0 - }; - std::cmp::min(dur_ms, u32::MAX as u128) as u32 + // `Duration::as_millis` truncates, so round up. This avoids + // turning sub-millisecond timeouts into a zero timeout, unless + // the caller explicitly requests that by specifying a zero + // timeout. + let dur_ms = (dur + Duration::from_nanos(999_999)).as_millis(); + cmp::min(dur_ms, u32::MAX as u128) as u32 } else { u32::MAX } diff --git a/src/sys/windows/net.rs b/src/sys/windows/net.rs index 102ba79..44f459a 100644 --- a/src/sys/windows/net.rs +++ b/src/sys/windows/net.rs @@ -4,12 +4,13 @@ use std::net::SocketAddr; use std::sync::Once; use windows_sys::Win32::Networking::WinSock::{ - ioctlsocket, socket, AF_INET, AF_INET6, FIONBIO, IN6_ADDR, IN6_ADDR_0, INVALID_SOCKET, IN_ADDR, - IN_ADDR_0, SOCKADDR, SOCKADDR_IN, SOCKADDR_IN6, SOCKADDR_IN6_0, SOCKET, + closesocket, ioctlsocket, socket, AF_INET, AF_INET6, FIONBIO, IN6_ADDR, IN6_ADDR_0, + INVALID_SOCKET, IN_ADDR, IN_ADDR_0, SOCKADDR, SOCKADDR_IN, SOCKADDR_IN6, SOCKADDR_IN6_0, + SOCKET, }; /// Initialise the network stack for Windows. -pub(crate) fn init() { +fn init() { static INIT: Once = Once::new(); INIT.call_once(|| { // Let standard library call `WSAStartup` for us, we can't do it @@ -26,18 +27,24 @@ pub(crate) fn new_ip_socket(addr: SocketAddr, socket_type: u16) -> io::Result AF_INET6, }; - new_socket(domain, socket_type) + new_socket(domain.into(), socket_type) } pub(crate) fn new_socket(domain: u32, socket_type: u16) -> io::Result { - syscall!( + init(); + + let socket = syscall!( socket(domain as i32, socket_type as i32, 0), PartialEq::eq, INVALID_SOCKET - ) - .and_then(|socket| { - syscall!(ioctlsocket(socket, FIONBIO, &mut 1), PartialEq::ne, 0).map(|_| socket as SOCKET) - }) + )?; + + if let Err(err) = syscall!(ioctlsocket(socket, FIONBIO, &mut 1), PartialEq::ne, 0) { + let _ = unsafe { closesocket(socket) }; + return Err(err); + } + + Ok(socket as SOCKET) } /// A type with the same memory layout as `SOCKADDR`. Used in converting Rust level diff --git a/src/sys/windows/tcp.rs b/src/sys/windows/tcp.rs index 533074b..addd1e8 100644 --- a/src/sys/windows/tcp.rs +++ b/src/sys/windows/tcp.rs @@ -2,19 +2,12 @@ use std::io; use std::net::{self, SocketAddr}; use std::os::windows::io::AsRawSocket; -use windows_sys::Win32::Networking::WinSock::{ - self, AF_INET, AF_INET6, SOCKET, SOCKET_ERROR, SOCK_STREAM, -}; +use windows_sys::Win32::Networking::WinSock::{self, SOCKET, SOCKET_ERROR, SOCK_STREAM}; -use crate::sys::windows::net::{init, new_socket, socket_addr}; +use crate::sys::windows::net::{new_ip_socket, socket_addr}; pub(crate) fn new_for_addr(address: SocketAddr) -> io::Result { - init(); - let domain = match address { - SocketAddr::V4(_) => AF_INET, - SocketAddr::V6(_) => AF_INET6, - }; - new_socket(domain, SOCK_STREAM) + new_ip_socket(address, SOCK_STREAM) } pub(crate) fn bind(socket: &net::TcpListener, addr: SocketAddr) -> io::Result<()> { diff --git a/src/sys/windows/udp.rs b/src/sys/windows/udp.rs index 91516cc..87e269f 100644 --- a/src/sys/windows/udp.rs +++ b/src/sys/windows/udp.rs @@ -4,28 +4,23 @@ use std::net::{self, SocketAddr}; use std::os::windows::io::{AsRawSocket, FromRawSocket}; use std::os::windows::raw::SOCKET as StdSocket; // windows-sys uses usize, stdlib uses u32/u64. -use crate::sys::windows::net::{init, new_ip_socket, socket_addr}; +use crate::sys::windows::net::{new_ip_socket, socket_addr}; use windows_sys::Win32::Networking::WinSock::{ - bind as win_bind, closesocket, getsockopt, IPPROTO_IPV6, IPV6_V6ONLY, SOCKET_ERROR, SOCK_DGRAM, + bind as win_bind, getsockopt, IPPROTO_IPV6, IPV6_V6ONLY, SOCKET_ERROR, SOCK_DGRAM, }; pub fn bind(addr: SocketAddr) -> io::Result { - init(); - new_ip_socket(addr, SOCK_DGRAM).and_then(|socket| { - let (raw_addr, raw_addr_length) = socket_addr(&addr); - syscall!( - win_bind(socket, raw_addr.as_ptr(), raw_addr_length,), - PartialEq::eq, - SOCKET_ERROR - ) - .map_err(|err| { - // Close the socket if we hit an error, ignoring the error - // from closing since we can't pass back two errors. - let _ = unsafe { closesocket(socket) }; - err - }) - .map(|_| unsafe { net::UdpSocket::from_raw_socket(socket as StdSocket) }) - }) + let raw_socket = new_ip_socket(addr, SOCK_DGRAM)?; + let socket = unsafe { net::UdpSocket::from_raw_socket(raw_socket as StdSocket) }; + + let (raw_addr, raw_addr_length) = socket_addr(&addr); + syscall!( + win_bind(raw_socket, raw_addr.as_ptr(), raw_addr_length), + PartialEq::eq, + SOCKET_ERROR + )?; + + Ok(socket) } pub(crate) fn only_v6(socket: &net::UdpSocket) -> io::Result { -- cgit v1.2.3