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