|
1 | 1 | use std::collections::BTreeMap;
|
| 2 | +use std::future::Future; |
2 | 3 | use std::io;
|
3 | 4 | use std::mem;
|
4 | 5 | #[cfg(unix)]
|
5 | 6 | use std::os::unix::io::RawFd;
|
6 | 7 | #[cfg(windows)]
|
7 | 8 | use std::os::windows::io::RawSocket;
|
8 | 9 | use std::panic;
|
| 10 | +use std::pin::Pin; |
9 | 11 | use std::sync::atomic::{AtomicUsize, Ordering};
|
10 | 12 | use std::sync::{Arc, Mutex, MutexGuard};
|
11 | 13 | use std::task::{Context, Poll, Waker};
|
12 | 14 | use std::time::{Duration, Instant};
|
13 | 15 |
|
14 | 16 | use concurrent_queue::ConcurrentQueue;
|
15 |
| -use futures_lite::future; |
| 17 | +use futures_lite::ready; |
16 | 18 | use once_cell::sync::Lazy;
|
17 | 19 | use polling::{Event, Poller};
|
18 | 20 | use slab::Slab;
|
@@ -441,78 +443,138 @@ impl Source {
|
441 | 443 | }
|
442 | 444 |
|
443 | 445 | /// Waits until the I/O source is readable.
|
444 |
| - pub(crate) async fn readable(&self) -> io::Result<()> { |
445 |
| - self.ready(READ).await?; |
446 |
| - log::trace!("readable: fd={}", self.raw); |
447 |
| - Ok(()) |
| 446 | + pub(crate) fn readable(self: &Arc<Self>) -> Readable { |
| 447 | + Readable(self.ready(READ)) |
448 | 448 | }
|
449 | 449 |
|
450 | 450 | /// Waits until the I/O source is writable.
|
451 |
| - pub(crate) async fn writable(&self) -> io::Result<()> { |
452 |
| - self.ready(WRITE).await?; |
453 |
| - log::trace!("writable: fd={}", self.raw); |
454 |
| - Ok(()) |
| 451 | + pub(crate) fn writable(self: &Arc<Self>) -> Writable { |
| 452 | + Writable(self.ready(WRITE)) |
455 | 453 | }
|
456 | 454 |
|
457 | 455 | /// Waits until the I/O source is readable or writable.
|
458 |
| - async fn ready(&self, dir: usize) -> io::Result<()> { |
459 |
| - let mut ticks = None; |
460 |
| - let mut index = None; |
461 |
| - let mut _guard = None; |
462 |
| - |
463 |
| - future::poll_fn(|cx| { |
464 |
| - let mut state = self.state.lock().unwrap(); |
465 |
| - |
466 |
| - // Check if the reactor has delivered an event. |
467 |
| - if let Some((a, b)) = ticks { |
468 |
| - // If `state[dir].tick` has changed to a value other than the old reactor tick, |
469 |
| - // that means a newer reactor tick has delivered an event. |
470 |
| - if state[dir].tick != a && state[dir].tick != b { |
471 |
| - return Poll::Ready(Ok(())); |
472 |
| - } |
| 456 | + fn ready(self: &Arc<Self>, dir: usize) -> Ready { |
| 457 | + Ready { |
| 458 | + source: self.clone(), |
| 459 | + dir, |
| 460 | + ticks: None, |
| 461 | + index: None, |
| 462 | + _guard: None, |
| 463 | + } |
| 464 | + } |
| 465 | +} |
| 466 | + |
| 467 | +/// Future for [`Async::readable`](crate::Async::readable). |
| 468 | +#[derive(Debug)] |
| 469 | +#[must_use = "futures do nothing unless you `.await` or poll them"] |
| 470 | +pub struct Readable(Ready); |
| 471 | + |
| 472 | +impl Future for Readable { |
| 473 | + type Output = io::Result<()>; |
| 474 | + |
| 475 | + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 476 | + ready!(Pin::new(&mut self.0).poll(cx))?; |
| 477 | + log::trace!("readable: fd={}", self.0.source.raw); |
| 478 | + Poll::Ready(Ok(())) |
| 479 | + } |
| 480 | +} |
| 481 | + |
| 482 | +/// Future for [`Async::writable`](crate::Async::writable). |
| 483 | +#[derive(Debug)] |
| 484 | +#[must_use = "futures do nothing unless you `.await` or poll them"] |
| 485 | +pub struct Writable(Ready); |
| 486 | + |
| 487 | +impl Future for Writable { |
| 488 | + type Output = io::Result<()>; |
| 489 | + |
| 490 | + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 491 | + ready!(Pin::new(&mut self.0).poll(cx))?; |
| 492 | + log::trace!("writable: fd={}", self.0.source.raw); |
| 493 | + Poll::Ready(Ok(())) |
| 494 | + } |
| 495 | +} |
| 496 | + |
| 497 | +#[derive(Debug)] |
| 498 | +struct Ready { |
| 499 | + source: Arc<Source>, |
| 500 | + dir: usize, |
| 501 | + ticks: Option<(usize, usize)>, |
| 502 | + index: Option<usize>, |
| 503 | + _guard: Option<RemoveOnDrop>, |
| 504 | +} |
| 505 | + |
| 506 | +impl Future for Ready { |
| 507 | + type Output = io::Result<()>; |
| 508 | + |
| 509 | + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
| 510 | + let Self { |
| 511 | + source, |
| 512 | + dir, |
| 513 | + ticks, |
| 514 | + index, |
| 515 | + _guard, |
| 516 | + } = &mut *self; |
| 517 | + |
| 518 | + let mut state = source.state.lock().unwrap(); |
| 519 | + |
| 520 | + // Check if the reactor has delivered an event. |
| 521 | + if let Some((a, b)) = *ticks { |
| 522 | + // If `state[dir].tick` has changed to a value other than the old reactor tick, |
| 523 | + // that means a newer reactor tick has delivered an event. |
| 524 | + if state[*dir].tick != a && state[*dir].tick != b { |
| 525 | + return Poll::Ready(Ok(())); |
473 | 526 | }
|
| 527 | + } |
474 | 528 |
|
475 |
| - let was_empty = state[dir].is_empty(); |
476 |
| - |
477 |
| - // Register the current task's waker. |
478 |
| - let i = match index { |
479 |
| - Some(i) => i, |
480 |
| - None => { |
481 |
| - let i = state[dir].wakers.insert(None); |
482 |
| - _guard = Some(CallOnDrop(move || { |
483 |
| - let mut state = self.state.lock().unwrap(); |
484 |
| - state[dir].wakers.remove(i); |
485 |
| - })); |
486 |
| - index = Some(i); |
487 |
| - ticks = Some((Reactor::get().ticker(), state[dir].tick)); |
488 |
| - i |
489 |
| - } |
490 |
| - }; |
491 |
| - state[dir].wakers[i] = Some(cx.waker().clone()); |
492 |
| - |
493 |
| - // Update interest in this I/O handle. |
494 |
| - if was_empty { |
495 |
| - Reactor::get().poller.modify( |
496 |
| - self.raw, |
497 |
| - Event { |
498 |
| - key: self.key, |
499 |
| - readable: !state[READ].is_empty(), |
500 |
| - writable: !state[WRITE].is_empty(), |
501 |
| - }, |
502 |
| - )?; |
| 529 | + let was_empty = state[*dir].is_empty(); |
| 530 | + |
| 531 | + // Register the current task's waker. |
| 532 | + let i = match *index { |
| 533 | + Some(i) => i, |
| 534 | + None => { |
| 535 | + let i = state[*dir].wakers.insert(None); |
| 536 | + *_guard = Some(RemoveOnDrop { |
| 537 | + source: source.clone(), |
| 538 | + dir: *dir, |
| 539 | + key: i, |
| 540 | + }); |
| 541 | + *index = Some(i); |
| 542 | + *ticks = Some((Reactor::get().ticker(), state[*dir].tick)); |
| 543 | + i |
503 | 544 | }
|
| 545 | + }; |
| 546 | + state[*dir].wakers[i] = Some(cx.waker().clone()); |
504 | 547 |
|
505 |
| - Poll::Pending |
506 |
| - }) |
507 |
| - .await |
| 548 | + // Update interest in this I/O handle. |
| 549 | + if was_empty { |
| 550 | + Reactor::get().poller.modify( |
| 551 | + source.raw, |
| 552 | + Event { |
| 553 | + key: source.key, |
| 554 | + readable: !state[READ].is_empty(), |
| 555 | + writable: !state[WRITE].is_empty(), |
| 556 | + }, |
| 557 | + )?; |
| 558 | + } |
| 559 | + |
| 560 | + Poll::Pending |
508 | 561 | }
|
509 | 562 | }
|
510 | 563 |
|
511 |
| -/// Runs a closure when dropped. |
512 |
| -struct CallOnDrop<F: Fn()>(F); |
| 564 | +/// Remove waker when dropped. |
| 565 | +#[derive(Debug)] |
| 566 | +struct RemoveOnDrop { |
| 567 | + source: Arc<Source>, |
| 568 | + dir: usize, |
| 569 | + key: usize, |
| 570 | +} |
513 | 571 |
|
514 |
| -impl<F: Fn()> Drop for CallOnDrop<F> { |
| 572 | +impl Drop for RemoveOnDrop { |
515 | 573 | fn drop(&mut self) {
|
516 |
| - (self.0)(); |
| 574 | + let mut state = self.source.state.lock().unwrap(); |
| 575 | + let wakers = &mut state[self.dir].wakers; |
| 576 | + if wakers.contains(self.key) { |
| 577 | + wakers.remove(self.key); |
| 578 | + } |
517 | 579 | }
|
518 | 580 | }
|
0 commit comments