1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use io;
use crateOsQueue;
use crate::;
/// Awakener allows cross-thread waking of [`OsQueue`].
///
/// When created it will cause events with [`Ready::READABLE`] and the provided
/// `id` if [`wake`] is called, possibly from another thread.
///
/// # Notes
///
/// The `Awakener` needs to be kept alive as long as wake up notifications are
/// required. This is due to an implementation detail where if all copies of the
/// `Awakener` are dropped it will also drop all wake up notifications from the
/// system queue, including wake up notifications that have been added before
/// the `Awakener` that was dropped, resulting the [`OsQueue`] not being woken
/// up.
///
/// Only a single `Awakener` should active per [`OsQueue`], the `Awakener` can
/// be cloned using [`try_clone`] if more are needed. What happens if multiple
/// `Awakener`s are registered with the same `OsQueue` is undefined.
///
/// [`Ready::READABLE`]: crate::event::Ready::READABLE
/// [`wake`]: Awakener::wake
/// [`try_clone`]: Awakener::try_clone
///
/// # Implementation notes
///
/// On platforms that support kqueue this will use the `EVFILT_USER` event
/// filter, see [implementation notes of the `os` module] to see what platform
/// supports kqueue. On Linux it uses [eventfd].
///
/// [implementation notes of the `os` module]: ../index.html#implementation-notes
/// [eventfd]: http://man7.org/linux/man-pages/man2/eventfd.2.html
///
/// # Examples
///
/// Wake an [`OsQueue`] from another thread.
///
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use std::io;
/// use std::thread;
/// use std::time::Duration;
///
/// use gaea::{event, poll};
/// use gaea::event::{Event, Ready};
/// use gaea::os::{OsQueue, Awakener};
///
/// const WAKE_ID: event::Id = event::Id(10);
///
/// let mut os_queue = OsQueue::new()?;
/// let mut events = Vec::new();
///
/// let awakener = Awakener::new(&mut os_queue, WAKE_ID)?;
///
/// // We need to keep the Awakener alive, so we'll create a clone for the
/// // thread we create below.
/// let awakener1 = awakener.try_clone()?;
/// let handle = thread::spawn(move || {
/// // Working hard, or hardly working?
/// thread::sleep(Duration::from_millis(500));
///
/// // Now we'll wake the queue on the other thread.
/// awakener1.wake().expect("unable to wake");
/// });
///
/// // On our current thread we'll poll for events, without a timeout.
/// poll::<_, io::Error>(&mut [&mut os_queue], &mut events, None)?;
///
/// // After about 500 milliseconds we should we awoken by the other thread we
/// // started, getting a single event.
/// assert_eq!(events.len(), 1);
/// assert_eq!(events[0], Event::new(WAKE_ID, Ready::READABLE));
/// # handle.join().unwrap();
/// # Ok(())
/// # }
/// ```