| 1 | use crate::{sys, Registry, Token}; |
| 2 | |
| 3 | use std::io; |
| 4 | |
| 5 | /// Waker allows cross-thread waking of [`Poll`]. |
| 6 | /// |
| 7 | /// When created it will cause events with [`readable`] readiness and the |
| 8 | /// provided `token` if [`wake`] is called, possibly from another thread. |
| 9 | /// |
| 10 | /// [`Poll`]: struct.Poll.html |
| 11 | /// [`readable`]: ./event/struct.Event.html#method.is_readable |
| 12 | /// [`wake`]: struct.Waker.html#method.wake |
| 13 | /// |
| 14 | /// # Notes |
| 15 | /// |
| 16 | /// `Waker` events are only guaranteed to be delivered while the `Waker` value |
| 17 | /// is alive. |
| 18 | /// |
| 19 | /// Only a single `Waker` can be active per [`Poll`], if multiple threads need |
| 20 | /// access to the `Waker` it can be shared via for example an `Arc`. What |
| 21 | /// happens if multiple `Waker`s are registered with the same `Poll` is |
| 22 | /// unspecified. |
| 23 | /// |
| 24 | /// # Implementation notes |
| 25 | /// |
| 26 | /// On platforms that support kqueue this will use the `EVFILT_USER` event |
| 27 | /// filter, see [implementation notes of `Poll`] to see what platforms support |
| 28 | /// kqueue. On Linux it uses [eventfd]. |
| 29 | /// |
| 30 | /// [implementation notes of `Poll`]: struct.Poll.html#implementation-notes |
| 31 | /// [eventfd]: https://man7.org/linux/man-pages/man2/eventfd.2.html |
| 32 | /// |
| 33 | /// # Examples |
| 34 | /// |
| 35 | /// Wake a [`Poll`] instance from another thread. |
| 36 | /// |
| 37 | #[cfg_attr (feature = "os-poll" , doc = "```" )] |
| 38 | #[cfg_attr (not(feature = "os-poll" ), doc = "```ignore" )] |
| 39 | /// # fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 40 | /// use std::thread; |
| 41 | /// use std::time::Duration; |
| 42 | /// use std::sync::Arc; |
| 43 | /// |
| 44 | /// use mio::{Events, Token, Poll, Waker}; |
| 45 | /// |
| 46 | /// const WAKE_TOKEN: Token = Token(10); |
| 47 | /// |
| 48 | /// let mut poll = Poll::new()?; |
| 49 | /// let mut events = Events::with_capacity(2); |
| 50 | /// |
| 51 | /// let waker = Arc::new(Waker::new(poll.registry(), WAKE_TOKEN)?); |
| 52 | /// |
| 53 | /// // We need to keep the Waker alive, so we'll create a clone for the |
| 54 | /// // thread we create below. |
| 55 | /// let waker1 = waker.clone(); |
| 56 | /// let handle = thread::spawn(move || { |
| 57 | /// // Working hard, or hardly working? |
| 58 | /// thread::sleep(Duration::from_millis(500)); |
| 59 | /// |
| 60 | /// // Now we'll wake the queue on the other thread. |
| 61 | /// waker1.wake().expect("unable to wake" ); |
| 62 | /// }); |
| 63 | /// |
| 64 | /// // On our current thread we'll poll for events, without a timeout. |
| 65 | /// poll.poll(&mut events, None)?; |
| 66 | /// |
| 67 | /// // After about 500 milliseconds we should be awoken by the other thread and |
| 68 | /// // get a single event. |
| 69 | /// assert!(!events.is_empty()); |
| 70 | /// let waker_event = events.iter().next().unwrap(); |
| 71 | /// assert!(waker_event.is_readable()); |
| 72 | /// assert_eq!(waker_event.token(), WAKE_TOKEN); |
| 73 | /// # handle.join().unwrap(); |
| 74 | /// # Ok(()) |
| 75 | /// # } |
| 76 | /// ``` |
| 77 | #[derive (Debug)] |
| 78 | pub struct Waker { |
| 79 | inner: sys::Waker, |
| 80 | } |
| 81 | |
| 82 | impl Waker { |
| 83 | /// Create a new `Waker`. |
| 84 | pub fn new(registry: &Registry, token: Token) -> io::Result<Waker> { |
| 85 | #[cfg (debug_assertions)] |
| 86 | registry.register_waker(); |
| 87 | sys::Waker::new(registry.selector(), token).map(|inner: Waker| Waker { inner }) |
| 88 | } |
| 89 | |
| 90 | /// Wake up the [`Poll`] associated with this `Waker`. |
| 91 | /// |
| 92 | /// [`Poll`]: struct.Poll.html |
| 93 | pub fn wake(&self) -> io::Result<()> { |
| 94 | self.inner.wake() |
| 95 | } |
| 96 | } |
| 97 | |