From aa25fe6ab1b96f8c13eb63ccf920810290cd4aab Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Thu, 1 Apr 2021 17:18:00 -0700 Subject: Upgrade rust/crates/mio to 0.7.11 Test: make Change-Id: Id1268d37e0b2f83e62d44c708049fb74fd3652bc --- .cargo_vcs_info.json | 2 +- Android.bp | 3 +- CHANGELOG.md | 24 ++++++++ Cargo.lock | 27 +++------ Cargo.toml | 4 +- Cargo.toml.orig | 4 +- METADATA | 8 +-- TEST_MAPPING | 14 ++++- src/lib.rs | 2 +- src/macros.rs | 2 +- src/sys/unix/tcp.rs | 27 ++++++++- src/sys/unix/uds/listener.rs | 22 ++++++- src/sys/windows/afd.rs | 6 +- src/sys/windows/named_pipe.rs | 131 +++++++++++++++++++++++++++++++----------- 14 files changed, 201 insertions(+), 75 deletions(-) diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index f8fb5d1..d513c37 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "20b7298fe0d3da04b965ec4a379db0247cd632be" + "sha1": "772c692150c711d7bdd72b5c6287072b8914e519" } } diff --git a/Android.bp b/Android.bp index 9fec9f1..8812f69 100644 --- a/Android.bp +++ b/Android.bp @@ -1,4 +1,5 @@ // This file is generated by cargo2android.py --run --device --dependencies --features os-poll,tcp,udp,uds,os-util --patch=patches/Android.bp.patch. +// Do not modify this file as changes will be overridden on upgrade. package { default_applicable_licenses: ["external_rust_crates_mio_license"], @@ -45,5 +46,5 @@ rust_library { // dependent_library ["feature_list"] // cfg-if-1.0.0 -// libc-0.2.86 "align,default,std" +// libc-0.2.92 "default,std" // log-0.4.14 "std" diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f23320..72cb770 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,27 @@ +# 0.7.11 + +## Fixes + +* Fix missing feature of winapi. + (https://github.com/tokio-rs/mio/commit/a7e61db9e3c2b929ef1a33532bfcc22045d163ce). + +# 0.7.10 + +## Fixes + +* Fix an instance of not doc(cfg(.*)) + (https://github.com/tokio-rs/mio/commit/25e8f911357c740034f10a170dfa4ea1b28234ce). + +## Fixes + +* Fix error handling in `NamedPipe::write` + (https://github.com/tokio-rs/mio/commit/aec872be9732e5c6685100674278be27f54a271b). +* Use `accept(2)` on x86 Android instead of `accept4(2)` + (https://github.com/tokio-rs/mio/commit/6f86b925d3e48f30905d5cfa54348acf3f1fa036, + https://github.com/tokio-rs/mio/commit/8d5414880ab82178305ac1d2c16d715e58633d3e). +* Improve error message when opening AFD device + (https://github.com/tokio-rs/mio/commit/139f7c4422321eb4a17b14ae2c296fddd19a8804). + # 0.7.8 ## Fixes diff --git a/Cargo.lock b/Cargo.lock index 0e25467..c91bfb8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,10 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +version = 3 [[package]] name = "cfg-if" @@ -35,16 +31,16 @@ checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" [[package]] name = "log" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] name = "mio" -version = "0.7.8" +version = "0.7.11" dependencies = [ "env_logger", "libc", @@ -111,21 +107,14 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - [[package]] name = "socket2" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c29947abdee2a218277abeca306f25789c938e500ea5a9d4b12a5a504466902" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "redox_syscall", "winapi", ] diff --git a/Cargo.toml b/Cargo.toml index 80f9f6e..62090ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "mio" -version = "0.7.8" +version = "0.7.11" authors = ["Carl Lerche ", "Thomas de Zeeuw ", "Tokio Contributors "] include = ["Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md", "src/**/*.rs", "examples/**/*.rs"] description = "Lightweight non-blocking IO" @@ -69,4 +69,4 @@ version = "0.3" [target."cfg(windows)".dependencies.winapi] version = "0.3" -features = ["winsock2", "mswsock"] +features = ["winsock2", "mswsock", "mstcpip"] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 0d4b1d8..a14d17d 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -6,7 +6,7 @@ name = "mio" # - Update CHANGELOG.md. # - Update doc URL. # - Create git tag -version = "0.7.8" +version = "0.7.11" license = "MIT" authors = [ "Carl Lerche ", @@ -57,7 +57,7 @@ libc = "0.2.86" [target.'cfg(windows)'.dependencies] miow = "0.3.6" -winapi = { version = "0.3", features = ["winsock2", "mswsock"] } +winapi = { version = "0.3", features = ["winsock2", "mswsock", "mstcpip"] } ntapi = "0.3" [dev-dependencies] diff --git a/METADATA b/METADATA index 9864d68..eb89225 100644 --- a/METADATA +++ b/METADATA @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/mio/mio-0.7.8.crate" + value: "https://static.crates.io/crates/mio/mio-0.7.11.crate" } - version: "0.7.8" + version: "0.7.11" license_type: NOTICE last_upgrade_date { year: 2021 - month: 2 - day: 17 + month: 4 + day: 1 } } diff --git a/TEST_MAPPING b/TEST_MAPPING index c1780b5..fadb544 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -2,10 +2,22 @@ { "presubmit": [ { - "name": "quiche_device_test_src_lib" + "name": "tokio-test_device_test_tests_macros" + }, + { + "name": "tokio-test_device_test_tests_block_on" + }, + { + "name": "tokio-test_device_test_tests_io" }, { "name": "futures-util_device_test_src_lib" + }, + { + "name": "tokio-test_device_test_src_lib" + }, + { + "name": "quiche_device_test_src_lib" } ] } diff --git a/src/lib.rs b/src/lib.rs index fedb789..ad417c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://docs.rs/mio/0.7.8")] +#![doc(html_root_url = "https://docs.rs/mio/0.7.11")] #![deny( missing_docs, missing_debug_implementations, diff --git a/src/macros.rs b/src/macros.rs index db93dfd..f97f909 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -52,7 +52,7 @@ macro_rules! cfg_io_source { ($($item:item)*) => { $( #[cfg(any(feature = "net", all(unix, feature = "os-ext")))] - #[cfg_attr(docsrs, doc(any(feature = "net", all(unix, feature = "os-ext"))))] + #[cfg_attr(docsrs, doc(cfg(any(feature = "net", all(unix, feature = "os-ext")))))] $item )* } diff --git a/src/sys/unix/tcp.rs b/src/sys/unix/tcp.rs index 70986fa..59642c6 100644 --- a/src/sys/unix/tcp.rs +++ b/src/sys/unix/tcp.rs @@ -429,7 +429,12 @@ pub fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, Socket // On platforms that support it we can use `accept4(2)` to set `NONBLOCK` // and `CLOEXEC` in the call to accept the connection. #[cfg(any( - target_os = "android", + // 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" + ), target_os = "dragonfly", target_os = "freebsd", target_os = "illumos", @@ -450,7 +455,15 @@ pub fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, Socket // But not all platforms have the `accept4(2)` call. Luckily BSD (derived) // OSes inherit the non-blocking flag from the listener, so we just have to // set `CLOEXEC`. - #[cfg(any(target_os = "ios", target_os = "macos", target_os = "solaris"))] + #[cfg(any( + all( + target_arch = "x86", + target_os = "android" + ), + target_os = "ios", + target_os = "macos", + target_os = "solaris" + ))] let stream = { syscall!(accept( listener.as_raw_fd(), @@ -458,7 +471,15 @@ pub fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, Socket &mut length )) .map(|socket| unsafe { net::TcpStream::from_raw_fd(socket) }) - .and_then(|s| syscall!(fcntl(s.as_raw_fd(), libc::F_SETFD, libc::FD_CLOEXEC)).map(|_| s)) + .and_then(|s| { + syscall!(fcntl(s.as_raw_fd(), libc::F_SETFD, libc::FD_CLOEXEC))?; + + // See https://github.com/tokio-rs/mio/issues/1450 + #[cfg(all(target_arch = "x86",target_os = "android"))] + syscall!(fcntl(s.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK))?; + + Ok(s) + }) }?; // This is safe because `accept` calls above ensures the address diff --git a/src/sys/unix/uds/listener.rs b/src/sys/unix/uds/listener.rs index b8fb5a9..547ff57 100644 --- a/src/sys/unix/uds/listener.rs +++ b/src/sys/unix/uds/listener.rs @@ -42,7 +42,13 @@ pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, So target_os = "ios", target_os = "macos", target_os = "netbsd", - target_os = "solaris" + target_os = "solaris", + // 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" + ) )))] let socket = { let flags = libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC; @@ -59,7 +65,11 @@ pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, So target_os = "ios", target_os = "macos", target_os = "netbsd", - target_os = "solaris" + target_os = "solaris", + all( + target_arch = "x86", + target_os = "android" + ) ))] let socket = syscall!(accept( listener.as_raw_fd(), @@ -70,7 +80,13 @@ pub(crate) fn accept(listener: &net::UnixListener) -> io::Result<(UnixStream, So // Ensure the socket is closed if either of the `fcntl` calls // error below. let s = unsafe { net::UnixStream::from_raw_fd(socket) }; - syscall!(fcntl(socket, libc::F_SETFD, libc::FD_CLOEXEC)).map(|_| s) + syscall!(fcntl(socket, libc::F_SETFD, libc::FD_CLOEXEC))?; + + // See https://github.com/tokio-rs/mio/issues/1450 + #[cfg(all(target_arch = "x86",target_os = "android"))] + syscall!(fcntl(socket, libc::F_SETFL, libc::O_NONBLOCK))?; + + Ok(s) }); socket diff --git a/src/sys/windows/afd.rs b/src/sys/windows/afd.rs index bf3704d..6241a45 100644 --- a/src/sys/windows/afd.rs +++ b/src/sys/windows/afd.rs @@ -188,9 +188,11 @@ cfg_io_source! { 0 as ULONG, ); if status != STATUS_SUCCESS { - return Err(io::Error::from_raw_os_error( + let raw_err = io::Error::from_raw_os_error( RtlNtStatusToDosError(status) as i32 - )); + ); + let msg = format!("Failed to open \\Device\\Afd\\Mio: {}", raw_err); + return Err(io::Error::new(raw_err.kind(), msg)); } let fd = File::from_raw_handle(afd_helper_handle as RawHandle); // Increment by 2 to reserve space for other types of handles. diff --git a/src/sys/windows/named_pipe.rs b/src/sys/windows/named_pipe.rs index a5688ce..8c81f38 100644 --- a/src/sys/windows/named_pipe.rs +++ b/src/sys/windows/named_pipe.rs @@ -1,6 +1,6 @@ -use crate::{poll, Registry}; use crate::event::Source; use crate::sys::windows::{Event, Overlapped}; +use crate::{poll, Registry}; use winapi::um::minwinbase::OVERLAPPED_ENTRY; use std::ffi::OsStr; @@ -9,8 +9,8 @@ use std::io::{self, Read, Write}; use std::mem; use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; use std::slice; -use std::sync::atomic::{AtomicUsize, AtomicBool}; use std::sync::atomic::Ordering::{Relaxed, SeqCst}; +use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::{Arc, Mutex}; use crate::{Interest, Token}; @@ -128,9 +128,7 @@ fn would_block() -> io::Error { impl NamedPipe { /// Creates a new named pipe at the specified `addr` given a "reasonable /// set" of initial configuration options. - pub fn new>( - addr: A, - ) -> io::Result { + pub fn new>(addr: A) -> io::Result { let pipe = pipe::NamedPipe::new(addr)?; // Safety: nothing actually unsafe about this. The trait fn includes // `unsafe`. @@ -226,9 +224,7 @@ impl NamedPipe { } impl FromRawHandle for NamedPipe { - unsafe fn from_raw_handle( - handle: RawHandle, - ) -> NamedPipe { + unsafe fn from_raw_handle(handle: RawHandle) -> NamedPipe { NamedPipe { inner: Arc::new(Inner { // Safety: not really unsafe @@ -281,9 +277,7 @@ impl<'a> Read for &'a NamedPipe { match mem::replace(&mut state.read, State::None) { // In theory not possible with `token` checked above, // but return would block for now. - State::None => { - Err(would_block()) - } + State::None => Err(would_block()), // A read is in flight, still waiting for it to finish State::Pending(buf, amt) => { @@ -324,7 +318,7 @@ impl<'a> Read for &'a NamedPipe { } impl<'a> Write for &'a NamedPipe { - fn write(&mut self, buf: &[u8]) -> io::Result { + fn write(&mut self, buf: &[u8]) -> io::Result { // Make sure there's no writes pending let mut io = self.inner.io.lock().unwrap(); @@ -334,6 +328,12 @@ impl<'a> Write for &'a NamedPipe { match io.write { State::None => {} + State::Err(_) => match mem::replace(&mut io.write, State::None) { + State::Err(e) => return Err(e), + // `io` is locked, so this branch is unreachable + _ => unreachable!(), + }, + // any other state should be handled in `write_done` _ => { return Err(would_block()); } @@ -342,17 +342,26 @@ impl<'a> Write for &'a NamedPipe { // Move `buf` onto the heap and fire off the write let mut owned_buf = self.inner.get_buffer(); owned_buf.extend(buf); - Inner::schedule_write(&self.inner, owned_buf, 0, &mut io, None); - Ok(buf.len()) + match Inner::maybe_schedule_write(&self.inner, owned_buf, 0, &mut io)? { + // Some bytes are written immediately + Some(n) => Ok(n), + // Write operation is anqueued for whole buffer + None => Ok(buf.len()), + } } - fn flush(&mut self) -> io::Result<()> { - Ok(()) + fn flush(&mut self) -> io::Result<()> { + Ok(()) } } impl Source for NamedPipe { - fn register(&mut self, registry: &Registry, token: Token, interest: Interest) -> io::Result<()> { + fn register( + &mut self, + registry: &Registry, + token: Token, + interest: Interest, + ) -> io::Result<()> { let mut io = self.inner.io.lock().unwrap(); io.check_association(registry, false)?; @@ -368,7 +377,10 @@ impl Source for NamedPipe { io.cp = Some(poll::selector(registry).clone_port()); let inner_token = NEXT_TOKEN.fetch_add(2, Relaxed) + 2; - poll::selector(registry).inner.cp.add_handle(inner_token, &self.inner.handle)?; + poll::selector(registry) + .inner + .cp + .add_handle(inner_token, &self.inner.handle)?; } io.token = Some(token); @@ -381,7 +393,12 @@ impl Source for NamedPipe { Ok(()) } - fn reregister(&mut self, registry: &Registry, token: Token, interest: Interest) -> io::Result<()> { + fn reregister( + &mut self, + registry: &Registry, + token: Token, + interest: Interest, + ) -> io::Result<()> { let mut io = self.inner.io.lock().unwrap(); io.check_association(registry, true)?; @@ -491,19 +508,61 @@ impl Inner { } } - fn schedule_write(me: &Arc, buf: Vec, pos: usize, io: &mut Io, events: Option<&mut Vec>) { + /// Maybe schedules overlapped write operation. + /// + /// * `None` means that overlapped operation was enqueued + /// * `Some(n)` means that `n` bytes was immediately written. + /// Note, that `write_done` will fire anyway to clean up the state. + fn maybe_schedule_write( + me: &Arc, + buf: Vec, + pos: usize, + io: &mut Io, + ) -> io::Result> { // Very similar to `schedule_read` above, just done for the write half. let e = unsafe { let overlapped = me.write.as_ptr() as *mut _; me.handle.write_overlapped(&buf[pos..], overlapped) }; + // See `connect` above for the rationale behind `forget` match e { - // See `connect` above for the rationale behind `forget` - Ok(_) => { + // `n` bytes are written immediately + Ok(Some(n)) => { + io.write = State::Ok(buf, pos); + mem::forget(me.clone()); + Ok(Some(n)) + } + // write operation is enqueued + Ok(None) => { io.write = State::Pending(buf, pos); - mem::forget(me.clone()) + mem::forget(me.clone()); + Ok(None) } + Err(e) => Err(e), + } + } + + fn schedule_write( + me: &Arc, + buf: Vec, + pos: usize, + io: &mut Io, + events: Option<&mut Vec>, + ) { + match Inner::maybe_schedule_write(me, buf, pos, io) { + Ok(Some(_)) => { + // immediate result will be handled in `write_done`, + // so we'll reinterpret the `Ok` state + let state = mem::replace(&mut io.write, State::None); + io.write = match state { + State::Ok(buf, pos) => State::Pending(buf, pos), + // io is locked, so this branch is unreachable + _ => unreachable!(), + }; + mem::forget(me.clone()); + } + Ok(None) => (), Err(e) => { io.write = State::Err(e); io.notify_writable(events); @@ -610,6 +669,12 @@ fn write_done(status: &OVERLAPPED_ENTRY, events: Option<&mut Vec>) { // then we're writable again and otherwise we schedule another write. let mut io = me.io.lock().unwrap(); let (buf, pos) = match mem::replace(&mut io.write, State::None) { + // `Ok` here means, that the operation was completed immediately + // `bytes_transferred` is already reported to a client + State::Ok(..) => { + io.notify_writable(events); + return; + } State::Pending(buf, pos) => (buf, pos), _ => unreachable!(), }; @@ -638,18 +703,14 @@ fn write_done(status: &OVERLAPPED_ENTRY, events: Option<&mut Vec>) { impl Io { fn check_association(&self, registry: &Registry, required: bool) -> io::Result<()> { match self.cp { - Some(ref cp) if !poll::selector(registry).same_port(cp) => { - Err(io::Error::new( - io::ErrorKind::AlreadyExists, - "I/O source already registered with a different `Registry`" - )) - } - None if required => { - Err(io::Error::new( - io::ErrorKind::NotFound, - "I/O source not registered with `Registry`" - )) - } + Some(ref cp) if !poll::selector(registry).same_port(cp) => Err(io::Error::new( + io::ErrorKind::AlreadyExists, + "I/O source already registered with a different `Registry`", + )), + None if required => Err(io::Error::new( + io::ErrorKind::NotFound, + "I/O source not registered with `Registry`", + )), _ => Ok(()), } } -- cgit v1.2.3