Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: bump tokio to v1 #55

Merged
merged 1 commit into from
Mar 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ matrix:

# MSRV
- env: TARGET=x86_64-unknown-linux-gnu DISABLE_TESTS=1
rust: 1.39.0
rust: 1.45.0
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)

before_install:
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## v0.5.0

- Update Tokio to 1.x. #[55]((https://github.com/rust-embedded/gpio-cdev/pull/55).
- Breaking change of `LineEventHandle::get_event()` which now expects `&mut self`.
- MSRV is now 1.45.0


## v0.4.0 - 2020-08-01

- Removed pub "errors" module. Error now exposed at top level.
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ edition = "2018"

[features]
default = []
async-tokio = ["tokio", "futures", "mio"]
async-tokio = ["tokio", "futures"]

[[example]]
name = "async_tokio"
Expand All @@ -23,13 +23,13 @@ required-features = ["async-tokio"]
bitflags = "1.0"
libc = "0.2"
nix = "0.14"
tokio = { version = "0.2", features = ["io-driver", "rt-threaded", "macros"], optional = true }
tokio = { version = "1", features = ["io-std", "net"], optional = true }
futures = { version = "0.3", optional = true }
mio = { version = "0.6", optional = true }

[dev-dependencies]
quicli = "0.2"
anyhow = "1.0"
tokio = { version = "1", features = ["io-std", "rt-multi-thread", "macros", "net"] }

[package.metadata.docs.rs]
# To build locally:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ to be considered reliable.

## Minimum Supported Rust Version (MSRV)

This crate is guaranteed to compile on stable Rust 1.39.0 and up. It *might*
This crate is guaranteed to compile on stable Rust 1.45.0 and up. It *might*
compile with older versions but that may change in any new patch release.

## License
Expand Down
71 changes: 18 additions & 53 deletions src/async_tokio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,48 +11,14 @@
use futures::ready;
use futures::stream::Stream;
use futures::task::{Context, Poll};
use mio::event::Evented;
use mio::unix::EventedFd;
use mio::{PollOpt, Ready, Token};
use tokio::io::PollEvented;
use tokio::io::unix::{AsyncFd, TryIoError};

use std::io;
use std::os::unix::io::AsRawFd;
use std::pin::Pin;

use super::event_err;
use super::{LineEvent, LineEventHandle, Result};

struct PollWrapper {
handle: LineEventHandle,
}

impl Evented for PollWrapper {
fn register(
&self,
poll: &mio::Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
EventedFd(&self.handle.file.as_raw_fd()).register(poll, token, interest, opts)
}

fn reregister(
&self,
poll: &mio::Poll,
token: Token,
interest: Ready,
opts: PollOpt,
) -> io::Result<()> {
EventedFd(&self.handle.file.as_raw_fd()).reregister(poll, token, interest, opts)
}

fn deregister(&self, poll: &mio::Poll) -> io::Result<()> {
EventedFd(&self.handle.file.as_raw_fd()).deregister(poll)
}
}

/// Wrapper around a `LineEventHandle` which implements a `futures::stream::Stream` for interrupts.
///
/// # Example
Expand Down Expand Up @@ -88,7 +54,7 @@ impl Evented for PollWrapper {
/// # }
/// ```
pub struct AsyncLineEventHandle {
evented: PollEvented<PollWrapper>,
asyncfd: AsyncFd<LineEventHandle>,
}

impl AsyncLineEventHandle {
Expand All @@ -106,36 +72,35 @@ impl AsyncLineEventHandle {
}

Ok(AsyncLineEventHandle {
evented: PollEvented::new(PollWrapper { handle })?,
asyncfd: AsyncFd::new(handle)?,
})
}
}

impl Stream for AsyncLineEventHandle {
type Item = Result<LineEvent>;

fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let ready = Ready::readable();
if let Err(e) = ready!(self.evented.poll_read_ready(cx, ready)) {
return Poll::Ready(Some(Err(e.into())));
}

match self.evented.get_ref().handle.read_event() {
Ok(Some(event)) => Poll::Ready(Some(Ok(event))),
Ok(None) => Poll::Ready(Some(Err(event_err(nix::Error::Sys(
nix::errno::Errno::EIO,
))))),
Err(nix::Error::Sys(nix::errno::Errno::EAGAIN)) => {
self.evented.clear_read_ready(cx, ready)?;
Poll::Pending
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
loop {
ryankurte marked this conversation as resolved.
Show resolved Hide resolved
let mut guard = ready!(self.asyncfd.poll_read_ready_mut(cx))?;
match guard.try_io(|inner| inner.get_mut().read_event()) {
Err(TryIoError { .. }) => {
// Continue
}
Ok(Ok(Some(event))) => return Poll::Ready(Some(Ok(event))),
Ok(Ok(None)) => {
return Poll::Ready(Some(Err(event_err(nix::Error::Sys(
nix::errno::Errno::EIO,
)))))
}
Ok(Err(err)) => return Poll::Ready(Some(Err(err.into()))),
}
Err(e) => Poll::Ready(Some(Err(event_err(e)))),
}
}
}

impl AsRef<LineEventHandle> for AsyncLineEventHandle {
fn as_ref(&self) -> &LineEventHandle {
&self.evented.get_ref().handle
&self.asyncfd.get_ref()
}
}
15 changes: 6 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ extern crate nix;
use std::cmp::min;
use std::ffi::CStr;
use std::fs::{read_dir, File, ReadDir};
use std::io::Read;
use std::mem;
use std::ops::Index;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
Expand Down Expand Up @@ -954,11 +955,11 @@ impl LineEventHandle {
/// This blocks while there is not another event available from the
/// kernel for the line which matches the subscription criteria
/// specified in the `event_flags` when the handle was created.
pub fn get_event(&self) -> Result<LineEvent> {
pub fn get_event(&mut self) -> Result<LineEvent> {
match self.read_event() {
Ok(Some(event)) => Ok(event),
Ok(None) => Err(event_err(nix::Error::Sys(nix::errno::Errno::EIO))),
Err(e) => Err(event_err(e)),
Err(e) => Err(e.into()),
}
}

Expand All @@ -981,19 +982,15 @@ impl LineEventHandle {

/// Helper function which returns the line event if a complete event was read, Ok(None) if not
/// enough data was read or the error returned by `read()`.
///
/// This function allows access to the raw `nix::Error` as required, for example, to theck
/// whether read() returned -EAGAIN.
pub(crate) fn read_event(&self) -> std::result::Result<Option<LineEvent>, nix::Error> {
pub(crate) fn read_event(&mut self) -> std::io::Result<Option<LineEvent>> {
let mut data: ffi::gpioevent_data = unsafe { mem::zeroed() };
let mut data_as_buf = unsafe {
slice::from_raw_parts_mut(
&mut data as *mut ffi::gpioevent_data as *mut u8,
mem::size_of::<ffi::gpioevent_data>(),
)
};
let bytes_read = nix::unistd::read(self.file.as_raw_fd(), &mut data_as_buf)?;

let bytes_read = self.file.read(&mut data_as_buf)?;
if bytes_read != mem::size_of::<ffi::gpioevent_data>() {
Ok(None)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again not really related to this PR (sorry, it's just caught my attention)... do you think there is any case in which a partial read should occur during operation?

i wonder whether this line is hiding dropping some data / a partial cause of #51, and whether this should instead be something like:

if bytes_read == 0 {
  return Ok(None);
else if bytes_read < mem::sizeof::... {
  // Error? Flush (drop events but recover)?
} ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, possibly. Do you know if a gpio char device can return partial packets? Couldn't find anything about that.

I couldn't repeat that select! error locally either, tested with master branch. Not running on a raspberry though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the way that the file works in the kernel for a character device, I wouldn't ever expect a read call to return a partial structure. I'll have to consider the linked issue but I don't think that branch would ever be hit in practice.

} else {
Expand All @@ -1016,7 +1013,7 @@ impl Iterator for LineEventHandle {
match self.read_event() {
Ok(None) => None,
Ok(Some(event)) => Some(Ok(event)),
Err(e) => Some(Err(event_err(e))),
Err(e) => Some(Err(e.into())),
}
}
}