yash_env/system/
shared.rs

1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2021 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! [`SharedSystem`] and related items
18
19use super::ChildProcessStarter;
20use super::Dir;
21use super::Disposition;
22use super::Errno;
23use super::FdFlag;
24use super::FlexFuture;
25use super::Gid;
26use super::LimitPair;
27use super::Mode;
28use super::OfdAccess;
29use super::OpenFlag;
30use super::Path;
31use super::PathBuf;
32use super::Resource;
33use super::Result;
34use super::SelectSystem;
35use super::SigmaskOp;
36use super::SignalStatus;
37use super::SignalSystem;
38use super::Stat;
39use super::System;
40use super::SystemEx;
41use super::Times;
42use super::Uid;
43use super::UnixString;
44use super::signal;
45#[cfg(doc)]
46use crate::Env;
47use crate::io::Fd;
48use crate::job::Pid;
49use crate::job::ProcessState;
50use crate::semantics::ExitStatus;
51use enumset::EnumSet;
52use std::cell::RefCell;
53use std::convert::Infallible;
54use std::ffi::CStr;
55use std::ffi::CString;
56use std::ffi::c_int;
57use std::future::poll_fn;
58use std::io::SeekFrom;
59use std::rc::Rc;
60use std::task::Poll;
61use std::time::Duration;
62use std::time::Instant;
63
64/// System shared by a reference counter.
65///
66/// A `SharedSystem` is a reference-counted container of a [`System`] instance
67/// accompanied with an internal state for supporting asynchronous interactions
68/// with the system. As it is reference-counted, cloning a `SharedSystem`
69/// instance only increments the reference count without cloning the backing
70/// system instance. This behavior allows calling `SharedSystem`'s methods
71/// concurrently from different `async` tasks that each have a `SharedSystem`
72/// instance sharing the same state.
73///
74/// `SharedSystem` implements [`System`] by delegating to the contained system
75/// instance. You should avoid calling some of the `System` methods, however.
76/// Prefer `async` functions provided by `SharedSystem` (e.g.,
77/// [`read_async`](Self::read_async)) over raw system functions (e.g.,
78/// [`read`](System::read)).
79///
80/// The following example illustrates how multiple concurrent tasks are run in a
81/// single-threaded pool:
82///
83/// ```
84/// # use yash_env::{SharedSystem, System, VirtualSystem};
85/// # use futures_util::task::LocalSpawnExt;
86/// let mut system = SharedSystem::new(Box::new(VirtualSystem::new()));
87/// let mut system2 = system.clone();
88/// let mut system3 = system.clone();
89/// let (reader, writer) = system.pipe().unwrap();
90/// let mut executor = futures_executor::LocalPool::new();
91///
92/// // We add a task that tries to read from the pipe, but nothing has been
93/// // written to it, so the task is stalled.
94/// let read_task = executor.spawner().spawn_local_with_handle(async move {
95///     let mut buffer = [0; 1];
96///     system.read_async(reader, &mut buffer).await.unwrap();
97///     buffer[0]
98/// });
99/// executor.run_until_stalled();
100///
101/// // Let's add a task that writes to the pipe.
102/// executor.spawner().spawn_local(async move {
103///     system2.write_all(writer, &[123]).await.unwrap();
104/// });
105/// executor.run_until_stalled();
106///
107/// // The write task has written a byte to the pipe, but the read task is still
108/// // stalled. We need to wake it up by calling `select`.
109/// system3.select(false).unwrap();
110///
111/// // Now the read task can proceed to the end.
112/// let number = executor.run_until(read_task.unwrap());
113/// assert_eq!(number, 123);
114/// ```
115///
116/// If there is a child process in the [`VirtualSystem`], you should call
117/// [`SystemState::select_all`](super::virtual::SystemState::select_all) in
118/// addition to [`SharedSystem::select`] so that the child process task is woken
119/// up when needed.
120/// (TBD code example)
121///
122/// [`VirtualSystem`]: crate::system::virtual::VirtualSystem
123#[derive(Clone, Debug)]
124pub struct SharedSystem(pub(super) Rc<RefCell<SelectSystem>>);
125
126impl SharedSystem {
127    /// Creates a new shared system.
128    pub fn new(system: Box<dyn System>) -> Self {
129        SharedSystem(Rc::new(RefCell::new(SelectSystem::new(system))))
130    }
131
132    /// Reads from the file descriptor.
133    ///
134    /// This function waits for one or more bytes to be available for reading.
135    /// If successful, returns the number of bytes read.
136    pub async fn read_async(&self, fd: Fd, buffer: &mut [u8]) -> Result<usize> {
137        let was_nonblocking = (&mut &*self).get_and_set_nonblocking(fd, true)?;
138
139        // We need to retain a strong reference to the waker outside the poll_fn
140        // function because SelectSystem only retains a weak reference to it.
141        // This allows SelectSystem to discard defunct wakers if this async task
142        // is aborted.
143        let waker = Rc::new(RefCell::new(None));
144
145        let result = poll_fn(|context| {
146            let mut inner = self.0.borrow_mut();
147            match inner.read(fd, buffer) {
148                Err(Errno::EAGAIN) => {
149                    *waker.borrow_mut() = Some(context.waker().clone());
150                    inner.add_reader(fd, Rc::downgrade(&waker));
151                    Poll::Pending
152                }
153                result => Poll::Ready(result),
154            }
155        })
156        .await;
157
158        _ = (&mut &*self).get_and_set_nonblocking(fd, was_nonblocking);
159
160        result
161    }
162
163    /// Writes to the file descriptor.
164    ///
165    /// This function calls [`System::write`] repeatedly until the whole
166    /// `buffer` is written to the FD. If the `buffer` is empty, `write` is not
167    /// called at all, so any error that would be returned from `write` is not
168    /// returned.
169    ///
170    /// This function silently ignores signals that may interrupt writes.
171    pub async fn write_all(&self, fd: Fd, mut buffer: &[u8]) -> Result<usize> {
172        if buffer.is_empty() {
173            return Ok(0);
174        }
175
176        let was_nonblocking = (&mut &*self).get_and_set_nonblocking(fd, true)?;
177        let mut written = 0;
178
179        // We need to retain a strong reference to the waker outside the poll_fn
180        // function because SelectSystem only retains a weak reference to it.
181        // This allows SelectSystem to discard defunct wakers if this async task
182        // is aborted.
183        let waker = Rc::new(RefCell::new(None));
184
185        let result = poll_fn(|context| {
186            let mut inner = self.0.borrow_mut();
187            match inner.write(fd, buffer) {
188                Ok(count) => {
189                    written += count;
190                    buffer = &buffer[count..];
191                    if buffer.is_empty() {
192                        return Poll::Ready(Ok(written));
193                    }
194                }
195                Err(Errno::EAGAIN | Errno::EINTR) => (),
196                Err(error) => return Poll::Ready(Err(error)),
197            }
198
199            *waker.borrow_mut() = Some(context.waker().clone());
200            inner.add_writer(fd, Rc::downgrade(&waker));
201            Poll::Pending
202        })
203        .await;
204
205        _ = (&mut &*self).get_and_set_nonblocking(fd, was_nonblocking);
206
207        result
208    }
209
210    /// Convenience function for printing a message to the standard error
211    pub async fn print_error(&self, message: &str) {
212        _ = self.write_all(Fd::STDERR, message.as_bytes()).await;
213    }
214
215    /// Waits until the specified time point.
216    pub async fn wait_until(&self, target: Instant) {
217        // We need to retain a strong reference to the waker outside the poll_fn
218        // function because SelectSystem only retains a weak reference to it.
219        // This allows SelectSystem to discard defunct wakers if this async task
220        // is aborted.
221        let waker = Rc::new(RefCell::new(None));
222
223        poll_fn(|context| {
224            let mut system = self.0.borrow_mut();
225            let now = system.now();
226            if now >= target {
227                return Poll::Ready(());
228            }
229            *waker.borrow_mut() = Some(context.waker().clone());
230            system.add_timeout(target, Rc::downgrade(&waker));
231            Poll::Pending
232        })
233        .await
234    }
235
236    /// Waits for some signals to be delivered to this process.
237    ///
238    /// Before calling this function, you need to [set the signal
239    /// disposition](Self::set_disposition) to `Catch`. Without doing so, this
240    /// function cannot detect the receipt of the signals.
241    ///
242    /// Returns an array of signals that were caught.
243    ///
244    /// If this `SharedSystem` is part of an [`Env`], you should call
245    /// [`Env::wait_for_signals`] rather than calling this function directly
246    /// so that the trap set can remember the caught signal.
247    pub async fn wait_for_signals(&self) -> Rc<[signal::Number]> {
248        let status = self.0.borrow_mut().add_signal_waker();
249        poll_fn(|context| {
250            let mut status = status.borrow_mut();
251            let dummy_status = SignalStatus::Expected(None);
252            let old_status = std::mem::replace(&mut *status, dummy_status);
253            match old_status {
254                SignalStatus::Caught(signals) => Poll::Ready(signals),
255                SignalStatus::Expected(_) => {
256                    *status = SignalStatus::Expected(Some(context.waker().clone()));
257                    Poll::Pending
258                }
259            }
260        })
261        .await
262    }
263
264    /// Waits for a signal to be delivered to this process.
265    ///
266    /// Before calling this function, you need to [set the signal
267    /// disposition](Self::set_disposition) to `Catch`.
268    /// Without doing so, this function cannot detect the receipt of the signal.
269    ///
270    /// If this `SharedSystem` is part of an [`Env`], you should call
271    /// [`Env::wait_for_signal`] rather than calling this function directly
272    /// so that the trap set can remember the caught signal.
273    pub async fn wait_for_signal(&self, signal: signal::Number) {
274        while !self.wait_for_signals().await.contains(&signal) {}
275    }
276
277    /// Waits for a next event to occur.
278    ///
279    /// This function calls [`System::select`] with arguments computed from the
280    /// current internal state of the `SharedSystem`. It will wake up tasks
281    /// waiting for the file descriptor to be ready in
282    /// [`read_async`](Self::read_async) and [`write_all`](Self::write_all) or
283    /// for a signal to be caught in [`wait_for_signal`](Self::wait_for_signal).
284    /// If no tasks are woken for FDs or signals and `poll` is false, this
285    /// function will block until the first task waiting for a specific time
286    /// point is woken.
287    ///
288    /// If poll is true, this function does not block, so it may not wake up any
289    /// tasks.
290    ///
291    /// This function may wake up a task even if the condition it is expecting
292    /// has not yet been met.
293    pub fn select(&self, poll: bool) -> Result<()> {
294        self.0.borrow_mut().select(poll)
295    }
296}
297
298/// Delegates `System` methods to the contained system instance.
299///
300/// This implementation only requires a non-mutable reference to the shared
301/// system because it uses `RefCell` to access the contained system instance.
302impl System for &SharedSystem {
303    fn fstat(&self, fd: Fd) -> Result<Stat> {
304        self.0.borrow().fstat(fd)
305    }
306    fn fstatat(&self, dir_fd: Fd, path: &CStr, follow_symlinks: bool) -> Result<Stat> {
307        self.0.borrow().fstatat(dir_fd, path, follow_symlinks)
308    }
309    fn is_executable_file(&self, path: &CStr) -> bool {
310        self.0.borrow().is_executable_file(path)
311    }
312    fn is_directory(&self, path: &CStr) -> bool {
313        self.0.borrow().is_directory(path)
314    }
315    fn pipe(&mut self) -> Result<(Fd, Fd)> {
316        self.0.borrow_mut().pipe()
317    }
318    fn dup(&mut self, from: Fd, to_min: Fd, flags: EnumSet<FdFlag>) -> Result<Fd> {
319        self.0.borrow_mut().dup(from, to_min, flags)
320    }
321    fn dup2(&mut self, from: Fd, to: Fd) -> Result<Fd> {
322        self.0.borrow_mut().dup2(from, to)
323    }
324    fn open(
325        &mut self,
326        path: &CStr,
327        access: OfdAccess,
328        flags: EnumSet<OpenFlag>,
329        mode: Mode,
330    ) -> Result<Fd> {
331        self.0.borrow_mut().open(path, access, flags, mode)
332    }
333    fn open_tmpfile(&mut self, parent_dir: &Path) -> Result<Fd> {
334        self.0.borrow_mut().open_tmpfile(parent_dir)
335    }
336    fn close(&mut self, fd: Fd) -> Result<()> {
337        self.0.borrow_mut().close(fd)
338    }
339    fn ofd_access(&self, fd: Fd) -> Result<OfdAccess> {
340        self.0.borrow().ofd_access(fd)
341    }
342    fn get_and_set_nonblocking(&mut self, fd: Fd, nonblocking: bool) -> Result<bool> {
343        self.0.borrow_mut().get_and_set_nonblocking(fd, nonblocking)
344    }
345    fn fcntl_getfd(&self, fd: Fd) -> Result<EnumSet<FdFlag>> {
346        self.0.borrow().fcntl_getfd(fd)
347    }
348    fn fcntl_setfd(&mut self, fd: Fd, flags: EnumSet<FdFlag>) -> Result<()> {
349        self.0.borrow_mut().fcntl_setfd(fd, flags)
350    }
351    fn isatty(&self, fd: Fd) -> bool {
352        self.0.borrow().isatty(fd)
353    }
354    fn read(&mut self, fd: Fd, buffer: &mut [u8]) -> Result<usize> {
355        self.0.borrow_mut().read(fd, buffer)
356    }
357    fn write(&mut self, fd: Fd, buffer: &[u8]) -> Result<usize> {
358        self.0.borrow_mut().write(fd, buffer)
359    }
360    fn lseek(&mut self, fd: Fd, position: SeekFrom) -> Result<u64> {
361        self.0.borrow_mut().lseek(fd, position)
362    }
363    fn fdopendir(&mut self, fd: Fd) -> Result<Box<dyn Dir>> {
364        self.0.borrow_mut().fdopendir(fd)
365    }
366    fn opendir(&mut self, path: &CStr) -> Result<Box<dyn Dir>> {
367        self.0.borrow_mut().opendir(path)
368    }
369    fn umask(&mut self, mask: Mode) -> Mode {
370        self.0.borrow_mut().umask(mask)
371    }
372    fn now(&self) -> Instant {
373        self.0.borrow().now()
374    }
375    fn times(&self) -> Result<Times> {
376        self.0.borrow().times()
377    }
378    fn validate_signal(&self, number: signal::RawNumber) -> Option<(signal::Name, signal::Number)> {
379        self.0.borrow().validate_signal(number)
380    }
381    fn signal_number_from_name(&self, name: signal::Name) -> Option<signal::Number> {
382        self.0.borrow().signal_number_from_name(name)
383    }
384    fn sigmask(
385        &mut self,
386        op: Option<(SigmaskOp, &[signal::Number])>,
387        old_mask: Option<&mut Vec<signal::Number>>,
388    ) -> Result<()> {
389        (**self.0.borrow_mut()).sigmask(op, old_mask)
390    }
391    fn get_sigaction(&self, signal: signal::Number) -> Result<Disposition> {
392        self.0.borrow().get_sigaction(signal)
393    }
394    fn sigaction(&mut self, signal: signal::Number, action: Disposition) -> Result<Disposition> {
395        self.0.borrow_mut().sigaction(signal, action)
396    }
397    fn caught_signals(&mut self) -> Vec<signal::Number> {
398        self.0.borrow_mut().caught_signals()
399    }
400    fn kill(&mut self, target: Pid, signal: Option<signal::Number>) -> FlexFuture<Result<()>> {
401        self.0.borrow_mut().kill(target, signal)
402    }
403    fn raise(&mut self, signal: signal::Number) -> FlexFuture<Result<()>> {
404        self.0.borrow_mut().raise(signal)
405    }
406    fn select(
407        &mut self,
408        readers: &mut Vec<Fd>,
409        writers: &mut Vec<Fd>,
410        timeout: Option<Duration>,
411        signal_mask: Option<&[signal::Number]>,
412    ) -> Result<c_int> {
413        (**self.0.borrow_mut()).select(readers, writers, timeout, signal_mask)
414    }
415    fn getsid(&self, pid: Pid) -> Result<Pid> {
416        self.0.borrow().getsid(pid)
417    }
418    fn getpid(&self) -> Pid {
419        self.0.borrow().getpid()
420    }
421    fn getppid(&self) -> Pid {
422        self.0.borrow().getppid()
423    }
424    fn getpgrp(&self) -> Pid {
425        self.0.borrow().getpgrp()
426    }
427    fn setpgid(&mut self, pid: Pid, pgid: Pid) -> Result<()> {
428        self.0.borrow_mut().setpgid(pid, pgid)
429    }
430    fn tcgetpgrp(&self, fd: Fd) -> Result<Pid> {
431        self.0.borrow().tcgetpgrp(fd)
432    }
433    fn tcsetpgrp(&mut self, fd: Fd, pgid: Pid) -> Result<()> {
434        self.0.borrow_mut().tcsetpgrp(fd, pgid)
435    }
436    fn new_child_process(&mut self) -> Result<ChildProcessStarter> {
437        self.0.borrow_mut().new_child_process()
438    }
439    fn wait(&mut self, target: Pid) -> Result<Option<(Pid, ProcessState)>> {
440        self.0.borrow_mut().wait(target)
441    }
442    fn execve(
443        &mut self,
444        path: &CStr,
445        args: &[CString],
446        envs: &[CString],
447    ) -> FlexFuture<Result<Infallible>> {
448        self.0.borrow_mut().execve(path, args, envs)
449    }
450    fn exit(&mut self, exit_status: ExitStatus) -> FlexFuture<Infallible> {
451        self.0.borrow_mut().exit(exit_status)
452    }
453    fn getcwd(&self) -> Result<PathBuf> {
454        self.0.borrow().getcwd()
455    }
456    fn chdir(&mut self, path: &CStr) -> Result<()> {
457        self.0.borrow_mut().chdir(path)
458    }
459    fn getuid(&self) -> Uid {
460        self.0.borrow().getuid()
461    }
462    fn geteuid(&self) -> Uid {
463        self.0.borrow().geteuid()
464    }
465    fn getgid(&self) -> Gid {
466        self.0.borrow().getgid()
467    }
468    fn getegid(&self) -> Gid {
469        self.0.borrow().getegid()
470    }
471    fn getpwnam_dir(&self, name: &CStr) -> Result<Option<PathBuf>> {
472        self.0.borrow().getpwnam_dir(name)
473    }
474    fn confstr_path(&self) -> Result<UnixString> {
475        self.0.borrow().confstr_path()
476    }
477    fn shell_path(&self) -> CString {
478        self.0.borrow().shell_path()
479    }
480    fn getrlimit(&self, resource: Resource) -> Result<LimitPair> {
481        self.0.borrow().getrlimit(resource)
482    }
483    fn setrlimit(&mut self, resource: Resource, limits: LimitPair) -> Result<()> {
484        self.0.borrow_mut().setrlimit(resource, limits)
485    }
486}
487
488/// Delegates `System` methods to the contained system instance.
489impl System for SharedSystem {
490    // All methods are delegated to `impl System for &SharedSystem`,
491    // which in turn delegates to the contained system instance.
492    #[inline]
493    fn fstat(&self, fd: Fd) -> Result<Stat> {
494        (&self).fstat(fd)
495    }
496    #[inline]
497    fn fstatat(&self, dir_fd: Fd, path: &CStr, follow_symlinks: bool) -> Result<Stat> {
498        (&self).fstatat(dir_fd, path, follow_symlinks)
499    }
500    #[inline]
501    fn is_executable_file(&self, path: &CStr) -> bool {
502        (&self).is_executable_file(path)
503    }
504    #[inline]
505    fn is_directory(&self, path: &CStr) -> bool {
506        (&self).is_directory(path)
507    }
508    #[inline]
509    fn pipe(&mut self) -> Result<(Fd, Fd)> {
510        (&mut &*self).pipe()
511    }
512    #[inline]
513    fn dup(&mut self, from: Fd, to_min: Fd, flags: EnumSet<FdFlag>) -> Result<Fd> {
514        (&mut &*self).dup(from, to_min, flags)
515    }
516    #[inline]
517    fn dup2(&mut self, from: Fd, to: Fd) -> Result<Fd> {
518        (&mut &*self).dup2(from, to)
519    }
520    #[inline]
521    fn open(
522        &mut self,
523        path: &CStr,
524        access: OfdAccess,
525        flags: EnumSet<OpenFlag>,
526        mode: Mode,
527    ) -> Result<Fd> {
528        (&mut &*self).open(path, access, flags, mode)
529    }
530    #[inline]
531    fn open_tmpfile(&mut self, parent_dir: &Path) -> Result<Fd> {
532        (&mut &*self).open_tmpfile(parent_dir)
533    }
534    #[inline]
535    fn close(&mut self, fd: Fd) -> Result<()> {
536        (&mut &*self).close(fd)
537    }
538    #[inline]
539    fn ofd_access(&self, fd: Fd) -> Result<OfdAccess> {
540        (&self).ofd_access(fd)
541    }
542    #[inline]
543    fn get_and_set_nonblocking(&mut self, fd: Fd, nonblocking: bool) -> Result<bool> {
544        (&mut &*self).get_and_set_nonblocking(fd, nonblocking)
545    }
546    #[inline]
547    fn fcntl_getfd(&self, fd: Fd) -> Result<EnumSet<FdFlag>> {
548        (&self).fcntl_getfd(fd)
549    }
550    #[inline]
551    fn fcntl_setfd(&mut self, fd: Fd, flags: EnumSet<FdFlag>) -> Result<()> {
552        (&mut &*self).fcntl_setfd(fd, flags)
553    }
554    #[inline]
555    fn isatty(&self, fd: Fd) -> bool {
556        (&self).isatty(fd)
557    }
558    #[inline]
559    fn read(&mut self, fd: Fd, buffer: &mut [u8]) -> Result<usize> {
560        (&mut &*self).read(fd, buffer)
561    }
562    #[inline]
563    fn write(&mut self, fd: Fd, buffer: &[u8]) -> Result<usize> {
564        (&mut &*self).write(fd, buffer)
565    }
566    #[inline]
567    fn lseek(&mut self, fd: Fd, position: SeekFrom) -> Result<u64> {
568        (&mut &*self).lseek(fd, position)
569    }
570    #[inline]
571    fn fdopendir(&mut self, fd: Fd) -> Result<Box<dyn Dir>> {
572        (&mut &*self).fdopendir(fd)
573    }
574    #[inline]
575    fn opendir(&mut self, path: &CStr) -> Result<Box<dyn Dir>> {
576        (&mut &*self).opendir(path)
577    }
578    #[inline]
579    fn umask(&mut self, mask: Mode) -> Mode {
580        (&mut &*self).umask(mask)
581    }
582    #[inline]
583    fn now(&self) -> Instant {
584        (&self).now()
585    }
586    #[inline]
587    fn times(&self) -> Result<Times> {
588        (&self).times()
589    }
590    #[inline]
591    fn validate_signal(&self, number: signal::RawNumber) -> Option<(signal::Name, signal::Number)> {
592        (&self).validate_signal(number)
593    }
594    #[inline]
595    fn signal_number_from_name(&self, name: signal::Name) -> Option<signal::Number> {
596        System::signal_number_from_name(&self, name)
597    }
598    #[inline]
599    fn sigmask(
600        &mut self,
601        op: Option<(SigmaskOp, &[signal::Number])>,
602        old_mask: Option<&mut Vec<signal::Number>>,
603    ) -> Result<()> {
604        (&mut &*self).sigmask(op, old_mask)
605    }
606    #[inline]
607    fn get_sigaction(&self, signal: signal::Number) -> Result<Disposition> {
608        (&self).get_sigaction(signal)
609    }
610    #[inline]
611    fn sigaction(&mut self, signal: signal::Number, action: Disposition) -> Result<Disposition> {
612        (&mut &*self).sigaction(signal, action)
613    }
614    #[inline]
615    fn caught_signals(&mut self) -> Vec<signal::Number> {
616        (&mut &*self).caught_signals()
617    }
618    #[inline]
619    fn kill(&mut self, target: Pid, signal: Option<signal::Number>) -> FlexFuture<Result<()>> {
620        (&mut &*self).kill(target, signal)
621    }
622    #[inline]
623    fn raise(&mut self, signal: signal::Number) -> FlexFuture<Result<()>> {
624        (&mut &*self).raise(signal)
625    }
626    #[inline]
627    fn select(
628        &mut self,
629        readers: &mut Vec<Fd>,
630        writers: &mut Vec<Fd>,
631        timeout: Option<Duration>,
632        signal_mask: Option<&[signal::Number]>,
633    ) -> Result<c_int> {
634        (&mut &*self).select(readers, writers, timeout, signal_mask)
635    }
636    #[inline]
637    fn getsid(&self, pid: Pid) -> Result<Pid> {
638        (&self).getsid(pid)
639    }
640    #[inline]
641    fn getpid(&self) -> Pid {
642        (&self).getpid()
643    }
644    #[inline]
645    fn getppid(&self) -> Pid {
646        (&self).getppid()
647    }
648    #[inline]
649    fn getpgrp(&self) -> Pid {
650        (&self).getpgrp()
651    }
652    #[inline]
653    fn setpgid(&mut self, pid: Pid, pgid: Pid) -> Result<()> {
654        (&mut &*self).setpgid(pid, pgid)
655    }
656    #[inline]
657    fn tcgetpgrp(&self, fd: Fd) -> Result<Pid> {
658        (&self).tcgetpgrp(fd)
659    }
660    #[inline]
661    fn tcsetpgrp(&mut self, fd: Fd, pgid: Pid) -> Result<()> {
662        (&mut &*self).tcsetpgrp(fd, pgid)
663    }
664    #[inline]
665    fn new_child_process(&mut self) -> Result<ChildProcessStarter> {
666        (&mut &*self).new_child_process()
667    }
668    #[inline]
669    fn wait(&mut self, target: Pid) -> Result<Option<(Pid, ProcessState)>> {
670        (&mut &*self).wait(target)
671    }
672    #[inline]
673    fn execve(
674        &mut self,
675        path: &CStr,
676        args: &[CString],
677        envs: &[CString],
678    ) -> FlexFuture<Result<Infallible>> {
679        (&mut &*self).execve(path, args, envs)
680    }
681    #[inline]
682    fn exit(&mut self, exit_status: ExitStatus) -> FlexFuture<Infallible> {
683        (&mut &*self).exit(exit_status)
684    }
685    #[inline]
686    fn getcwd(&self) -> Result<PathBuf> {
687        (&self).getcwd()
688    }
689    #[inline]
690    fn chdir(&mut self, path: &CStr) -> Result<()> {
691        (&mut &*self).chdir(path)
692    }
693    #[inline]
694    fn getuid(&self) -> Uid {
695        (&self).getuid()
696    }
697    #[inline]
698    fn geteuid(&self) -> Uid {
699        (&self).geteuid()
700    }
701    #[inline]
702    fn getgid(&self) -> Gid {
703        (&self).getgid()
704    }
705    #[inline]
706    fn getegid(&self) -> Gid {
707        (&self).getegid()
708    }
709    #[inline]
710    fn getpwnam_dir(&self, name: &CStr) -> Result<Option<PathBuf>> {
711        (&self).getpwnam_dir(name)
712    }
713    #[inline]
714    fn confstr_path(&self) -> Result<UnixString> {
715        (&self).confstr_path()
716    }
717    #[inline]
718    fn shell_path(&self) -> CString {
719        (&self).shell_path()
720    }
721    #[inline]
722    fn getrlimit(&self, resource: Resource) -> Result<LimitPair> {
723        (&self).getrlimit(resource)
724    }
725    #[inline]
726    fn setrlimit(&mut self, resource: Resource, limits: LimitPair) -> Result<()> {
727        (&mut &*self).setrlimit(resource, limits)
728    }
729}
730
731impl SignalSystem for &SharedSystem {
732    #[inline]
733    fn signal_name_from_number(&self, number: signal::Number) -> signal::Name {
734        SystemEx::signal_name_from_number(*self, number)
735    }
736
737    #[inline]
738    fn signal_number_from_name(&self, name: signal::Name) -> Option<signal::Number> {
739        System::signal_number_from_name(*self, name)
740    }
741
742    fn get_disposition(&self, signal: signal::Number) -> Result<Disposition> {
743        self.0.borrow().get_disposition(signal)
744    }
745
746    fn set_disposition(
747        &mut self,
748        signal: signal::Number,
749        disposition: Disposition,
750    ) -> Result<Disposition> {
751        self.0.borrow_mut().set_disposition(signal, disposition)
752    }
753}
754
755impl SignalSystem for SharedSystem {
756    #[inline]
757    fn signal_name_from_number(&self, number: signal::Number) -> signal::Name {
758        SystemEx::signal_name_from_number(self, number)
759    }
760
761    #[inline]
762    fn signal_number_from_name(&self, name: signal::Name) -> Option<signal::Number> {
763        System::signal_number_from_name(self, name)
764    }
765
766    #[inline]
767    fn get_disposition(&self, signal: signal::Number) -> Result<Disposition> {
768        self.0.borrow().get_disposition(signal)
769    }
770
771    #[inline]
772    fn set_disposition(
773        &mut self,
774        signal: signal::Number,
775        disposition: Disposition,
776    ) -> Result<Disposition> {
777        self.0.borrow_mut().set_disposition(signal, disposition)
778    }
779}
780
781#[cfg(test)]
782mod tests {
783    use super::super::r#virtual::PIPE_SIZE;
784    use super::super::r#virtual::VirtualSystem;
785    use super::super::r#virtual::{SIGCHLD, SIGINT, SIGTERM, SIGUSR1};
786    use super::*;
787    use assert_matches::assert_matches;
788    use futures_util::FutureExt as _;
789    use std::task::Context;
790    use std::task::Poll;
791    use std::task::Waker;
792    use std::time::Duration;
793
794    #[test]
795    fn shared_system_read_async_ready() {
796        let mut system = SharedSystem::new(Box::new(VirtualSystem::new()));
797        let (reader, writer) = system.pipe().unwrap();
798        system.write(writer, &[42]).unwrap();
799
800        let mut buffer = [0; 2];
801        let result = system.read_async(reader, &mut buffer).now_or_never();
802        assert_eq!(result, Some(Ok(1)));
803        assert_eq!(buffer[..1], [42]);
804    }
805
806    #[test]
807    fn shared_system_read_async_not_ready_at_first() {
808        let system = VirtualSystem::new();
809        let process_id = system.process_id;
810        let state = Rc::clone(&system.state);
811        let mut system = SharedSystem::new(Box::new(system));
812        let system2 = system.clone();
813        let (reader, writer) = system.pipe().unwrap();
814
815        let mut context = Context::from_waker(Waker::noop());
816        let mut buffer = [0; 2];
817        let mut future = Box::pin(system.read_async(reader, &mut buffer));
818        let result = future.as_mut().poll(&mut context);
819        assert_eq!(result, Poll::Pending);
820
821        let result = system2.select(false);
822        assert_eq!(result, Ok(()));
823        let result = future.as_mut().poll(&mut context);
824        assert_eq!(result, Poll::Pending);
825
826        state.borrow_mut().processes[&process_id].fds[&writer]
827            .open_file_description
828            .borrow_mut()
829            .write(&[56])
830            .unwrap();
831
832        let result = future.as_mut().poll(&mut context);
833        drop(future);
834        assert_eq!(result, Poll::Ready(Ok(1)));
835        assert_eq!(buffer[..1], [56]);
836    }
837
838    #[test]
839    fn shared_system_write_all_ready() {
840        let mut system = SharedSystem::new(Box::new(VirtualSystem::new()));
841        let (reader, writer) = system.pipe().unwrap();
842        let result = system.write_all(writer, &[17]).now_or_never().unwrap();
843        assert_eq!(result, Ok(1));
844
845        let mut buffer = [0; 2];
846        system.read(reader, &mut buffer).unwrap();
847        assert_eq!(buffer[..1], [17]);
848    }
849
850    #[test]
851    fn shared_system_write_all_not_ready_at_first() {
852        let system = VirtualSystem::new();
853        let process_id = system.process_id;
854        let state = Rc::clone(&system.state);
855        let mut system = SharedSystem::new(Box::new(system));
856        let (reader, writer) = system.pipe().unwrap();
857
858        state.borrow_mut().processes[&process_id].fds[&writer]
859            .open_file_description
860            .borrow_mut()
861            .write(&[42; PIPE_SIZE])
862            .unwrap();
863
864        let mut context = Context::from_waker(Waker::noop());
865        let mut out_buffer = [87; PIPE_SIZE];
866        out_buffer[0] = 0;
867        out_buffer[1] = 1;
868        out_buffer[PIPE_SIZE - 2] = 0xFE;
869        out_buffer[PIPE_SIZE - 1] = 0xFF;
870        let mut future = Box::pin(system.write_all(writer, &out_buffer));
871        let result = future.as_mut().poll(&mut context);
872        assert_eq!(result, Poll::Pending);
873
874        let mut in_buffer = [0; PIPE_SIZE - 1];
875        state.borrow_mut().processes[&process_id].fds[&reader]
876            .open_file_description
877            .borrow_mut()
878            .read(&mut in_buffer)
879            .unwrap();
880        assert_eq!(in_buffer, [42; PIPE_SIZE - 1]);
881
882        let result = future.as_mut().poll(&mut context);
883        assert_eq!(result, Poll::Pending);
884
885        in_buffer[0] = 0;
886        state.borrow_mut().processes[&process_id].fds[&reader]
887            .open_file_description
888            .borrow_mut()
889            .read(&mut in_buffer[..1])
890            .unwrap();
891        assert_eq!(in_buffer[..1], [42; 1]);
892
893        let result = future.as_mut().poll(&mut context);
894        assert_eq!(result, Poll::Ready(Ok(out_buffer.len())));
895
896        state.borrow_mut().processes[&process_id].fds[&reader]
897            .open_file_description
898            .borrow_mut()
899            .read(&mut in_buffer)
900            .unwrap();
901        assert_eq!(in_buffer, out_buffer[..PIPE_SIZE - 1]);
902        state.borrow_mut().processes[&process_id].fds[&reader]
903            .open_file_description
904            .borrow_mut()
905            .read(&mut in_buffer)
906            .unwrap();
907        assert_eq!(in_buffer[..1], out_buffer[PIPE_SIZE - 1..]);
908    }
909
910    #[test]
911    fn shared_system_write_all_empty() {
912        let system = VirtualSystem::new();
913        let process_id = system.process_id;
914        let state = Rc::clone(&system.state);
915        let mut system = SharedSystem::new(Box::new(system));
916        let (_reader, writer) = system.pipe().unwrap();
917
918        state.borrow_mut().processes[&process_id].fds[&writer]
919            .open_file_description
920            .borrow_mut()
921            .write(&[0; PIPE_SIZE])
922            .unwrap();
923
924        // Even if the pipe is full, empty write succeeds.
925        let mut context = Context::from_waker(Waker::noop());
926        let mut future = Box::pin(system.write_all(writer, &[]));
927        let result = future.as_mut().poll(&mut context);
928        assert_eq!(result, Poll::Ready(Ok(0)));
929        // TODO Make sure `write` is not called at all
930    }
931
932    // TODO Test SharedSystem::write_all where second write returns EINTR
933
934    #[test]
935    fn shared_system_wait_until() {
936        let system = VirtualSystem::new();
937        let state = Rc::clone(&system.state);
938        let system = SharedSystem::new(Box::new(system));
939        let start = Instant::now();
940        state.borrow_mut().now = Some(start);
941        let target = start + Duration::from_millis(1_125);
942
943        let mut future = Box::pin(system.wait_until(target));
944        let mut context = Context::from_waker(Waker::noop());
945        let poll = future.as_mut().poll(&mut context);
946        assert_eq!(poll, Poll::Pending);
947
948        system.select(false).unwrap();
949        let poll = future.as_mut().poll(&mut context);
950        assert_eq!(poll, Poll::Ready(()));
951        assert_eq!(state.borrow().now, Some(target));
952    }
953
954    #[test]
955    fn shared_system_wait_for_signals() {
956        let system = VirtualSystem::new();
957        let process_id = system.process_id;
958        let state = Rc::clone(&system.state);
959        let mut system = SharedSystem::new(Box::new(system));
960        system.set_disposition(SIGCHLD, Disposition::Catch).unwrap();
961        system.set_disposition(SIGINT, Disposition::Catch).unwrap();
962        system.set_disposition(SIGUSR1, Disposition::Catch).unwrap();
963
964        let mut context = Context::from_waker(Waker::noop());
965        let mut future = Box::pin(system.wait_for_signals());
966        let result = future.as_mut().poll(&mut context);
967        assert_eq!(result, Poll::Pending);
968
969        {
970            let mut state = state.borrow_mut();
971            let process = state.processes.get_mut(&process_id).unwrap();
972            assert!(process.blocked_signals().contains(&SIGCHLD));
973            assert!(process.blocked_signals().contains(&SIGINT));
974            assert!(process.blocked_signals().contains(&SIGUSR1));
975            let _ = process.raise_signal(SIGCHLD);
976            let _ = process.raise_signal(SIGINT);
977        }
978        let result = future.as_mut().poll(&mut context);
979        assert_eq!(result, Poll::Pending);
980
981        system.select(false).unwrap();
982        let result = future.as_mut().poll(&mut context);
983        assert_matches!(result, Poll::Ready(signals) => {
984            assert_eq!(signals.len(), 2);
985            assert!(signals.contains(&SIGCHLD));
986            assert!(signals.contains(&SIGINT));
987        });
988    }
989
990    #[test]
991    fn shared_system_wait_for_signal_returns_on_caught() {
992        let system = VirtualSystem::new();
993        let process_id = system.process_id;
994        let state = Rc::clone(&system.state);
995        let mut system = SharedSystem::new(Box::new(system));
996        system.set_disposition(SIGCHLD, Disposition::Catch).unwrap();
997
998        let mut context = Context::from_waker(Waker::noop());
999        let mut future = Box::pin(system.wait_for_signal(SIGCHLD));
1000        let result = future.as_mut().poll(&mut context);
1001        assert_eq!(result, Poll::Pending);
1002
1003        {
1004            let mut state = state.borrow_mut();
1005            let process = state.processes.get_mut(&process_id).unwrap();
1006            assert!(process.blocked_signals().contains(&SIGCHLD));
1007            let _ = process.raise_signal(SIGCHLD);
1008        }
1009        let result = future.as_mut().poll(&mut context);
1010        assert_eq!(result, Poll::Pending);
1011
1012        system.select(false).unwrap();
1013        let result = future.as_mut().poll(&mut context);
1014        assert_eq!(result, Poll::Ready(()));
1015    }
1016
1017    #[test]
1018    fn shared_system_wait_for_signal_ignores_irrelevant_signals() {
1019        let system = VirtualSystem::new();
1020        let process_id = system.process_id;
1021        let state = Rc::clone(&system.state);
1022        let mut system = SharedSystem::new(Box::new(system));
1023        system.set_disposition(SIGINT, Disposition::Catch).unwrap();
1024        system.set_disposition(SIGTERM, Disposition::Catch).unwrap();
1025
1026        let mut context = Context::from_waker(Waker::noop());
1027        let mut future = Box::pin(system.wait_for_signal(SIGINT));
1028        let result = future.as_mut().poll(&mut context);
1029        assert_eq!(result, Poll::Pending);
1030
1031        {
1032            let mut state = state.borrow_mut();
1033            let process = state.processes.get_mut(&process_id).unwrap();
1034            let _ = process.raise_signal(SIGCHLD);
1035            let _ = process.raise_signal(SIGTERM);
1036        }
1037        system.select(false).unwrap();
1038
1039        let result = future.as_mut().poll(&mut context);
1040        assert_eq!(result, Poll::Pending);
1041    }
1042
1043    #[test]
1044    fn shared_system_select_consumes_all_pending_signals() {
1045        let system = VirtualSystem::new();
1046        let process_id = system.process_id;
1047        let state = Rc::clone(&system.state);
1048        let mut system = SharedSystem::new(Box::new(system));
1049        system.set_disposition(SIGINT, Disposition::Catch).unwrap();
1050        system.set_disposition(SIGTERM, Disposition::Catch).unwrap();
1051
1052        {
1053            let mut state = state.borrow_mut();
1054            let process = state.processes.get_mut(&process_id).unwrap();
1055            let _ = process.raise_signal(SIGINT);
1056            let _ = process.raise_signal(SIGTERM);
1057        }
1058        system.select(false).unwrap();
1059
1060        let state = state.borrow();
1061        let process = state.processes.get(&process_id).unwrap();
1062        let blocked = process.blocked_signals();
1063        assert!(blocked.contains(&SIGINT));
1064        assert!(blocked.contains(&SIGTERM));
1065        let pending = process.pending_signals();
1066        assert!(!pending.contains(&SIGINT));
1067        assert!(!pending.contains(&SIGTERM));
1068    }
1069
1070    #[test]
1071    fn shared_system_select_does_not_wake_signal_waiters_on_io() {
1072        let system = VirtualSystem::new();
1073        let mut system_1 = SharedSystem::new(Box::new(system));
1074        let mut system_2 = system_1.clone();
1075        let mut system_3 = system_1.clone();
1076        let (reader, writer) = system_1.pipe().unwrap();
1077        system_2
1078            .set_disposition(SIGCHLD, Disposition::Catch)
1079            .unwrap();
1080
1081        let mut buffer = [0];
1082        let mut read_future = Box::pin(system_1.read_async(reader, &mut buffer));
1083        let mut signal_future = Box::pin(system_2.wait_for_signals());
1084        let mut context = Context::from_waker(Waker::noop());
1085        let result = read_future.as_mut().poll(&mut context);
1086        assert_eq!(result, Poll::Pending);
1087        let result = signal_future.as_mut().poll(&mut context);
1088        assert_eq!(result, Poll::Pending);
1089        system_3.write(writer, &[42]).unwrap();
1090        system_3.select(false).unwrap();
1091
1092        let result = read_future.as_mut().poll(&mut context);
1093        assert_eq!(result, Poll::Ready(Ok(1)));
1094        let result = signal_future.as_mut().poll(&mut context);
1095        assert_eq!(result, Poll::Pending);
1096    }
1097
1098    #[test]
1099    fn shared_system_select_poll() {
1100        let system = VirtualSystem::new();
1101        let state = Rc::clone(&system.state);
1102        let system = SharedSystem::new(Box::new(system));
1103        let start = Instant::now();
1104        state.borrow_mut().now = Some(start);
1105        let target = start + Duration::from_millis(1_125);
1106
1107        let mut future = Box::pin(system.wait_until(target));
1108        let mut context = Context::from_waker(Waker::noop());
1109        let poll = future.as_mut().poll(&mut context);
1110        assert_eq!(poll, Poll::Pending);
1111
1112        system.select(true).unwrap();
1113        let poll = future.as_mut().poll(&mut context);
1114        assert_eq!(poll, Poll::Pending);
1115        assert_eq!(state.borrow().now, Some(start));
1116    }
1117}