aria_primitives/
wakeup.rs1use std::io::{self, Read, Write};
8use std::os::unix::net::UnixStream;
9
10const DRAIN_BUFFER_BYTES: usize = 64;
11
12pub struct Wakeup {
13 reader: UnixStream,
14 writer: UnixStream,
15}
16
17impl Wakeup {
18 pub fn new() -> Result<Self, WakeupError> {
19 let (reader, writer) = UnixStream::pair().map_err(WakeupError::Create)?;
20 reader
21 .set_nonblocking(true)
22 .map_err(WakeupError::Configure)?;
23 writer
24 .set_nonblocking(true)
25 .map_err(WakeupError::Configure)?;
26 Ok(Self { reader, writer })
27 }
28
29 pub fn clone_reader(&self) -> Result<UnixStream, WakeupError> {
31 self.reader.try_clone().map_err(WakeupError::Duplicate)
32 }
33
34 pub fn clone_writer(&self) -> Result<UnixStream, WakeupError> {
36 self.writer.try_clone().map_err(WakeupError::Duplicate)
37 }
38
39 pub fn signal(&self) -> Result<(), WakeupError> {
41 match (&self.writer).write_all(b"X") {
42 Ok(()) => Ok(()),
43 Err(error) if error.kind() == io::ErrorKind::WouldBlock => Ok(()),
44 Err(error) => Err(WakeupError::Signal(error)),
45 }
46 }
47
48 pub fn drain(&self) -> Result<(), WakeupError> {
49 let mut reader = &self.reader;
50 let mut buffer = [0_u8; DRAIN_BUFFER_BYTES];
51 loop {
52 match reader.read(&mut buffer) {
53 Ok(0) => return Ok(()),
54 Ok(_read) => {}
55 Err(error) if error.kind() == io::ErrorKind::Interrupted => {}
56 Err(error) if error.kind() == io::ErrorKind::WouldBlock => return Ok(()),
57 Err(error) => return Err(WakeupError::Drain(error)),
58 }
59 }
60 }
61}
62
63#[derive(Debug, thiserror::Error)]
64pub enum WakeupError {
65 #[error("failed to create the wakeup socket pair")]
66 Create(#[source] io::Error),
67
68 #[error("failed to configure the wakeup socket pair")]
69 Configure(#[source] io::Error),
70
71 #[error("failed to duplicate the wakeup socket")]
72 Duplicate(#[source] io::Error),
73
74 #[error("failed to signal the wakeup socket")]
75 Signal(#[source] io::Error),
76
77 #[error("failed to drain the wakeup socket")]
78 Drain(#[source] io::Error),
79}