1use std::{
4 cell::UnsafeCell,
5 io::{self, Read, Write},
6 net::Shutdown,
7 os::unix::net::UnixStream,
8 sync::{
9 Arc,
10 atomic::{AtomicBool, AtomicI32, AtomicUsize, Ordering},
11 },
12 time::{Duration, Instant},
13};
14
15use super::{SyncTransport, proactor};
16
17#[repr(align(64))]
18struct Cursor(AtomicUsize);
19
20struct MemoryLane {
21 bytes: Box<[UnsafeCell<u8>]>,
22 head: Cursor,
23 tail: Cursor,
24 reader_alive: AtomicBool,
25 writer_alive: AtomicBool,
26 error: AtomicI32,
27 #[cfg(test)]
28 waiting: Arc<AtomicBool>,
29}
30
31unsafe impl Sync for MemoryLane {}
36
37impl MemoryLane {
38 fn new(capacity: usize) -> io::Result<Self> {
39 let mut bytes = Vec::new();
40 bytes
41 .try_reserve_exact(capacity)
42 .map_err(io::Error::other)?;
43 bytes.resize_with(capacity, || UnsafeCell::new(0));
44 Ok(Self {
45 bytes: bytes.into_boxed_slice(),
46 head: Cursor(AtomicUsize::new(0)),
47 tail: Cursor(AtomicUsize::new(0)),
48 reader_alive: AtomicBool::new(true),
49 writer_alive: AtomicBool::new(true),
50 error: AtomicI32::new(0),
51 #[cfg(test)]
52 waiting: Arc::new(AtomicBool::new(false)),
53 })
54 }
55
56 fn distance(&self, head: usize, tail: usize) -> usize {
57 if tail >= head {
58 tail - head
59 } else {
60 self.bytes.len() * 2 - head + tail
61 }
62 }
63
64 fn advance(&self, cursor: usize, count: usize) -> usize {
65 let until_wrap = self.bytes.len() * 2 - cursor;
66 if count >= until_wrap {
67 count - until_wrap
68 } else {
69 cursor + count
70 }
71 }
72
73 fn read(&self, destination: &mut [u8]) -> usize {
74 let head = self.head.0.load(Ordering::Relaxed);
75 let tail = self.tail.0.load(Ordering::Acquire);
76 let count = destination.len().min(self.distance(head, tail));
77 if count == 0 {
78 return 0;
79 }
80 let start = head % self.bytes.len();
81 let first = count.min(self.bytes.len() - start);
82 unsafe {
86 std::ptr::copy_nonoverlapping(self.bytes[start].get(), destination.as_mut_ptr(), first);
87 std::ptr::copy_nonoverlapping(
88 self.bytes[0].get(),
89 destination.as_mut_ptr().add(first),
90 count - first,
91 );
92 }
93 self.head
94 .0
95 .store(self.advance(head, count), Ordering::Release);
96 count
97 }
98
99 fn write(&self, source: &[u8]) -> usize {
100 let tail = self.tail.0.load(Ordering::Relaxed);
101 let head = self.head.0.load(Ordering::Acquire);
102 let count = source
103 .len()
104 .min(self.bytes.len() - self.distance(head, tail));
105 if count == 0 {
106 return 0;
107 }
108 let start = tail % self.bytes.len();
109 let first = count.min(self.bytes.len() - start);
110 unsafe {
114 std::ptr::copy_nonoverlapping(source.as_ptr(), self.bytes[start].get(), first);
115 std::ptr::copy_nonoverlapping(
116 source.as_ptr().add(first),
117 self.bytes[0].get(),
118 count - first,
119 );
120 }
121 self.tail
122 .0
123 .store(self.advance(tail, count), Ordering::Release);
124 count
125 }
126
127 fn check_error(&self) -> io::Result<()> {
128 match self.error.load(Ordering::Acquire) {
129 0 => Ok(()),
130 errno => Err(io::Error::from_raw_os_error(errno)),
131 }
132 }
133}
134
135pub struct MemoryPipe {
139 incoming: Arc<MemoryLane>,
140 outgoing: Arc<MemoryLane>,
141 wake: UnixStream,
142 nonblocking: bool,
143 read_timeout: Option<Duration>,
144 write_timeout: Option<Duration>,
145}
146
147impl MemoryPipe {
148 pub fn pair() -> (Self, Self) {
153 Self::with_capacity(64 * 1024).expect("cannot create default memory pipe")
154 }
155
156 pub fn with_capacity(capacity: usize) -> io::Result<(Self, Self)> {
161 if capacity == 0 || capacity > isize::MAX as usize {
162 return Err(io::Error::new(
163 io::ErrorKind::InvalidInput,
164 "memory capacity must be positive and fit an allocation",
165 ));
166 }
167 let incoming = Arc::new(MemoryLane::new(capacity)?);
168 let outgoing = Arc::new(MemoryLane::new(capacity)?);
169 let (first, second) = UnixStream::pair()?;
170 let endpoint = |incoming, outgoing, wake| Self {
171 incoming,
172 outgoing,
173 wake,
174 nonblocking: false,
175 read_timeout: None,
176 write_timeout: None,
177 };
178 Ok((
179 endpoint(Arc::clone(&incoming), Arc::clone(&outgoing), first),
180 endpoint(outgoing, incoming, second),
181 ))
182 }
183
184 fn validate_timeout(timeout: Option<Duration>) -> io::Result<()> {
185 if timeout.is_some_and(|duration| {
186 duration.is_zero() || Instant::now().checked_add(duration).is_none()
187 }) {
188 return Err(io::Error::new(
189 io::ErrorKind::InvalidInput,
190 "timeout must be nonzero and fit the monotonic clock",
191 ));
192 }
193 Ok(())
194 }
195
196 fn notify(&self) {
197 loop {
198 match proactor::write(&self.wake, &[1], None, true) {
199 Ok(1) => return,
200 Err(error) if error.kind() == io::ErrorKind::WouldBlock => return,
202 Err(error) if error.kind() == io::ErrorKind::Interrupted => continue,
203 Err(error)
204 if matches!(
205 error.kind(),
206 io::ErrorKind::BrokenPipe | io::ErrorKind::ConnectionReset
207 ) && !self.outgoing.reader_alive.load(Ordering::Acquire) =>
208 {
209 return;
210 }
211 result => {
212 let errno = match result {
216 Err(error) => error.raw_os_error().unwrap_or(libc::EIO),
217 Ok(_) => libc::EIO,
218 };
219 self.incoming.error.store(errno, Ordering::Release);
220 self.outgoing.error.store(errno, Ordering::Release);
221 if let Err(error) = self.wake.shutdown(Shutdown::Both) {
222 self.incoming
223 .error
224 .store(error.raw_os_error().unwrap_or(libc::EIO), Ordering::Release);
225 self.outgoing
226 .error
227 .store(error.raw_os_error().unwrap_or(libc::EIO), Ordering::Release);
228 }
229 return;
230 }
231 }
232 }
233 }
234
235 fn drain_notification(&self) -> io::Result<()> {
236 match proactor::read(&self.wake, &mut [0; 256], None, true) {
237 Ok(_) => Ok(()),
238 Err(error)
239 if matches!(
240 error.kind(),
241 io::ErrorKind::WouldBlock | io::ErrorKind::Interrupted
242 ) =>
243 {
244 Ok(())
245 }
246 Err(error)
247 if matches!(
248 error.kind(),
249 io::ErrorKind::ConnectionReset | io::ErrorKind::BrokenPipe
250 ) && !self.incoming.writer_alive.load(Ordering::Acquire) =>
251 {
252 Ok(())
253 }
254 Err(error) => Err(error),
255 }
256 }
257
258 fn wait(&self, lane: &MemoryLane, deadline: Option<Instant>) -> io::Result<()> {
259 let remaining = deadline
260 .map(|deadline| {
261 deadline
262 .checked_duration_since(Instant::now())
263 .ok_or_else(|| io::Error::from(io::ErrorKind::TimedOut))
264 })
265 .transpose()?;
266 #[cfg(test)]
267 lane.waiting.store(true, Ordering::Release);
268 #[cfg(not(test))]
269 lane.check_error()?;
270 proactor::readable(&self.wake, remaining)
271 }
272
273 #[cfg(test)]
274 pub(super) fn wait_flag(&self, writing: bool) -> Arc<AtomicBool> {
275 Arc::clone(
276 &if writing {
277 &self.outgoing
278 } else {
279 &self.incoming
280 }
281 .waiting,
282 )
283 }
284}
285
286impl Read for MemoryPipe {
287 fn read(&mut self, destination: &mut [u8]) -> io::Result<usize> {
288 if destination.is_empty() {
289 return Ok(0);
290 }
291 let deadline = self
292 .read_timeout
293 .and_then(|timeout| Instant::now().checked_add(timeout));
294 let mut drained = false;
295 loop {
296 let count = self.incoming.read(destination);
297 if count > 0 {
298 self.notify();
299 return Ok(count);
300 }
301 if !self.incoming.writer_alive.load(Ordering::Acquire) {
302 let count = self.incoming.read(destination);
305 if count > 0 {
306 self.notify();
307 }
308 return Ok(count);
309 }
310 self.incoming.check_error()?;
311 if self.nonblocking {
312 return Err(io::ErrorKind::WouldBlock.into());
313 }
314 if drained {
315 self.wait(&self.incoming, deadline)?;
316 }
317 self.drain_notification()?;
318 drained = true;
320 }
321 }
322}
323
324impl Write for MemoryPipe {
325 fn write(&mut self, source: &[u8]) -> io::Result<usize> {
326 if source.is_empty() {
327 return Ok(0);
328 }
329 let deadline = self
330 .write_timeout
331 .and_then(|timeout| Instant::now().checked_add(timeout));
332 let mut drained = false;
333 loop {
334 if !self.outgoing.reader_alive.load(Ordering::Acquire) {
335 return Err(io::ErrorKind::BrokenPipe.into());
336 }
337 self.outgoing.check_error()?;
338 let count = self.outgoing.write(source);
339 if count > 0 {
340 self.notify();
341 return Ok(count);
342 }
343 if self.nonblocking {
344 return Err(io::ErrorKind::WouldBlock.into());
345 }
346 if drained {
347 self.wait(&self.outgoing, deadline)?;
348 }
349 self.drain_notification()?;
350 drained = true;
351 }
352 }
353
354 fn flush(&mut self) -> io::Result<()> {
355 Ok(())
356 }
357}
358
359impl SyncTransport for MemoryPipe {
360 fn set_nonblocking(&mut self, nonblocking: bool) -> io::Result<()> {
361 self.nonblocking = nonblocking;
362 Ok(())
363 }
364 fn set_read_timeout(&mut self, timeout: Option<Duration>) -> io::Result<()> {
365 Self::validate_timeout(timeout)?;
366 self.read_timeout = timeout;
367 Ok(())
368 }
369 fn set_write_timeout(&mut self, timeout: Option<Duration>) -> io::Result<()> {
370 Self::validate_timeout(timeout)?;
371 self.write_timeout = timeout;
372 Ok(())
373 }
374 fn read_timeout(&self) -> io::Result<Option<Duration>> {
375 Ok(self.read_timeout)
376 }
377 fn write_timeout(&self) -> io::Result<Option<Duration>> {
378 Ok(self.write_timeout)
379 }
380 fn peer_endpoint(&self) -> io::Result<String> {
381 Ok("memory://peer".into())
382 }
383}
384
385impl Drop for MemoryPipe {
386 fn drop(&mut self) {
387 self.incoming.reader_alive.store(false, Ordering::Release);
388 self.outgoing.writer_alive.store(false, Ordering::Release);
389 }
392}