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::signal;
20use super::ChildProcessStarter;
21use super::Dir;
22use super::Disposition;
23use super::Errno;
24use super::FdFlag;
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 crate::io::Fd;
45use crate::job::Pid;
46use crate::job::ProcessState;
47#[cfg(doc)]
48use crate::Env;
49use enumset::EnumSet;
50use std::cell::RefCell;
51use std::convert::Infallible;
52use std::ffi::c_int;
53use std::ffi::CStr;
54use std::ffi::CString;
55use std::future::poll_fn;
56use std::future::Future;
57use std::io::SeekFrom;
58use std::pin::Pin;
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 sigaction(&mut self, signal: signal::Number, action: Disposition) -> Result<Disposition> {
392        self.0.borrow_mut().sigaction(signal, action)
393    }
394    fn caught_signals(&mut self) -> Vec<signal::Number> {
395        self.0.borrow_mut().caught_signals()
396    }
397    fn kill(
398        &mut self,
399        target: Pid,
400        signal: Option<signal::Number>,
401    ) -> Pin<Box<(dyn Future<Output = Result<()>>)>> {
402        self.0.borrow_mut().kill(target, signal)
403    }
404    fn select(
405        &mut self,
406        readers: &mut Vec<Fd>,
407        writers: &mut Vec<Fd>,
408        timeout: Option<Duration>,
409        signal_mask: Option<&[signal::Number]>,
410    ) -> Result<c_int> {
411        (**self.0.borrow_mut()).select(readers, writers, timeout, signal_mask)
412    }
413    fn getpid(&self) -> Pid {
414        self.0.borrow().getpid()
415    }
416    fn getppid(&self) -> Pid {
417        self.0.borrow().getppid()
418    }
419    fn getpgrp(&self) -> Pid {
420        self.0.borrow().getpgrp()
421    }
422    fn setpgid(&mut self, pid: Pid, pgid: Pid) -> Result<()> {
423        self.0.borrow_mut().setpgid(pid, pgid)
424    }
425    fn tcgetpgrp(&self, fd: Fd) -> Result<Pid> {
426        self.0.borrow().tcgetpgrp(fd)
427    }
428    fn tcsetpgrp(&mut self, fd: Fd, pgid: Pid) -> Result<()> {
429        self.0.borrow_mut().tcsetpgrp(fd, pgid)
430    }
431    fn new_child_process(&mut self) -> Result<ChildProcessStarter> {
432        self.0.borrow_mut().new_child_process()
433    }
434    fn wait(&mut self, target: Pid) -> Result<Option<(Pid, ProcessState)>> {
435        self.0.borrow_mut().wait(target)
436    }
437    fn execve(&mut self, path: &CStr, args: &[CString], envs: &[CString]) -> Result<Infallible> {
438        self.0.borrow_mut().execve(path, args, envs)
439    }
440    fn getcwd(&self) -> Result<PathBuf> {
441        self.0.borrow().getcwd()
442    }
443    fn chdir(&mut self, path: &CStr) -> Result<()> {
444        self.0.borrow_mut().chdir(path)
445    }
446    fn getuid(&self) -> Uid {
447        self.0.borrow().getuid()
448    }
449    fn geteuid(&self) -> Uid {
450        self.0.borrow().geteuid()
451    }
452    fn getgid(&self) -> Gid {
453        self.0.borrow().getgid()
454    }
455    fn getegid(&self) -> Gid {
456        self.0.borrow().getegid()
457    }
458    fn getpwnam_dir(&self, name: &str) -> Result<Option<PathBuf>> {
459        self.0.borrow().getpwnam_dir(name)
460    }
461    fn confstr_path(&self) -> Result<UnixString> {
462        self.0.borrow().confstr_path()
463    }
464    fn shell_path(&self) -> CString {
465        self.0.borrow().shell_path()
466    }
467    fn getrlimit(&self, resource: Resource) -> Result<LimitPair> {
468        self.0.borrow().getrlimit(resource)
469    }
470    fn setrlimit(&mut self, resource: Resource, limits: LimitPair) -> Result<()> {
471        self.0.borrow_mut().setrlimit(resource, limits)
472    }
473}
474
475/// Delegates `System` methods to the contained system instance.
476impl System for SharedSystem {
477    // All methods are delegated to `impl System for &SharedSystem`,
478    // which in turn delegates to the contained system instance.
479    #[inline]
480    fn fstat(&self, fd: Fd) -> Result<Stat> {
481        (&self).fstat(fd)
482    }
483    #[inline]
484    fn fstatat(&self, dir_fd: Fd, path: &CStr, follow_symlinks: bool) -> Result<Stat> {
485        (&self).fstatat(dir_fd, path, follow_symlinks)
486    }
487    #[inline]
488    fn is_executable_file(&self, path: &CStr) -> bool {
489        (&self).is_executable_file(path)
490    }
491    #[inline]
492    fn is_directory(&self, path: &CStr) -> bool {
493        (&self).is_directory(path)
494    }
495    #[inline]
496    fn pipe(&mut self) -> Result<(Fd, Fd)> {
497        (&mut &*self).pipe()
498    }
499    #[inline]
500    fn dup(&mut self, from: Fd, to_min: Fd, flags: EnumSet<FdFlag>) -> Result<Fd> {
501        (&mut &*self).dup(from, to_min, flags)
502    }
503    #[inline]
504    fn dup2(&mut self, from: Fd, to: Fd) -> Result<Fd> {
505        (&mut &*self).dup2(from, to)
506    }
507    #[inline]
508    fn open(
509        &mut self,
510        path: &CStr,
511        access: OfdAccess,
512        flags: EnumSet<OpenFlag>,
513        mode: Mode,
514    ) -> Result<Fd> {
515        (&mut &*self).open(path, access, flags, mode)
516    }
517    #[inline]
518    fn open_tmpfile(&mut self, parent_dir: &Path) -> Result<Fd> {
519        (&mut &*self).open_tmpfile(parent_dir)
520    }
521    #[inline]
522    fn close(&mut self, fd: Fd) -> Result<()> {
523        (&mut &*self).close(fd)
524    }
525    #[inline]
526    fn ofd_access(&self, fd: Fd) -> Result<OfdAccess> {
527        (&self).ofd_access(fd)
528    }
529    #[inline]
530    fn get_and_set_nonblocking(&mut self, fd: Fd, nonblocking: bool) -> Result<bool> {
531        (&mut &*self).get_and_set_nonblocking(fd, nonblocking)
532    }
533    #[inline]
534    fn fcntl_getfd(&self, fd: Fd) -> Result<EnumSet<FdFlag>> {
535        (&self).fcntl_getfd(fd)
536    }
537    #[inline]
538    fn fcntl_setfd(&mut self, fd: Fd, flags: EnumSet<FdFlag>) -> Result<()> {
539        (&mut &*self).fcntl_setfd(fd, flags)
540    }
541    #[inline]
542    fn isatty(&self, fd: Fd) -> bool {
543        (&self).isatty(fd)
544    }
545    #[inline]
546    fn read(&mut self, fd: Fd, buffer: &mut [u8]) -> Result<usize> {
547        (&mut &*self).read(fd, buffer)
548    }
549    #[inline]
550    fn write(&mut self, fd: Fd, buffer: &[u8]) -> Result<usize> {
551        (&mut &*self).write(fd, buffer)
552    }
553    #[inline]
554    fn lseek(&mut self, fd: Fd, position: SeekFrom) -> Result<u64> {
555        (&mut &*self).lseek(fd, position)
556    }
557    #[inline]
558    fn fdopendir(&mut self, fd: Fd) -> Result<Box<dyn Dir>> {
559        (&mut &*self).fdopendir(fd)
560    }
561    #[inline]
562    fn opendir(&mut self, path: &CStr) -> Result<Box<dyn Dir>> {
563        (&mut &*self).opendir(path)
564    }
565    #[inline]
566    fn umask(&mut self, mask: Mode) -> Mode {
567        (&mut &*self).umask(mask)
568    }
569    #[inline]
570    fn now(&self) -> Instant {
571        (&self).now()
572    }
573    #[inline]
574    fn times(&self) -> Result<Times> {
575        (&self).times()
576    }
577    #[inline]
578    fn validate_signal(&self, number: signal::RawNumber) -> Option<(signal::Name, signal::Number)> {
579        (&self).validate_signal(number)
580    }
581    #[inline]
582    fn signal_number_from_name(&self, name: signal::Name) -> Option<signal::Number> {
583        System::signal_number_from_name(&self, name)
584    }
585    #[inline]
586    fn sigmask(
587        &mut self,
588        op: Option<(SigmaskOp, &[signal::Number])>,
589        old_mask: Option<&mut Vec<signal::Number>>,
590    ) -> Result<()> {
591        (&mut &*self).sigmask(op, old_mask)
592    }
593    #[inline]
594    fn sigaction(&mut self, signal: signal::Number, action: Disposition) -> Result<Disposition> {
595        (&mut &*self).sigaction(signal, action)
596    }
597    #[inline]
598    fn caught_signals(&mut self) -> Vec<signal::Number> {
599        (&mut &*self).caught_signals()
600    }
601    #[inline]
602    fn kill(
603        &mut self,
604        target: Pid,
605        signal: Option<signal::Number>,
606    ) -> Pin<Box<dyn Future<Output = Result<()>>>> {
607        (&mut &*self).kill(target, signal)
608    }
609    #[inline]
610    fn select(
611        &mut self,
612        readers: &mut Vec<Fd>,
613        writers: &mut Vec<Fd>,
614        timeout: Option<Duration>,
615        signal_mask: Option<&[signal::Number]>,
616    ) -> Result<c_int> {
617        (&mut &*self).select(readers, writers, timeout, signal_mask)
618    }
619    #[inline]
620    fn getpid(&self) -> Pid {
621        (&self).getpid()
622    }
623    #[inline]
624    fn getppid(&self) -> Pid {
625        (&self).getppid()
626    }
627    #[inline]
628    fn getpgrp(&self) -> Pid {
629        (&self).getpgrp()
630    }
631    #[inline]
632    fn setpgid(&mut self, pid: Pid, pgid: Pid) -> Result<()> {
633        (&mut &*self).setpgid(pid, pgid)
634    }
635    #[inline]
636    fn tcgetpgrp(&self, fd: Fd) -> Result<Pid> {
637        (&self).tcgetpgrp(fd)
638    }
639    #[inline]
640    fn tcsetpgrp(&mut self, fd: Fd, pgid: Pid) -> Result<()> {
641        (&mut &*self).tcsetpgrp(fd, pgid)
642    }
643    #[inline]
644    fn new_child_process(&mut self) -> Result<ChildProcessStarter> {
645        (&mut &*self).new_child_process()
646    }
647    #[inline]
648    fn wait(&mut self, target: Pid) -> Result<Option<(Pid, ProcessState)>> {
649        (&mut &*self).wait(target)
650    }
651    #[inline]
652    fn execve(&mut self, path: &CStr, args: &[CString], envs: &[CString]) -> Result<Infallible> {
653        (&mut &*self).execve(path, args, envs)
654    }
655    #[inline]
656    fn getcwd(&self) -> Result<PathBuf> {
657        (&self).getcwd()
658    }
659    #[inline]
660    fn chdir(&mut self, path: &CStr) -> Result<()> {
661        (&mut &*self).chdir(path)
662    }
663    #[inline]
664    fn getuid(&self) -> Uid {
665        (&self).getuid()
666    }
667    #[inline]
668    fn geteuid(&self) -> Uid {
669        (&self).geteuid()
670    }
671    #[inline]
672    fn getgid(&self) -> Gid {
673        (&self).getgid()
674    }
675    #[inline]
676    fn getegid(&self) -> Gid {
677        (&self).getegid()
678    }
679    #[inline]
680    fn getpwnam_dir(&self, name: &str) -> Result<Option<PathBuf>> {
681        (&self).getpwnam_dir(name)
682    }
683    #[inline]
684    fn confstr_path(&self) -> Result<UnixString> {
685        (&self).confstr_path()
686    }
687    #[inline]
688    fn shell_path(&self) -> CString {
689        (&self).shell_path()
690    }
691    #[inline]
692    fn getrlimit(&self, resource: Resource) -> Result<LimitPair> {
693        (&self).getrlimit(resource)
694    }
695    #[inline]
696    fn setrlimit(&mut self, resource: Resource, limits: LimitPair) -> Result<()> {
697        (&mut &*self).setrlimit(resource, limits)
698    }
699}
700
701impl SignalSystem for &SharedSystem {
702    #[inline]
703    fn signal_name_from_number(&self, number: signal::Number) -> signal::Name {
704        SystemEx::signal_name_from_number(*self, number)
705    }
706
707    #[inline]
708    fn signal_number_from_name(&self, name: signal::Name) -> Option<signal::Number> {
709        System::signal_number_from_name(*self, name)
710    }
711
712    fn set_disposition(
713        &mut self,
714        signal: signal::Number,
715        disposition: Disposition,
716    ) -> Result<Disposition> {
717        self.0.borrow_mut().set_disposition(signal, disposition)
718    }
719}
720
721impl SignalSystem for SharedSystem {
722    #[inline]
723    fn signal_name_from_number(&self, number: signal::Number) -> signal::Name {
724        SystemEx::signal_name_from_number(self, number)
725    }
726
727    #[inline]
728    fn signal_number_from_name(&self, name: signal::Name) -> Option<signal::Number> {
729        System::signal_number_from_name(self, name)
730    }
731
732    #[inline]
733    fn set_disposition(
734        &mut self,
735        signal: signal::Number,
736        disposition: Disposition,
737    ) -> Result<Disposition> {
738        self.0.borrow_mut().set_disposition(signal, disposition)
739    }
740}
741
742#[cfg(test)]
743mod tests {
744    use super::super::r#virtual::VirtualSystem;
745    use super::super::r#virtual::PIPE_SIZE;
746    use super::super::r#virtual::{SIGCHLD, SIGINT, SIGTERM, SIGUSR1};
747    use super::*;
748    use assert_matches::assert_matches;
749    use futures_util::task::noop_waker_ref;
750    use futures_util::FutureExt as _;
751    use std::task::Context;
752    use std::task::Poll;
753    use std::time::Duration;
754
755    #[test]
756    fn shared_system_read_async_ready() {
757        let mut system = SharedSystem::new(Box::new(VirtualSystem::new()));
758        let (reader, writer) = system.pipe().unwrap();
759        system.write(writer, &[42]).unwrap();
760
761        let mut buffer = [0; 2];
762        let result = system.read_async(reader, &mut buffer).now_or_never();
763        assert_eq!(result, Some(Ok(1)));
764        assert_eq!(buffer[..1], [42]);
765    }
766
767    #[test]
768    fn shared_system_read_async_not_ready_at_first() {
769        let system = VirtualSystem::new();
770        let process_id = system.process_id;
771        let state = Rc::clone(&system.state);
772        let mut system = SharedSystem::new(Box::new(system));
773        let system2 = system.clone();
774        let (reader, writer) = system.pipe().unwrap();
775
776        let mut context = Context::from_waker(noop_waker_ref());
777        let mut buffer = [0; 2];
778        let mut future = Box::pin(system.read_async(reader, &mut buffer));
779        let result = future.as_mut().poll(&mut context);
780        assert_eq!(result, Poll::Pending);
781
782        let result = system2.select(false);
783        assert_eq!(result, Ok(()));
784        let result = future.as_mut().poll(&mut context);
785        assert_eq!(result, Poll::Pending);
786
787        state.borrow_mut().processes[&process_id].fds[&writer]
788            .open_file_description
789            .borrow_mut()
790            .write(&[56])
791            .unwrap();
792
793        let result = future.as_mut().poll(&mut context);
794        drop(future);
795        assert_eq!(result, Poll::Ready(Ok(1)));
796        assert_eq!(buffer[..1], [56]);
797    }
798
799    #[test]
800    fn shared_system_write_all_ready() {
801        let mut system = SharedSystem::new(Box::new(VirtualSystem::new()));
802        let (reader, writer) = system.pipe().unwrap();
803        let result = system.write_all(writer, &[17]).now_or_never().unwrap();
804        assert_eq!(result, Ok(1));
805
806        let mut buffer = [0; 2];
807        system.read(reader, &mut buffer).unwrap();
808        assert_eq!(buffer[..1], [17]);
809    }
810
811    #[test]
812    fn shared_system_write_all_not_ready_at_first() {
813        let system = VirtualSystem::new();
814        let process_id = system.process_id;
815        let state = Rc::clone(&system.state);
816        let mut system = SharedSystem::new(Box::new(system));
817        let (reader, writer) = system.pipe().unwrap();
818
819        state.borrow_mut().processes[&process_id].fds[&writer]
820            .open_file_description
821            .borrow_mut()
822            .write(&[42; PIPE_SIZE])
823            .unwrap();
824
825        let mut context = Context::from_waker(noop_waker_ref());
826        let mut out_buffer = [87; PIPE_SIZE];
827        out_buffer[0] = 0;
828        out_buffer[1] = 1;
829        out_buffer[PIPE_SIZE - 2] = 0xFE;
830        out_buffer[PIPE_SIZE - 1] = 0xFF;
831        let mut future = Box::pin(system.write_all(writer, &out_buffer));
832        let result = future.as_mut().poll(&mut context);
833        assert_eq!(result, Poll::Pending);
834
835        let mut in_buffer = [0; PIPE_SIZE - 1];
836        state.borrow_mut().processes[&process_id].fds[&reader]
837            .open_file_description
838            .borrow_mut()
839            .read(&mut in_buffer)
840            .unwrap();
841        assert_eq!(in_buffer, [42; PIPE_SIZE - 1]);
842
843        let result = future.as_mut().poll(&mut context);
844        assert_eq!(result, Poll::Pending);
845
846        in_buffer[0] = 0;
847        state.borrow_mut().processes[&process_id].fds[&reader]
848            .open_file_description
849            .borrow_mut()
850            .read(&mut in_buffer[..1])
851            .unwrap();
852        assert_eq!(in_buffer[..1], [42; 1]);
853
854        let result = future.as_mut().poll(&mut context);
855        assert_eq!(result, Poll::Ready(Ok(out_buffer.len())));
856
857        state.borrow_mut().processes[&process_id].fds[&reader]
858            .open_file_description
859            .borrow_mut()
860            .read(&mut in_buffer)
861            .unwrap();
862        assert_eq!(in_buffer, out_buffer[..PIPE_SIZE - 1]);
863        state.borrow_mut().processes[&process_id].fds[&reader]
864            .open_file_description
865            .borrow_mut()
866            .read(&mut in_buffer)
867            .unwrap();
868        assert_eq!(in_buffer[..1], out_buffer[PIPE_SIZE - 1..]);
869    }
870
871    #[test]
872    fn shared_system_write_all_empty() {
873        let system = VirtualSystem::new();
874        let process_id = system.process_id;
875        let state = Rc::clone(&system.state);
876        let mut system = SharedSystem::new(Box::new(system));
877        let (_reader, writer) = system.pipe().unwrap();
878
879        state.borrow_mut().processes[&process_id].fds[&writer]
880            .open_file_description
881            .borrow_mut()
882            .write(&[0; PIPE_SIZE])
883            .unwrap();
884
885        // Even if the pipe is full, empty write succeeds.
886        let mut context = Context::from_waker(noop_waker_ref());
887        let mut future = Box::pin(system.write_all(writer, &[]));
888        let result = future.as_mut().poll(&mut context);
889        assert_eq!(result, Poll::Ready(Ok(0)));
890        // TODO Make sure `write` is not called at all
891    }
892
893    // TODO Test SharedSystem::write_all where second write returns EINTR
894
895    #[test]
896    fn shared_system_wait_until() {
897        let system = VirtualSystem::new();
898        let state = Rc::clone(&system.state);
899        let system = SharedSystem::new(Box::new(system));
900        let start = Instant::now();
901        state.borrow_mut().now = Some(start);
902        let target = start + Duration::from_millis(1_125);
903
904        let mut future = Box::pin(system.wait_until(target));
905        let mut context = Context::from_waker(noop_waker_ref());
906        let poll = future.as_mut().poll(&mut context);
907        assert_eq!(poll, Poll::Pending);
908
909        system.select(false).unwrap();
910        let poll = future.as_mut().poll(&mut context);
911        assert_eq!(poll, Poll::Ready(()));
912        assert_eq!(state.borrow().now, Some(target));
913    }
914
915    #[test]
916    fn shared_system_wait_for_signals() {
917        let system = VirtualSystem::new();
918        let process_id = system.process_id;
919        let state = Rc::clone(&system.state);
920        let mut system = SharedSystem::new(Box::new(system));
921        system.set_disposition(SIGCHLD, Disposition::Catch).unwrap();
922        system.set_disposition(SIGINT, Disposition::Catch).unwrap();
923        system.set_disposition(SIGUSR1, Disposition::Catch).unwrap();
924
925        let mut context = Context::from_waker(noop_waker_ref());
926        let mut future = Box::pin(system.wait_for_signals());
927        let result = future.as_mut().poll(&mut context);
928        assert_eq!(result, Poll::Pending);
929
930        {
931            let mut state = state.borrow_mut();
932            let process = state.processes.get_mut(&process_id).unwrap();
933            assert!(process.blocked_signals().contains(&SIGCHLD));
934            assert!(process.blocked_signals().contains(&SIGINT));
935            assert!(process.blocked_signals().contains(&SIGUSR1));
936            let _ = process.raise_signal(SIGCHLD);
937            let _ = process.raise_signal(SIGINT);
938        }
939        let result = future.as_mut().poll(&mut context);
940        assert_eq!(result, Poll::Pending);
941
942        system.select(false).unwrap();
943        let result = future.as_mut().poll(&mut context);
944        assert_matches!(result, Poll::Ready(signals) => {
945            assert_eq!(signals.len(), 2);
946            assert!(signals.contains(&SIGCHLD));
947            assert!(signals.contains(&SIGINT));
948        });
949    }
950
951    #[test]
952    fn shared_system_wait_for_signal_returns_on_caught() {
953        let system = VirtualSystem::new();
954        let process_id = system.process_id;
955        let state = Rc::clone(&system.state);
956        let mut system = SharedSystem::new(Box::new(system));
957        system.set_disposition(SIGCHLD, Disposition::Catch).unwrap();
958
959        let mut context = Context::from_waker(noop_waker_ref());
960        let mut future = Box::pin(system.wait_for_signal(SIGCHLD));
961        let result = future.as_mut().poll(&mut context);
962        assert_eq!(result, Poll::Pending);
963
964        {
965            let mut state = state.borrow_mut();
966            let process = state.processes.get_mut(&process_id).unwrap();
967            assert!(process.blocked_signals().contains(&SIGCHLD));
968            let _ = process.raise_signal(SIGCHLD);
969        }
970        let result = future.as_mut().poll(&mut context);
971        assert_eq!(result, Poll::Pending);
972
973        system.select(false).unwrap();
974        let result = future.as_mut().poll(&mut context);
975        assert_eq!(result, Poll::Ready(()));
976    }
977
978    #[test]
979    fn shared_system_wait_for_signal_ignores_irrelevant_signals() {
980        let system = VirtualSystem::new();
981        let process_id = system.process_id;
982        let state = Rc::clone(&system.state);
983        let mut system = SharedSystem::new(Box::new(system));
984        system.set_disposition(SIGINT, Disposition::Catch).unwrap();
985        system.set_disposition(SIGTERM, Disposition::Catch).unwrap();
986
987        let mut context = Context::from_waker(noop_waker_ref());
988        let mut future = Box::pin(system.wait_for_signal(SIGINT));
989        let result = future.as_mut().poll(&mut context);
990        assert_eq!(result, Poll::Pending);
991
992        {
993            let mut state = state.borrow_mut();
994            let process = state.processes.get_mut(&process_id).unwrap();
995            let _ = process.raise_signal(SIGCHLD);
996            let _ = process.raise_signal(SIGTERM);
997        }
998        system.select(false).unwrap();
999
1000        let result = future.as_mut().poll(&mut context);
1001        assert_eq!(result, Poll::Pending);
1002    }
1003
1004    #[test]
1005    fn shared_system_select_consumes_all_pending_signals() {
1006        let system = VirtualSystem::new();
1007        let process_id = system.process_id;
1008        let state = Rc::clone(&system.state);
1009        let mut system = SharedSystem::new(Box::new(system));
1010        system.set_disposition(SIGINT, Disposition::Catch).unwrap();
1011        system.set_disposition(SIGTERM, Disposition::Catch).unwrap();
1012
1013        {
1014            let mut state = state.borrow_mut();
1015            let process = state.processes.get_mut(&process_id).unwrap();
1016            let _ = process.raise_signal(SIGINT);
1017            let _ = process.raise_signal(SIGTERM);
1018        }
1019        system.select(false).unwrap();
1020
1021        let state = state.borrow();
1022        let process = state.processes.get(&process_id).unwrap();
1023        let blocked = process.blocked_signals();
1024        assert!(blocked.contains(&SIGINT));
1025        assert!(blocked.contains(&SIGTERM));
1026        let pending = process.pending_signals();
1027        assert!(!pending.contains(&SIGINT));
1028        assert!(!pending.contains(&SIGTERM));
1029    }
1030
1031    #[test]
1032    fn shared_system_select_does_not_wake_signal_waiters_on_io() {
1033        let system = VirtualSystem::new();
1034        let mut system_1 = SharedSystem::new(Box::new(system));
1035        let mut system_2 = system_1.clone();
1036        let mut system_3 = system_1.clone();
1037        let (reader, writer) = system_1.pipe().unwrap();
1038        system_2
1039            .set_disposition(SIGCHLD, Disposition::Catch)
1040            .unwrap();
1041
1042        let mut buffer = [0];
1043        let mut read_future = Box::pin(system_1.read_async(reader, &mut buffer));
1044        let mut signal_future = Box::pin(system_2.wait_for_signals());
1045        let mut context = Context::from_waker(noop_waker_ref());
1046        let result = read_future.as_mut().poll(&mut context);
1047        assert_eq!(result, Poll::Pending);
1048        let result = signal_future.as_mut().poll(&mut context);
1049        assert_eq!(result, Poll::Pending);
1050        system_3.write(writer, &[42]).unwrap();
1051        system_3.select(false).unwrap();
1052
1053        let result = read_future.as_mut().poll(&mut context);
1054        assert_eq!(result, Poll::Ready(Ok(1)));
1055        let result = signal_future.as_mut().poll(&mut context);
1056        assert_eq!(result, Poll::Pending);
1057    }
1058
1059    #[test]
1060    fn shared_system_select_poll() {
1061        let system = VirtualSystem::new();
1062        let state = Rc::clone(&system.state);
1063        let system = SharedSystem::new(Box::new(system));
1064        let start = Instant::now();
1065        state.borrow_mut().now = Some(start);
1066        let target = start + Duration::from_millis(1_125);
1067
1068        let mut future = Box::pin(system.wait_until(target));
1069        let mut context = Context::from_waker(noop_waker_ref());
1070        let poll = future.as_mut().poll(&mut context);
1071        assert_eq!(poll, Poll::Pending);
1072
1073        system.select(true).unwrap();
1074        let poll = future.as_mut().poll(&mut context);
1075        assert_eq!(poll, Poll::Pending);
1076        assert_eq!(state.borrow().now, Some(start));
1077    }
1078}