Skip to main content

yash_env/system/virtual/
select.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//! Implementation of [`Select`] for [`VirtualSystem`]
18
19use super::fd_set::FdSet;
20use super::{
21    Duration, Errno, Result, Select, SigmaskOp, Sigset, TryInto as _, VirtualSystem, raise_sigchld,
22    signal,
23};
24use crate::job::ProcessState;
25use crate::system::FdSet as _;
26use std::cell::{Cell, LazyCell};
27use std::ffi::c_int;
28use std::future::poll_fn;
29use std::rc::Rc;
30use std::task::{Poll, Waker};
31
32impl Select for VirtualSystem {
33    type FdSet = FdSet;
34
35    /// Waits for a next event.
36    ///
37    /// The `VirtualSystem` implementation for this method simulates the
38    /// blocking behavior of `select` by returning a future that becomes ready
39    /// when the specified FDs are ready, the timeout expires, or a signal is
40    /// delivered. However, it does not actually block the calling thread.
41    /// Instead, it relies on the caller to poll the returned future to
42    /// determine when the event occurs. This design allows the `VirtualSystem`
43    /// to be used in asynchronous contexts without blocking the entire thread,
44    /// while still providing the expected behavior of `select`.
45    fn select<'a>(
46        &self,
47        readers: &'a mut FdSet,
48        writers: &'a mut FdSet,
49        timeout: Option<Duration>,
50        signal_mask: Option<&Sigset>,
51    ) -> impl Future<Output = Result<c_int>> + use<'a> {
52        let this = self.clone();
53        let signal_mask = signal_mask.map(|mask| mask.iter().copied().collect::<Vec<_>>());
54        #[allow(clippy::await_holding_refcell_ref, reason = "false positive")]
55        async move {
56            let (old_mask, old_caught_signals, deadline) = {
57                let state = &mut *this.state.borrow_mut();
58                let proc = state
59                    .processes
60                    .get_mut(&this.process_id)
61                    .expect("the current process should be in the system state");
62
63                let old_caught_signals = proc.caught_signals.len();
64
65                let old_mask = match signal_mask {
66                    None => None,
67                    Some(new_mask) => {
68                        let old_mask = proc
69                            .blocked_signals()
70                            .iter()
71                            .copied()
72                            .collect::<Vec<signal::Number>>();
73
74                        let result = proc.block_signals(SigmaskOp::Set, new_mask);
75                        if result.process_state_changed {
76                            let ppid = proc.ppid;
77                            raise_sigchld(state, ppid);
78                        }
79
80                        Some(old_mask)
81                    }
82                };
83
84                let deadline = match timeout {
85                    // Don't require the now time if the timeout is zero or infinite
86                    None | Some(Duration::ZERO) => None,
87                    Some(timeout) => {
88                        let now = state.now;
89                        let now = now.expect("the current time should be set in the system state");
90                        Some(now + timeout)
91                    }
92                };
93
94                (old_mask, old_caught_signals, deadline)
95            };
96
97            let waker: LazyCell<Rc<Cell<Option<Waker>>>> = LazyCell::default();
98
99            let result = poll_fn(|context| {
100                let state = &mut *this.state.borrow_mut();
101                let proc = state
102                    .processes
103                    .get_mut(&this.process_id)
104                    .expect("the current process should be in the system state");
105
106                // If the process is currently suspended, do nothing until resumed
107                if let ProcessState::Halted(reason) = proc.state() {
108                    if reason.is_stopped() {
109                        waker.set(Some(context.waker().clone()));
110                        proc.wake_on_resumption(Rc::downgrade(&waker));
111                        return Poll::Pending;
112                    }
113                }
114
115                // Check for delivered signals
116                if proc.caught_signals.len() != old_caught_signals {
117                    return Poll::Ready(Err(Errno::EINTR));
118                }
119
120                // Find ready FDs
121                let mut ready_readers = FdSet::new();
122                let mut ready_writers = FdSet::new();
123                for fd in readers.iter().cloned() {
124                    let Some(fd_body) = proc.fds().get(&fd) else {
125                        return Poll::Ready(Err(Errno::EBADF));
126                    };
127                    let ofd = fd_body.open_file_description.borrow();
128                    if ofd.is_ready_for_reading() {
129                        ready_readers.insert(fd);
130                    }
131                }
132                for fd in writers.iter().cloned() {
133                    let Some(fd_body) = proc.fds().get(&fd) else {
134                        return Poll::Ready(Err(Errno::EBADF));
135                    };
136                    let ofd = fd_body.open_file_description.borrow();
137                    if ofd.is_ready_for_writing() {
138                        ready_writers.insert(fd);
139                    }
140                }
141                let count = (ready_readers.len() + ready_writers.len())
142                    .try_into()
143                    .unwrap();
144                if count > 0 {
145                    *readers = ready_readers;
146                    *writers = ready_writers;
147                    return Poll::Ready(Ok(count));
148                }
149
150                // Check for the deadline
151                let expired = match deadline {
152                    None => timeout == Some(Duration::ZERO),
153                    Some(deadline) => {
154                        let now = state.now;
155                        let now = now.expect("the current time should be set in the system state");
156                        now >= deadline
157                    }
158                };
159                if expired {
160                    *readers = FdSet::new();
161                    *writers = FdSet::new();
162                    return Poll::Ready(Ok(0));
163                }
164
165                // Register wakers for the expected events
166                waker.set(Some(context.waker().clone()));
167                proc.register_signal_waker(Rc::downgrade(&waker));
168                for fd in readers.iter() {
169                    let mut ofd = proc.fds()[fd].open_file_description.borrow_mut();
170                    ofd.register_reader_waker(Rc::downgrade(&waker));
171                }
172                for fd in writers.iter() {
173                    let mut ofd = proc.fds()[fd].open_file_description.borrow_mut();
174                    ofd.register_writer_waker(Rc::downgrade(&waker));
175                }
176                if let Some(deadline) = deadline {
177                    state.scheduled_wakers.push(deadline, Rc::downgrade(&waker));
178                }
179                Poll::Pending
180            })
181            .await;
182
183            drop(waker);
184
185            // Restore the previous signal mask
186            if let Some(old_mask) = old_mask {
187                let mut state = this.state.borrow_mut();
188                let proc = state
189                    .processes
190                    .get_mut(&this.process_id)
191                    .expect("the current process should be in the system state");
192                let result = proc.block_signals(SigmaskOp::Set, old_mask);
193                if result.process_state_changed {
194                    let ppid = proc.ppid;
195                    raise_sigchld(&mut state, ppid);
196                    drop(state);
197                    this.block_until_running().await;
198                }
199            }
200
201            result
202        }
203    }
204}
205
206#[cfg(test)]
207mod tests {
208    use super::super::Process;
209    use super::super::{PIPE_BUF, PIPE_SIZE, SIGCHLD, SIGCONT, SIGTSTP};
210    use super::*;
211    use crate::io::Fd;
212    use crate::job::Pid;
213    use crate::system::{
214        CaughtSignals as _, Close as _, Disposition, Pipe as _, Read as _, SendSignal as _,
215        Sigaction as _, Sigmask as _, Sigset as _, Write as _,
216    };
217    use crate::test_helper::WakeFlag;
218    use futures_util::FutureExt as _;
219    use std::pin::pin;
220    use std::sync::Arc;
221    use std::task::{Context, Waker};
222    use std::time::Instant;
223
224    #[test]
225    fn select_with_no_condition_blocks_forever() {
226        let system = VirtualSystem::new();
227        let mut readers = FdSet::new();
228        let mut writers = FdSet::new();
229        let mut select = pin!(system.select(&mut readers, &mut writers, None, None));
230
231        // Polling the future should return pending, and it should not be woken up.
232        let woken = Arc::new(WakeFlag::new());
233        let waker = Waker::from(Arc::clone(&woken));
234        let mut context = Context::from_waker(&waker);
235        let poll = select.as_mut().poll(&mut context);
236        assert_eq!(poll, Poll::Pending);
237        assert!(!woken.is_woken());
238    }
239
240    #[test]
241    fn select_with_zero_timeout_returns_immediately() {
242        let system = VirtualSystem::new();
243        let mut readers = FdSet::new();
244        let mut writers = FdSet::new();
245        let mut select =
246            pin!(system.select(&mut readers, &mut writers, Some(Duration::ZERO), None));
247
248        // Polling the future should return ready immediately with a timeout result.
249        let woken = Arc::new(WakeFlag::new());
250        let waker = Waker::from(Arc::clone(&woken));
251        let mut context = Context::from_waker(&waker);
252        let poll = select.as_mut().poll(&mut context);
253        assert_eq!(poll, Poll::Ready(Ok(0)));
254        assert!(!woken.is_woken());
255    }
256
257    #[test]
258    fn select_regular_file_is_always_ready() {
259        let system = VirtualSystem::new();
260        let mut readers = FdSet::from_fds([Fd::STDIN]);
261        let mut writers = FdSet::from_fds([Fd::STDOUT, Fd::STDERR]);
262        {
263            let mut select = pin!(system.select(&mut readers, &mut writers, None, None));
264
265            let woken = Arc::new(WakeFlag::new());
266            let waker = Waker::from(Arc::clone(&woken));
267            let mut context = Context::from_waker(&waker);
268            let poll = select.as_mut().poll(&mut context);
269            assert_eq!(poll, Poll::Ready(Ok(3)));
270            assert!(!woken.is_woken());
271        }
272        assert_eq!(readers, FdSet::from_fds([Fd::STDIN]));
273        assert_eq!(writers, FdSet::from_fds([Fd::STDOUT, Fd::STDERR]));
274    }
275
276    #[test]
277    fn select_pipe_reader_is_ready_if_writer_is_closed() {
278        let system = VirtualSystem::new();
279        let (reader, writer) = system.pipe().unwrap();
280        system.close(writer).unwrap();
281        let mut readers = FdSet::from_fds([reader]);
282        let mut writers = FdSet::new();
283        {
284            let mut select = pin!(system.select(&mut readers, &mut writers, None, None));
285
286            let woken = Arc::new(WakeFlag::new());
287            let waker = Waker::from(Arc::clone(&woken));
288            let mut context = Context::from_waker(&waker);
289            let poll = select.as_mut().poll(&mut context);
290            assert_eq!(poll, Poll::Ready(Ok(1)));
291            assert!(!woken.is_woken());
292        }
293        assert_eq!(readers, FdSet::from_fds([reader]));
294        assert_eq!(writers, FdSet::new());
295    }
296
297    #[test]
298    fn select_pipe_reader_is_ready_if_something_has_been_written() {
299        let system = VirtualSystem::new();
300        let (reader, writer) = system.pipe().unwrap();
301        system.write(writer, &[0]).now_or_never().unwrap().unwrap();
302        let mut readers = FdSet::from_fds([reader]);
303        let mut writers = FdSet::new();
304        {
305            let mut select = pin!(system.select(&mut readers, &mut writers, None, None));
306
307            let woken = Arc::new(WakeFlag::new());
308            let waker = Waker::from(Arc::clone(&woken));
309            let mut context = Context::from_waker(&waker);
310            let poll = select.as_mut().poll(&mut context);
311            assert_eq!(poll, Poll::Ready(Ok(1)));
312            assert!(!woken.is_woken());
313        }
314        assert_eq!(readers, FdSet::from_fds([reader]));
315        assert_eq!(writers, FdSet::new());
316    }
317
318    #[test]
319    fn select_pipe_reader_gets_ready_when_some_data_is_written() {
320        let system = VirtualSystem::new();
321        let (reader, writer) = system.pipe().unwrap();
322        let mut readers = FdSet::from_fds([reader]);
323        let mut writers = FdSet::new();
324        {
325            let mut select = pin!(system.select(&mut readers, &mut writers, None, None));
326
327            // Nothing has been written yet, so the future should not be ready,
328            // and it should not be woken up.
329            let woken = Arc::new(WakeFlag::new());
330            let waker = Waker::from(Arc::clone(&woken));
331            let mut context = Context::from_waker(&waker);
332            let poll = select.as_mut().poll(&mut context);
333            assert_eq!(poll, Poll::Pending);
334            assert!(!woken.is_woken());
335
336            // Write some data to the pipe. The future should now be woken up.
337            system.write(writer, &[0]).now_or_never().unwrap().unwrap();
338            assert!(woken.is_woken());
339
340            // Polling the future should now return ready with the reader FD.
341            let woken = Arc::new(WakeFlag::new());
342            let waker = Waker::from(Arc::clone(&woken));
343            let mut context = Context::from_waker(&waker);
344            let poll = select.as_mut().poll(&mut context);
345            assert_eq!(poll, Poll::Ready(Ok(1)));
346            assert!(!woken.is_woken());
347        }
348        assert_eq!(readers, FdSet::from_fds([reader]));
349        assert_eq!(writers, FdSet::new());
350    }
351
352    #[test]
353    fn select_pipe_writer_is_ready_if_pipe_is_not_full() {
354        let system = VirtualSystem::new();
355        let (_reader, writer) = system.pipe().unwrap();
356        let mut readers = FdSet::new();
357        let mut writers = FdSet::from_fds([writer]);
358        {
359            let mut select = pin!(system.select(&mut readers, &mut writers, None, None));
360
361            let woken = Arc::new(WakeFlag::new());
362            let waker = Waker::from(Arc::clone(&woken));
363            let mut context = Context::from_waker(&waker);
364            let poll = select.as_mut().poll(&mut context);
365            assert_eq!(poll, Poll::Ready(Ok(1)));
366            assert!(!woken.is_woken());
367        }
368        assert_eq!(readers, FdSet::new());
369        assert_eq!(writers, FdSet::from_fds([writer]));
370    }
371
372    #[test]
373    fn select_pipe_writer_gets_ready_when_some_data_is_read() {
374        let system = VirtualSystem::new();
375        let (reader, writer) = system.pipe().unwrap();
376        let mut readers = FdSet::new();
377        let mut writers = FdSet::from_fds([writer]);
378
379        // Fill the pipe buffer.
380        system
381            .write(writer, &[0; PIPE_SIZE])
382            .now_or_never()
383            .unwrap()
384            .unwrap();
385
386        {
387            let mut select = pin!(system.select(&mut readers, &mut writers, None, None));
388
389            // The pipe is full, so the future should not be ready, and it should not be woken up.
390            let woken = Arc::new(WakeFlag::new());
391            let waker = Waker::from(Arc::clone(&woken));
392            let mut context = Context::from_waker(&waker);
393            let poll = select.as_mut().poll(&mut context);
394            assert_eq!(poll, Poll::Pending);
395            assert!(!woken.is_woken());
396
397            // Read some data from the pipe. The future should now be woken up.
398            system
399                .read(reader, &mut [0; PIPE_BUF])
400                .now_or_never()
401                .unwrap()
402                .unwrap();
403            assert!(woken.is_woken());
404
405            // Polling the future should now return ready with the writer FD.
406            let woken = Arc::new(WakeFlag::new());
407            let waker = Waker::from(Arc::clone(&woken));
408            let mut context = Context::from_waker(&waker);
409            let poll = select.as_mut().poll(&mut context);
410            assert_eq!(poll, Poll::Ready(Ok(1)));
411            assert!(!woken.is_woken());
412        }
413        assert_eq!(readers, FdSet::new());
414        assert_eq!(writers, FdSet::from_fds([writer]));
415    }
416
417    #[test]
418    fn select_on_unreadable_fd() {
419        let system = VirtualSystem::new();
420        let (_reader, writer) = system.pipe().unwrap();
421        let mut fds = FdSet::from_fds([writer]);
422        let result = system
423            .select(&mut fds, &mut FdSet::new(), None, None)
424            .now_or_never()
425            .unwrap();
426        assert_eq!(result, Ok(1));
427        assert_eq!(fds, FdSet::from_fds([writer]));
428    }
429
430    #[test]
431    fn select_on_unwritable_fd() {
432        let system = VirtualSystem::new();
433        let (reader, _writer) = system.pipe().unwrap();
434        let mut fds = FdSet::from_fds([reader]);
435        let result = system
436            .select(&mut FdSet::new(), &mut fds, None, None)
437            .now_or_never()
438            .unwrap();
439        assert_eq!(result, Ok(1));
440        assert_eq!(fds, FdSet::from_fds([reader]));
441    }
442
443    #[test]
444    fn select_on_invalid_fd_for_readers() {
445        let system = VirtualSystem::new();
446        let mut readers = FdSet::from_fds([Fd(17)]);
447        let mut writers = FdSet::new();
448        {
449            let mut select = pin!(system.select(&mut readers, &mut writers, None, None));
450
451            let woken = Arc::new(WakeFlag::new());
452            let waker = Waker::from(Arc::clone(&woken));
453            let mut context = Context::from_waker(&waker);
454            let poll = select.as_mut().poll(&mut context);
455            assert_eq!(poll, Poll::Ready(Err(Errno::EBADF)));
456            assert!(!woken.is_woken());
457        }
458        assert_eq!(readers, FdSet::from_fds([Fd(17)]));
459        assert_eq!(writers, FdSet::new());
460    }
461
462    #[test]
463    fn select_on_invalid_fd_for_writers() {
464        let system = VirtualSystem::new();
465        let mut readers = FdSet::new();
466        let mut writers = FdSet::from_fds([Fd(17)]);
467        {
468            let mut select = pin!(system.select(&mut readers, &mut writers, None, None));
469
470            let woken = Arc::new(WakeFlag::new());
471            let waker = Waker::from(Arc::clone(&woken));
472            let mut context = Context::from_waker(&waker);
473            let poll = select.as_mut().poll(&mut context);
474            assert_eq!(poll, Poll::Ready(Err(Errno::EBADF)));
475            assert!(!woken.is_woken());
476        }
477        assert_eq!(readers, FdSet::new());
478        assert_eq!(writers, FdSet::from_fds([Fd(17)]));
479    }
480
481    fn system_for_catching_sigchld() -> VirtualSystem {
482        let system = VirtualSystem::new();
483        system
484            .sigmask(Some((SigmaskOp::Add, &Sigset::from(SIGCHLD))), None)
485            .now_or_never()
486            .unwrap()
487            .unwrap();
488        system.sigaction(SIGCHLD, Disposition::Catch).unwrap();
489        system
490    }
491
492    #[test]
493    fn select_on_pending_signal() {
494        let system = system_for_catching_sigchld();
495        let _ = system.current_process_mut().raise_signal(SIGCHLD);
496        let mut readers = FdSet::new();
497        let mut writers = FdSet::new();
498
499        let mut select =
500            pin!(system.select(&mut readers, &mut writers, None, Some(&Sigset::new())));
501
502        let woken = Arc::new(WakeFlag::new());
503        let waker = Waker::from(Arc::clone(&woken));
504        let mut context = Context::from_waker(&waker);
505        let poll = select.as_mut().poll(&mut context);
506        assert_eq!(poll, Poll::Ready(Err(Errno::EINTR)));
507        assert!(!woken.is_woken());
508        assert_eq!(system.caught_signals(), [SIGCHLD]);
509        // Check that the signal mask is the same as before the select call.
510        let mut mask = Sigset::new();
511        system
512            .sigmask(None, Some(&mut mask))
513            .now_or_never()
514            .unwrap()
515            .unwrap();
516        assert_eq!(mask, Sigset::from(SIGCHLD));
517    }
518
519    #[test]
520    fn select_interrupted_by_signal() {
521        let system = VirtualSystem::new();
522        system.sigaction(SIGCHLD, Disposition::Catch).unwrap();
523        let mut readers = FdSet::new();
524        let mut writers = FdSet::new();
525
526        let mut select = pin!(system.select(&mut readers, &mut writers, None, None));
527
528        // Since no conditions were specified, the select call should block indefinitely.
529        let woken = Arc::new(WakeFlag::new());
530        let waker = Waker::from(Arc::clone(&woken));
531        let mut context = Context::from_waker(&waker);
532        let poll = select.as_mut().poll(&mut context);
533        assert_eq!(poll, Poll::Pending);
534        assert!(!woken.is_woken());
535
536        // Even if not woken, it must be safe to poll the future again,
537        // and it should still not be ready.
538        let woken = Arc::new(WakeFlag::new());
539        let waker = Waker::from(Arc::clone(&woken));
540        let mut context = Context::from_waker(&waker);
541        let poll = select.as_mut().poll(&mut context);
542        assert_eq!(poll, Poll::Pending);
543        assert!(!woken.is_woken());
544
545        // When a signal is caught, the future should be woken up.
546        _ = system.current_process_mut().raise_signal(SIGCHLD);
547        assert!(woken.is_woken());
548
549        // Polling the future should now return ready with an EINTR error.
550        let woken = Arc::new(WakeFlag::new());
551        let waker = Waker::from(Arc::clone(&woken));
552        let mut context = Context::from_waker(&waker);
553        let poll = select.as_mut().poll(&mut context);
554        assert_eq!(poll, Poll::Ready(Err(Errno::EINTR)));
555        assert!(!woken.is_woken());
556    }
557
558    #[test]
559    fn select_on_signal_delivered_while_waiting() {
560        let system = system_for_catching_sigchld();
561        let mut readers = FdSet::new();
562        let mut writers = FdSet::new();
563
564        let mut select =
565            pin!(system.select(&mut readers, &mut writers, None, Some(&Sigset::new())));
566
567        // The future should not be ready yet, and it should not be woken up.
568        let woken = Arc::new(WakeFlag::new());
569        let waker = Waker::from(Arc::clone(&woken));
570        let mut context = Context::from_waker(&waker);
571        let poll = select.as_mut().poll(&mut context);
572        assert_eq!(poll, Poll::Pending);
573        assert!(!woken.is_woken());
574        // While waiting, the signal mask passed to select should be in effect
575        let mut mask = Sigset::new();
576        system
577            .sigmask(None, Some(&mut mask))
578            .now_or_never()
579            .unwrap()
580            .unwrap();
581        assert_eq!(mask, Sigset::new());
582
583        // Even if not woken, it must be safe to poll the future again,
584        // and it should still not be ready.
585        let woken = Arc::new(WakeFlag::new());
586        let waker = Waker::from(Arc::clone(&woken));
587        let mut context = Context::from_waker(&waker);
588        let poll = select.as_mut().poll(&mut context);
589        assert_eq!(poll, Poll::Pending);
590        assert!(!woken.is_woken());
591
592        // Raise a signal. The future should now be woken up.
593        let _ = system.current_process_mut().raise_signal(SIGCHLD);
594        assert!(woken.is_woken());
595
596        // Polling the future should now return ready with an EINTR error.
597        let woken = Arc::new(WakeFlag::new());
598        let waker = Waker::from(Arc::clone(&woken));
599        let mut context = Context::from_waker(&waker);
600        let poll = select.as_mut().poll(&mut context);
601        assert_eq!(poll, Poll::Ready(Err(Errno::EINTR)));
602        assert!(!woken.is_woken());
603        assert_eq!(system.caught_signals(), [SIGCHLD]);
604        // Check that the signal mask is the same as before the select call.
605        let mut mask = Sigset::new();
606        system
607            .sigmask(None, Some(&mut mask))
608            .now_or_never()
609            .unwrap()
610            .unwrap();
611        assert_eq!(mask, Sigset::from(SIGCHLD));
612    }
613
614    #[test]
615    fn select_timeout() {
616        let system = VirtualSystem::new();
617        let now = Instant::now();
618        system.state.borrow_mut().now = Some(now);
619
620        // The first pipe is empty, so the reader is not ready.
621        let (reader_1, _writer_1) = system.pipe().unwrap();
622        // The second pipe is full, so the writer is not ready.
623        let (_reader_2, writer_2) = system.pipe().unwrap();
624        system
625            .write(writer_2, &[0; PIPE_SIZE])
626            .now_or_never()
627            .unwrap()
628            .unwrap();
629        let mut readers = FdSet::from_fds([reader_1]);
630        let mut writers = FdSet::from_fds([writer_2]);
631        let timeout = Duration::new(42, 195);
632
633        {
634            let mut select = pin!(system.select(&mut readers, &mut writers, Some(timeout), None));
635
636            // On the first poll, the timeout should not have expired yet,
637            // and the future should not be woken up.
638            let woken = Arc::new(WakeFlag::new());
639            let waker = Waker::from(Arc::clone(&woken));
640            let mut context = Context::from_waker(&waker);
641            let poll = select.as_mut().poll(&mut context);
642            assert_eq!(poll, Poll::Pending);
643            assert!(!woken.is_woken());
644
645            // Advance time by 42 seconds. The timeout is not yet reached.
646            let time_before_timeout = now + Duration::new(42, 0);
647            system.state.borrow_mut().advance_time(time_before_timeout);
648            assert!(!woken.is_woken());
649
650            // Even if not woken, it must be safe to poll the future again,
651            // and it should still not be ready.
652            let woken = Arc::new(WakeFlag::new());
653            let waker = Waker::from(Arc::clone(&woken));
654            let mut context = Context::from_waker(&waker);
655            let poll = select.as_mut().poll(&mut context);
656            assert_eq!(poll, Poll::Pending);
657            assert!(!woken.is_woken());
658
659            // Advance time by another 195 nanoseconds.
660            // The timeout should now be reached, and the future should be woken up.
661            system.state.borrow_mut().advance_time(now + timeout);
662            assert!(woken.is_woken());
663
664            // Polling the future should now return ready with a timeout result.
665            let woken = Arc::new(WakeFlag::new());
666            let waker = Waker::from(Arc::clone(&woken));
667            let mut context = Context::from_waker(&waker);
668            let poll = select.as_mut().poll(&mut context);
669            assert_eq!(poll, Poll::Ready(Ok(0)));
670        }
671        // After a timeout, no readers or writers should be ready
672        assert_eq!(readers, FdSet::new());
673        assert_eq!(writers, FdSet::new());
674    }
675
676    fn virtual_system_with_parent_process() -> VirtualSystem {
677        let system = VirtualSystem::new();
678        let ppid = system.current_process().ppid;
679        let mut parent = Process::with_parent_and_group(Pid(1), Pid(1));
680        parent.set_disposition(SIGCHLD, Disposition::Catch);
681        system.state.borrow_mut().processes.insert(ppid, parent);
682        system
683    }
684
685    /// In this test case, SIGTSTP is blocked and pending when the `select` call
686    /// is made. When the `select` call temporarily unblocks SIGTSTP, the
687    /// pending signal should be delivered, which suspends the process. The
688    /// `select` future should return pending until the process is resumed.
689    #[test]
690    fn select_returns_pending_while_process_is_suspended_1() {
691        let system = virtual_system_with_parent_process();
692        let now = Instant::now();
693        system.state.borrow_mut().now = Some(now);
694        system
695            .sigmask(Some((SigmaskOp::Add, &Sigset::from(SIGTSTP))), None)
696            .now_or_never()
697            .unwrap()
698            .unwrap();
699
700        // Send SIGTSTP while it is blocked
701        system.raise(SIGTSTP).now_or_never().unwrap().unwrap();
702
703        let mut readers = FdSet::new();
704        let mut writers = FdSet::new();
705
706        let mut select = pin!(system.select(
707            &mut readers,
708            &mut writers,
709            Some(Duration::from_secs(1)),
710            Some(&Sigset::new())
711        ));
712
713        let woken = Arc::new(WakeFlag::new());
714        let waker = Waker::from(Arc::clone(&woken));
715        let mut context = Context::from_waker(&waker);
716        let poll = select.as_mut().poll(&mut context);
717        assert_eq!(poll, Poll::Pending);
718        assert!(!woken.is_woken());
719
720        // The select call temporarily unblocks SIGTSTP, so the pending signal should be delivered,
721        // which suspends the process. The parent process should receive a SIGCHLD signal.
722        {
723            let state = system.state.borrow();
724            let ppid = state.processes[&system.process_id].ppid;
725            assert_eq!(state.processes[&ppid].caught_signals, [SIGCHLD]);
726        }
727
728        // Since the process is suspended, the future should not be ready even after the timeout
729        system
730            .state
731            .borrow_mut()
732            .advance_time(now + Duration::from_secs(2));
733        let woken = Arc::new(WakeFlag::new());
734        let waker = Waker::from(Arc::clone(&woken));
735        let mut context = Context::from_waker(&waker);
736        let poll = select.as_mut().poll(&mut context);
737        assert_eq!(poll, Poll::Pending);
738        assert!(!woken.is_woken());
739
740        // When the process is resumed, the future should be woken up
741        system.raise(SIGCONT).now_or_never().unwrap().unwrap();
742        assert!(woken.is_woken());
743
744        // Polling the future should now return ready
745        let woken = Arc::new(WakeFlag::new());
746        let waker = Waker::from(Arc::clone(&woken));
747        let mut context = Context::from_waker(&waker);
748        let poll = select.as_mut().poll(&mut context);
749        assert_eq!(poll, Poll::Ready(Ok(0)));
750    }
751
752    /// In this test case, the process receives a SIGTSTP signal while it is
753    /// waiting in the `select` call that temporarily blocks SIGTSTP. The
754    /// pending signal should be delivered when `select` times out and unblocks
755    /// SIGTSTP, which suspends the process. The `select` future should return
756    /// pending until the process is resumed.
757    #[test]
758    fn select_returns_pending_while_process_is_suspended_2() {
759        let system = virtual_system_with_parent_process();
760        let now = Instant::now();
761        system.state.borrow_mut().now = Some(now);
762
763        let mut readers = FdSet::new();
764        let mut writers = FdSet::new();
765
766        let mut select = pin!(system.select(
767            &mut readers,
768            &mut writers,
769            Some(Duration::from_secs(1)),
770            Some(&Sigset::from(SIGTSTP))
771        ));
772
773        // Initially, the future should not be ready.
774        let woken = Arc::new(WakeFlag::new());
775        let waker = Waker::from(Arc::clone(&woken));
776        let mut context = Context::from_waker(&waker);
777        let poll = select.as_mut().poll(&mut context);
778        assert_eq!(poll, Poll::Pending);
779        assert!(!woken.is_woken());
780
781        // While waiting, SIGTSTP is blocked by the temporary signal mask.
782        let mut mask = Sigset::new();
783        system
784            .sigmask(None, Some(&mut mask))
785            .now_or_never()
786            .unwrap()
787            .unwrap();
788        assert_eq!(mask, Sigset::from(SIGTSTP));
789
790        // Send SIGTSTP while it is blocked. It should remain pending.
791        system.raise(SIGTSTP).now_or_never().unwrap().unwrap();
792        assert!(!woken.is_woken());
793
794        // Polling again should still be pending.
795        let woken = Arc::new(WakeFlag::new());
796        let waker = Waker::from(Arc::clone(&woken));
797        let mut context = Context::from_waker(&waker);
798        let poll = select.as_mut().poll(&mut context);
799        assert_eq!(poll, Poll::Pending);
800        assert!(!woken.is_woken());
801
802        // Advance time to the timeout. This wakes the future.
803        system
804            .state
805            .borrow_mut()
806            .advance_time(now + Duration::from_secs(1));
807        assert!(woken.is_woken());
808
809        // Timeout unblocks SIGTSTP and delivers it, suspending the process.
810        // The future should remain pending until the process is resumed.
811        let woken = Arc::new(WakeFlag::new());
812        let waker = Waker::from(Arc::clone(&woken));
813        let mut context = Context::from_waker(&waker);
814        let poll = select.as_mut().poll(&mut context);
815        assert_eq!(poll, Poll::Pending);
816        assert!(!woken.is_woken());
817
818        // The parent process should have caught SIGCHLD for the suspension.
819        {
820            let state = system.state.borrow();
821            let ppid = state.processes[&system.process_id].ppid;
822            assert_eq!(state.processes[&ppid].caught_signals, [SIGCHLD]);
823        }
824
825        // Resuming the process should wake the future.
826        system.raise(SIGCONT).now_or_never().unwrap().unwrap();
827        assert!(woken.is_woken());
828
829        // Polling the future should now return ready with timeout.
830        let woken = Arc::new(WakeFlag::new());
831        let waker = Waker::from(Arc::clone(&woken));
832        let mut context = Context::from_waker(&waker);
833        let poll = select.as_mut().poll(&mut context);
834        assert_eq!(poll, Poll::Ready(Ok(0)));
835    }
836}