mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-07 00:00:08 +02:00
Simultaneous futures compat (#172)
This patch adds opt-in support for futures 0.2.
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
use futures::task::{self, Task};
|
||||
|
||||
use std::fmt;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering::{Acquire, Release};
|
||||
|
||||
use Task;
|
||||
|
||||
/// A synchronization primitive for task notification.
|
||||
///
|
||||
/// `AtomicTask` will coordinate concurrent notifications with the consumer
|
||||
@@ -69,11 +69,6 @@ impl AtomicTask {
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers the **current** task to be notified on calls to `notify`.
|
||||
pub fn register(&self) {
|
||||
self.register_task(task::current());
|
||||
}
|
||||
|
||||
/// Registers the task to be notified on calls to `notify`.
|
||||
///
|
||||
/// The new task will take place of any previous tasks that were registered
|
||||
@@ -89,7 +84,7 @@ impl AtomicTask {
|
||||
/// idea. Concurrent calls to `register` will attempt to register different
|
||||
/// tasks to be notified. One of the callers will win and have its task set,
|
||||
/// but there is no guarantee as to which caller will succeed.
|
||||
pub fn register_task(&self, task: Task) {
|
||||
pub(crate) fn register(&self, task: Task) {
|
||||
match self.state.compare_and_swap(WAITING, LOCKED_WRITE, Acquire) {
|
||||
WAITING => {
|
||||
unsafe {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use {Reactor, Handle};
|
||||
use {Reactor, Handle, Task};
|
||||
use atomic_task::AtomicTask;
|
||||
|
||||
use futures::{Future, Async, Poll};
|
||||
use futures::{Future, Async, Poll, task};
|
||||
|
||||
use std::io;
|
||||
use std::thread;
|
||||
@@ -136,7 +136,8 @@ impl Future for Shutdown {
|
||||
type Error = ();
|
||||
|
||||
fn poll(&mut self) -> Poll<(), ()> {
|
||||
self.inner.shared.shutdown_task.register();
|
||||
let task = Task::Futures1(task::current());
|
||||
self.inner.shared.shutdown_task.register(task);
|
||||
|
||||
if !self.inner.is_shutdown() {
|
||||
return Ok(Async::NotReady);
|
||||
|
||||
@@ -39,6 +39,9 @@ extern crate slab;
|
||||
extern crate tokio_executor;
|
||||
extern crate tokio_io;
|
||||
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
extern crate futures2;
|
||||
|
||||
pub(crate) mod background;
|
||||
mod atomic_task;
|
||||
mod poll_evented;
|
||||
@@ -69,7 +72,6 @@ use std::time::{Duration, Instant};
|
||||
use log::Level;
|
||||
use mio::event::Evented;
|
||||
use slab::Slab;
|
||||
use futures::task::Task;
|
||||
|
||||
/// The core reactor, or event loop.
|
||||
///
|
||||
@@ -155,6 +157,14 @@ fn _assert_kinds() {
|
||||
_assert::<Handle>();
|
||||
}
|
||||
|
||||
/// A wakeup handle for a task, which may be either a futures 0.1 or 0.2 task
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum Task {
|
||||
Futures1(futures::task::Task),
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
Futures2(futures2::task::Waker),
|
||||
}
|
||||
|
||||
// ===== impl Reactor =====
|
||||
|
||||
/// Set the default reactor for the duration of the closure
|
||||
@@ -578,7 +588,7 @@ impl Inner {
|
||||
Direction::Write => (&sched.writer, mio::Ready::writable()),
|
||||
};
|
||||
|
||||
task.register_task(t);
|
||||
task.register(t);
|
||||
|
||||
if sched.readiness.load(SeqCst) & ready.as_usize() != 0 {
|
||||
task.notify();
|
||||
@@ -611,6 +621,17 @@ impl Direction {
|
||||
}
|
||||
}
|
||||
|
||||
impl Task {
|
||||
fn notify(&self) {
|
||||
match *self {
|
||||
Task::Futures1(ref task) => task.notify(),
|
||||
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
Task::Futures2(ref waker) => waker.wake(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "fuchsia")))]
|
||||
mod platform {
|
||||
use mio::Ready;
|
||||
@@ -637,3 +658,19 @@ mod platform {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
fn lift_async<T>(old: futures::Async<T>) -> futures2::Async<T> {
|
||||
match old {
|
||||
futures::Async::Ready(x) => futures2::Async::Ready(x),
|
||||
futures::Async::NotReady => futures2::Async::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
fn lower_async<T>(new: futures2::Async<T>) -> futures::Async<T> {
|
||||
match new {
|
||||
futures2::Async::Ready(x) => futures::Async::Ready(x),
|
||||
futures2::Async::Pending => futures::Async::NotReady,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ use mio;
|
||||
use mio::event::Evented;
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
use futures2;
|
||||
|
||||
use std::fmt;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
@@ -99,7 +102,7 @@ struct Inner {
|
||||
// ===== impl PollEvented =====
|
||||
|
||||
macro_rules! poll_ready {
|
||||
($me:expr, $mask:expr, $cache:ident, $poll:ident, $take:ident) => {{
|
||||
($me:expr, $mask:expr, $cache:ident, $take:ident, $poll:expr) => {{
|
||||
$me.register()?;
|
||||
|
||||
// Load cached & encoded readiness.
|
||||
@@ -114,7 +117,7 @@ macro_rules! poll_ready {
|
||||
// stream. This happens in a loop to ensure that the stream gets
|
||||
// drained.
|
||||
loop {
|
||||
let ready = try_ready!($me.inner.registration.$poll());
|
||||
let ready = try_ready!($poll);
|
||||
cached |= ready.as_usize();
|
||||
|
||||
// Update the cache store
|
||||
@@ -210,7 +213,23 @@ where E: Evented
|
||||
/// * called from outside of a task context.
|
||||
pub fn poll_read_ready(&self, mask: mio::Ready) -> Poll<mio::Ready, io::Error> {
|
||||
assert!(!mask.is_writable(), "cannot poll for write readiness");
|
||||
poll_ready!(self, mask, read_readiness, poll_read_ready, take_read_ready)
|
||||
poll_ready!(
|
||||
self, mask, read_readiness, take_read_ready,
|
||||
self.inner.registration.poll_read_ready()
|
||||
)
|
||||
}
|
||||
|
||||
/// Like `poll_read_ready` but compatible with futures 0.2.
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
pub fn poll_read_ready2(&self, cx: &mut futures2::task::Context, mask: mio::Ready)
|
||||
-> futures2::Poll<mio::Ready, io::Error>
|
||||
{
|
||||
assert!(!mask.is_writable(), "cannot poll for write readiness");
|
||||
let mut res = || poll_ready!(
|
||||
self, mask, read_readiness, take_read_ready,
|
||||
self.inner.registration.poll_read_ready2(cx).map(::lower_async)
|
||||
);
|
||||
res().map(::lift_async)
|
||||
}
|
||||
|
||||
/// Clears the I/O resource's read readiness state and registers the current
|
||||
@@ -243,6 +262,25 @@ where E: Evented
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Like `clear_read_ready` but compatible with futures 0.2.
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
pub fn clear_read_ready2(&self, cx: &mut futures2::task::Context, ready: mio::Ready)
|
||||
-> io::Result<()>
|
||||
{
|
||||
// Cannot clear write readiness
|
||||
assert!(!ready.is_writable(), "cannot clear write readiness");
|
||||
assert!(!::platform::is_hup(&ready), "cannot clear HUP readiness");
|
||||
|
||||
self.inner.read_readiness.fetch_and(!ready.as_usize(), Relaxed);
|
||||
|
||||
if self.poll_read_ready2(cx, ready)?.is_ready() {
|
||||
// Notify the current task
|
||||
cx.waker().wake()
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check the I/O resource's write readiness state.
|
||||
///
|
||||
/// This always checks for writable readiness and also checks for HUP
|
||||
@@ -263,13 +301,31 @@ where E: Evented
|
||||
/// * `ready` contains bits besides `writable` and `hup`.
|
||||
/// * called from outside of a task context.
|
||||
pub fn poll_write_ready(&self) -> Poll<mio::Ready, io::Error> {
|
||||
poll_ready!(self,
|
||||
mio::Ready::writable(),
|
||||
write_readiness,
|
||||
poll_write_ready,
|
||||
take_write_ready)
|
||||
poll_ready!(
|
||||
self,
|
||||
mio::Ready::writable(),
|
||||
write_readiness,
|
||||
take_write_ready,
|
||||
self.inner.registration.poll_write_ready()
|
||||
)
|
||||
}
|
||||
|
||||
/// Like `poll_write_ready` but compatible with futures 0.2.
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
pub fn poll_write_ready2(&self, cx: &mut futures2::task::Context)
|
||||
-> futures2::Poll<mio::Ready, io::Error>
|
||||
{
|
||||
let mut res = || poll_ready!(
|
||||
self,
|
||||
mio::Ready::writable(),
|
||||
write_readiness,
|
||||
take_write_ready,
|
||||
self.inner.registration.poll_write_ready2(cx).map(::lower_async)
|
||||
);
|
||||
res().map(::lift_async)
|
||||
}
|
||||
|
||||
|
||||
/// Resets the I/O resource's write readiness state and registers the current
|
||||
/// task to be notified once a write readiness event is received.
|
||||
///
|
||||
@@ -295,6 +351,21 @@ where E: Evented
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Like `clear_write_ready`, but compatible with futures 0.2.
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
pub fn clear_write_ready2(&self, cx: &mut futures2::task::Context) -> io::Result<()> {
|
||||
let ready = mio::Ready::writable();
|
||||
|
||||
self.inner.read_readiness.fetch_and(!ready.as_usize(), Relaxed);
|
||||
|
||||
if self.poll_write_ready2(cx)?.is_ready() {
|
||||
// Notify the current task
|
||||
cx.waker().wake()
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensure that the I/O resource is registered with the reactor.
|
||||
fn register(&self) -> io::Result<()> {
|
||||
self.inner.registration.register(self.io.as_ref().unwrap())?;
|
||||
@@ -322,6 +393,28 @@ where E: Evented + Read,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
impl<E> futures2::io::AsyncRead for PollEvented<E>
|
||||
where E: Evented, E: Read,
|
||||
{
|
||||
fn poll_read(&mut self, cx: &mut futures2::task::Context, buf: &mut [u8])
|
||||
-> futures2::Poll<usize, io::Error>
|
||||
{
|
||||
if let futures2::Async::Pending = self.poll_read_ready2(cx, mio::Ready::readable())? {
|
||||
return Ok(futures2::Async::Pending);
|
||||
}
|
||||
|
||||
match self.get_mut().read(buf) {
|
||||
Ok(n) => Ok(futures2::Async::Ready(n)),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
self.clear_read_ready2(cx, mio::Ready::readable())?;
|
||||
Ok(futures2::Async::Pending)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> Write for PollEvented<E>
|
||||
where E: Evented + Write,
|
||||
{
|
||||
@@ -354,6 +447,48 @@ where E: Evented + Write,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
impl<E> futures2::io::AsyncWrite for PollEvented<E>
|
||||
where E: Evented, E: Write,
|
||||
{
|
||||
fn poll_write(&mut self, cx: &mut futures2::task::Context, buf: &[u8])
|
||||
-> futures2::Poll<usize, io::Error>
|
||||
{
|
||||
if let futures2::Async::Pending = self.poll_write_ready2(cx)? {
|
||||
return Ok(futures2::Async::Pending);
|
||||
}
|
||||
|
||||
match self.get_mut().write(buf) {
|
||||
Ok(n) => Ok(futures2::Async::Ready(n)),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
self.clear_write_ready2(cx)?;
|
||||
Ok(futures2::Async::Pending)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(&mut self, cx: &mut futures2::task::Context) -> futures2::Poll<(), io::Error> {
|
||||
if let futures2::Async::Pending = self.poll_write_ready2(cx)? {
|
||||
return Ok(futures2::Async::Pending);
|
||||
}
|
||||
|
||||
match self.get_mut().flush() {
|
||||
Ok(_) => Ok(futures2::Async::Ready(())),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
self.clear_write_ready2(cx)?;
|
||||
Ok(futures2::Async::Pending)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_close(&mut self, cx: &mut futures2::task::Context) -> futures2::Poll<(), io::Error> {
|
||||
futures2::io::AsyncWrite::poll_flush(self, cx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<E> AsyncRead for PollEvented<E>
|
||||
where E: Evented + Read,
|
||||
{
|
||||
@@ -387,6 +522,28 @@ where E: Evented, &'a E: Read,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
impl<'a, E> futures2::io::AsyncRead for &'a PollEvented<E>
|
||||
where E: Evented, &'a E: Read,
|
||||
{
|
||||
fn poll_read(&mut self, cx: &mut futures2::task::Context, buf: &mut [u8])
|
||||
-> futures2::Poll<usize, io::Error>
|
||||
{
|
||||
if let futures2::Async::Pending = self.poll_read_ready2(cx, mio::Ready::readable())? {
|
||||
return Ok(futures2::Async::Pending);
|
||||
}
|
||||
|
||||
match self.get_ref().read(buf) {
|
||||
Ok(n) => Ok(futures2::Async::Ready(n)),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
self.clear_read_ready2(cx, mio::Ready::readable())?;
|
||||
Ok(futures2::Async::Pending)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> Write for &'a PollEvented<E>
|
||||
where E: Evented, &'a E: Write,
|
||||
{
|
||||
@@ -419,6 +576,47 @@ where E: Evented, &'a E: Write,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
impl<'a, E> futures2::io::AsyncWrite for &'a PollEvented<E>
|
||||
where E: Evented, &'a E: Write,
|
||||
{
|
||||
fn poll_write(&mut self, cx: &mut futures2::task::Context, buf: &[u8])
|
||||
-> futures2::Poll<usize, io::Error>
|
||||
{
|
||||
if let futures2::Async::Pending = self.poll_write_ready2(cx)? {
|
||||
return Ok(futures2::Async::Pending);
|
||||
}
|
||||
|
||||
match self.get_ref().write(buf) {
|
||||
Ok(n) => Ok(futures2::Async::Ready(n)),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
self.clear_write_ready2(cx)?;
|
||||
Ok(futures2::Async::Pending)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(&mut self, cx: &mut futures2::task::Context) -> futures2::Poll<(), io::Error> {
|
||||
if let futures2::Async::Pending = self.poll_write_ready2(cx)? {
|
||||
return Ok(futures2::Async::Pending);
|
||||
}
|
||||
|
||||
match self.get_ref().flush() {
|
||||
Ok(_) => Ok(futures2::Async::Ready(())),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
self.clear_write_ready2(cx)?;
|
||||
Ok(futures2::Async::Pending)
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_close(&mut self, cx: &mut futures2::task::Context) -> futures2::Poll<(), io::Error> {
|
||||
futures2::io::AsyncWrite::poll_flush(self, cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> AsyncRead for &'a PollEvented<E>
|
||||
where E: Evented, &'a E: Read,
|
||||
{
|
||||
@@ -439,7 +637,6 @@ fn is_wouldblock<T>(r: &io::Result<T>) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<E: Evented + fmt::Debug> fmt::Debug for PollEvented<E> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("PollEvented")
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use {Handle, Direction};
|
||||
use {Handle, Direction, Task};
|
||||
|
||||
use futures::{Async, Poll};
|
||||
use futures::task::{self, Task};
|
||||
use futures::{Async, Poll, task};
|
||||
use mio::{self, Evented};
|
||||
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
use futures2;
|
||||
|
||||
use std::{io, mem, usize};
|
||||
use std::cell::UnsafeCell;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
@@ -271,13 +273,26 @@ impl Registration {
|
||||
///
|
||||
/// This function will panic if called from outside of a task context.
|
||||
pub fn poll_read_ready(&self) -> Poll<mio::Ready, io::Error> {
|
||||
self.poll_ready(Direction::Read, true)
|
||||
self.poll_ready(Direction::Read, true, || Task::Futures1(task::current()))
|
||||
.map(|v| match v {
|
||||
Some(v) => Async::Ready(v),
|
||||
_ => Async::NotReady,
|
||||
})
|
||||
}
|
||||
|
||||
/// Like `poll_ready_ready`, but compatible with futures 0.2
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
pub fn poll_read_ready2(&self, cx: &mut futures2::task::Context)
|
||||
-> futures2::Poll<mio::Ready, io::Error>
|
||||
{
|
||||
use futures2::Async as Async2;
|
||||
self.poll_ready(Direction::Read, true, || Task::Futures2(cx.waker().clone()))
|
||||
.map(|v| match v {
|
||||
Some(v) => Async2::Ready(v),
|
||||
_ => Async2::Pending,
|
||||
})
|
||||
}
|
||||
|
||||
/// Consume any pending read readiness event.
|
||||
///
|
||||
/// This function is identical to [`poll_read_ready`] **except** that it
|
||||
@@ -286,7 +301,7 @@ impl Registration {
|
||||
///
|
||||
/// [`poll_read_ready`]: #method.poll_read_ready
|
||||
pub fn take_read_ready(&self) -> io::Result<Option<mio::Ready>> {
|
||||
self.poll_ready(Direction::Read, false)
|
||||
self.poll_ready(Direction::Read, false, || panic!())
|
||||
|
||||
}
|
||||
|
||||
@@ -323,13 +338,26 @@ impl Registration {
|
||||
///
|
||||
/// This function will panic if called from outside of a task context.
|
||||
pub fn poll_write_ready(&self) -> Poll<mio::Ready, io::Error> {
|
||||
self.poll_ready(Direction::Write, true)
|
||||
self.poll_ready(Direction::Write, true, || Task::Futures1(task::current()))
|
||||
.map(|v| match v {
|
||||
Some(v) => Async::Ready(v),
|
||||
_ => Async::NotReady,
|
||||
})
|
||||
}
|
||||
|
||||
/// Like `poll_write_ready`, but compatible with futures 0.2
|
||||
#[cfg(feature = "unstable-futures")]
|
||||
pub fn poll_write_ready2(&self, cx: &mut futures2::task::Context)
|
||||
-> futures2::Poll<mio::Ready, io::Error>
|
||||
{
|
||||
use futures2::Async as Async2;
|
||||
self.poll_ready(Direction::Write, true, || Task::Futures2(cx.waker().clone()))
|
||||
.map(|v| match v {
|
||||
Some(v) => Async2::Ready(v),
|
||||
_ => Async2::Pending,
|
||||
})
|
||||
}
|
||||
|
||||
/// Consume any pending write readiness event.
|
||||
///
|
||||
/// This function is identical to [`poll_write_ready`] **except** that it
|
||||
@@ -338,11 +366,12 @@ impl Registration {
|
||||
///
|
||||
/// [`poll_write_ready`]: #method.poll_write_ready
|
||||
pub fn take_write_ready(&self) -> io::Result<Option<mio::Ready>> {
|
||||
self.poll_ready(Direction::Write, false)
|
||||
self.poll_ready(Direction::Write, false, || unreachable!())
|
||||
}
|
||||
|
||||
fn poll_ready(&self, direction: Direction, notify: bool)
|
||||
fn poll_ready<F>(&self, direction: Direction, notify: bool, task: F)
|
||||
-> io::Result<Option<mio::Ready>>
|
||||
where F: Fn() -> Task
|
||||
{
|
||||
let mut state = self.state.load(SeqCst);
|
||||
|
||||
@@ -357,7 +386,7 @@ impl Registration {
|
||||
}
|
||||
READY => {
|
||||
let inner = unsafe { (*self.inner.get()).as_ref().unwrap() };
|
||||
return inner.poll_ready(direction, notify);
|
||||
return inner.poll_ready(direction, notify, task);
|
||||
}
|
||||
_ => {
|
||||
if !notify {
|
||||
@@ -371,7 +400,7 @@ impl Registration {
|
||||
let mut n = node.take().unwrap_or_else(|| {
|
||||
Box::new(Node {
|
||||
direction,
|
||||
task: task::current(),
|
||||
task: task(),
|
||||
next: None,
|
||||
})
|
||||
});
|
||||
@@ -472,8 +501,9 @@ impl Inner {
|
||||
inner.deregister_source(io)
|
||||
}
|
||||
|
||||
fn poll_ready(&self, direction: Direction, notify: bool)
|
||||
fn poll_ready<F>(&self, direction: Direction, notify: bool, task: F)
|
||||
-> io::Result<Option<mio::Ready>>
|
||||
where F: FnOnce() -> Task
|
||||
{
|
||||
if self.token == ERROR {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "failed to associate with reactor"));
|
||||
@@ -504,8 +534,8 @@ impl Inner {
|
||||
if ready.is_empty() && notify {
|
||||
// Update the task info
|
||||
match direction {
|
||||
Direction::Read => sched.reader.register(),
|
||||
Direction::Write => sched.writer.register(),
|
||||
Direction::Read => sched.reader.register(task()),
|
||||
Direction::Write => sched.writer.register(task()),
|
||||
}
|
||||
|
||||
// Try again
|
||||
|
||||
Reference in New Issue
Block a user