1use super::Disposition;
20use super::Gid;
21use super::Mode;
22use super::SigmaskOp;
23use super::Sigset;
24use super::Uid;
25use super::WakerSet;
26use super::io::FdBody;
27use super::signal::{self, SignalEffect};
28use crate::io::Fd;
29use crate::job::Pid;
30use crate::job::ProcessResult;
31use crate::job::ProcessState;
32use crate::path::Path;
33use crate::path::PathBuf;
34use crate::system::Sigset as _;
35use crate::system::resource::INFINITY;
36use crate::system::resource::LimitPair;
37use crate::system::resource::Resource;
38use std::cell::Cell;
39use std::collections::BTreeMap;
40use std::collections::HashMap;
41use std::ffi::CString;
42use std::fmt::Debug;
43use std::ops::BitOr;
44use std::ops::BitOrAssign;
45use std::rc::Weak;
46use std::task::Waker;
47
48#[derive(Clone, derive_more::Debug)]
50pub struct Process {
51 pub(crate) ppid: Pid,
53
54 pub(crate) pgid: Pid,
56
57 uid: Uid,
59
60 euid: Uid,
62
63 gid: Gid,
65
66 egid: Gid,
68
69 pub(crate) fds: BTreeMap<Fd, FdBody>,
71
72 pub(crate) umask: Mode,
74
75 pub(crate) cwd: PathBuf,
77
78 pub(crate) state: ProcessState,
80
81 state_has_changed: bool,
87
88 resumption_awaiters: WakerSet,
90
91 dispositions: HashMap<signal::Number, Disposition>,
96
97 blocked_signals: Sigset,
99
100 pending_signals: Sigset,
102
103 pub(crate) caught_signals: Vec<signal::Number>,
105
106 pub(crate) caught_signals_count: usize,
112
113 signal_wakers: WakerSet,
120
121 pub(crate) resource_limits: HashMap<Resource, LimitPair>,
123
124 pub(crate) last_exec: Option<(CString, Vec<CString>, Vec<CString>)>,
126}
127
128fn min_unused_fd<'a, I: IntoIterator<Item = &'a Fd>>(min: Fd, existings: I) -> Fd {
133 let candidates = (min.0..).map(Fd);
134 let rejections = existings
135 .into_iter()
136 .skip_while(|fd| **fd < min)
137 .map(Some)
138 .chain(std::iter::repeat(None));
139 candidates
140 .zip(rejections)
141 .skip_while(|(candidate, rejection)| Some(candidate) == *rejection)
142 .map(|(candidate, _rejection)| candidate)
143 .next()
144 .unwrap()
145}
146
147impl Process {
148 pub fn with_parent_and_group(ppid: Pid, pgid: Pid) -> Process {
150 Process {
151 ppid,
152 pgid,
153 uid: Uid(1),
154 euid: Uid(1),
155 gid: Gid(1),
156 egid: Gid(1),
157 fds: BTreeMap::new(),
158 umask: Mode::default(),
159 cwd: PathBuf::new(),
160 state: ProcessState::Running,
161 state_has_changed: false,
162 resumption_awaiters: WakerSet::new(),
163 dispositions: HashMap::new(),
164 blocked_signals: Sigset::default(),
165 pending_signals: Sigset::default(),
166 caught_signals: Vec::new(),
167 caught_signals_count: 0,
168 signal_wakers: WakerSet::new(),
169 resource_limits: HashMap::new(),
170 last_exec: None,
171 }
172 }
173
174 pub fn fork_from(ppid: Pid, parent: &Process) -> Process {
178 let mut child = Self::with_parent_and_group(ppid, parent.pgid);
179 child.uid = parent.uid;
180 child.euid = parent.euid;
181 child.gid = parent.gid;
182 child.egid = parent.egid;
183 child.fds = parent.fds.clone();
184 child.dispositions.clone_from(&parent.dispositions);
185 child.blocked_signals.clone_from(&parent.blocked_signals);
186 child
187 }
188
189 #[inline(always)]
191 #[must_use]
192 pub fn ppid(&self) -> Pid {
193 self.ppid
194 }
195
196 #[inline(always)]
198 #[must_use]
199 pub fn pgid(&self) -> Pid {
200 self.pgid
201 }
202
203 #[inline(always)]
205 #[must_use]
206 pub fn uid(&self) -> Uid {
207 self.uid
208 }
209
210 #[inline(always)]
212 pub fn set_uid(&mut self, uid: Uid) {
213 self.uid = uid;
214 }
215
216 #[inline(always)]
218 #[must_use]
219 pub fn euid(&self) -> Uid {
220 self.euid
221 }
222
223 #[inline(always)]
225 pub fn set_euid(&mut self, euid: Uid) {
226 self.euid = euid;
227 }
228
229 #[inline(always)]
231 #[must_use]
232 pub fn gid(&self) -> Gid {
233 self.gid
234 }
235
236 #[inline(always)]
238 pub fn set_gid(&mut self, gid: Gid) {
239 self.gid = gid;
240 }
241
242 #[inline(always)]
244 #[must_use]
245 pub fn egid(&self) -> Gid {
246 self.egid
247 }
248
249 #[inline(always)]
251 pub fn set_egid(&mut self, egid: Gid) {
252 self.egid = egid;
253 }
254
255 #[inline(always)]
257 #[must_use]
258 pub fn fds(&self) -> &BTreeMap<Fd, FdBody> {
259 &self.fds
260 }
261
262 #[inline]
264 #[must_use]
265 pub fn get_fd(&self, fd: Fd) -> Option<&FdBody> {
266 self.fds.get(&fd)
267 }
268
269 #[inline]
271 #[must_use]
272 pub fn get_fd_mut(&mut self, fd: Fd) -> Option<&mut FdBody> {
273 self.fds.get_mut(&fd)
274 }
275
276 pub fn set_fd(&mut self, fd: Fd, body: FdBody) -> Result<Option<FdBody>, FdBody> {
282 let limit = self
283 .resource_limits
284 .get(&Resource::NOFILE)
285 .map(|l| l.soft)
286 .unwrap_or(INFINITY);
287
288 #[allow(
289 clippy::unnecessary_cast,
290 reason = "the types of FD and limit may vary across platforms"
291 )]
292 if limit == INFINITY || (fd.0 as u64) < limit as u64 {
293 Ok(self.fds.insert(fd, body))
294 } else {
295 Err(body)
296 }
297 }
298
299 pub fn open_fd_ge(&mut self, min_fd: Fd, body: FdBody) -> Result<Fd, FdBody> {
307 let fd = min_unused_fd(min_fd, self.fds.keys());
308 let old_body = self.set_fd(fd, body)?;
309 debug_assert_eq!(old_body, None);
310 Ok(fd)
311 }
312
313 pub fn open_fd(&mut self, body: FdBody) -> Result<Fd, FdBody> {
320 self.open_fd_ge(Fd(0), body)
321 }
322
323 pub fn close_fd(&mut self, fd: Fd) -> Option<FdBody> {
325 self.fds.remove(&fd)
326 }
327
328 pub fn close_fds(&mut self) {
330 self.fds.clear();
331 }
332
333 pub fn getcwd(&self) -> &Path {
335 &self.cwd
336 }
337
338 pub fn chdir(&mut self, path: PathBuf) {
342 self.cwd = path
343 }
344
345 pub fn wake_on_resumption(&mut self, waker: Weak<Cell<Option<Waker>>>) {
355 if self.state.is_stopped() {
356 self.resumption_awaiters.insert(waker);
357 }
358 }
359
360 #[inline(always)]
362 #[must_use]
363 pub fn state(&self) -> ProcessState {
364 self.state
365 }
366
367 #[must_use = "You must send SIGCHLD to the parent if set_state returns true"]
377 pub fn set_state(&mut self, state: ProcessState) -> bool {
378 let old_state = std::mem::replace(&mut self.state, state);
379
380 if old_state == state {
381 false
382 } else {
383 match state {
384 ProcessState::Running => self.resumption_awaiters.wake_all(),
385 ProcessState::Halted(result) => {
386 if !result.is_stopped() {
387 self.close_fds()
388 }
389 }
390 }
391 self.state_has_changed = true;
392 true
393 }
394 }
395
396 #[must_use]
399 pub fn state_has_changed(&self) -> bool {
400 self.state_has_changed
401 }
402
403 pub fn take_state(&mut self) -> ProcessState {
406 self.state_has_changed = false;
407 self.state
408 }
409
410 pub fn blocked_signals(&self) -> &Sigset {
412 &self.blocked_signals
413 }
414
415 pub fn pending_signals(&self) -> &Sigset {
420 &self.pending_signals
421 }
422
423 #[must_use = "send SIGCHLD if process state has changed"]
432 pub fn block_signals<I>(&mut self, how: SigmaskOp, signals: I) -> SignalResult
433 where
434 I: IntoIterator<Item = signal::Number>,
435 {
436 match how {
437 SigmaskOp::Set => self.blocked_signals = signals.into_iter().collect(),
438 SigmaskOp::Add => self.blocked_signals.extend(signals),
439 SigmaskOp::Remove => {
440 for signal in signals {
441 self.blocked_signals.remove(signal).ok();
442 }
443 }
444 }
445
446 self.deliver_pending_signals()
447 }
448
449 fn deliver_pending_signals(&mut self) -> SignalResult {
450 let signals_to_deliver = self
451 .pending_signals
452 .difference_to_vec(&self.blocked_signals);
453 let mut result = SignalResult::default();
454 for signal in signals_to_deliver {
455 self.pending_signals.remove(signal).ok();
456 result |= self.deliver_signal(signal);
457 }
458 result
459 }
460
461 pub fn disposition(&self, number: signal::Number) -> Disposition {
466 self.dispositions.get(&number).copied().unwrap_or_default()
467 }
468
469 pub fn set_disposition(
474 &mut self,
475 number: signal::Number,
476 disposition: Disposition,
477 ) -> Disposition {
478 let old_disposition = self.dispositions.insert(number, disposition);
479 old_disposition.unwrap_or_default()
480 }
481
482 #[inline(always)]
484 pub(crate) fn register_signal_waker(&mut self, waker: Weak<Cell<Option<Waker>>>) {
485 self.signal_wakers.insert(waker);
486 }
487
488 #[must_use = "send SIGCHLD if process state has changed"]
498 fn deliver_signal(&mut self, signal: signal::Number) -> SignalResult {
499 let disposition = if signal == signal::SIGKILL || signal == signal::SIGSTOP {
500 Disposition::Default
501 } else {
502 self.disposition(signal)
503 };
504
505 match disposition {
506 Disposition::Default => {
507 let name = signal::Name::try_from_raw_virtual(signal.as_raw())
508 .unwrap_or(signal::Name::Sys);
509 let process_state_changed = match SignalEffect::of(name) {
510 SignalEffect::None | SignalEffect::Resume => false,
511 SignalEffect::Terminate { core_dump } => {
512 let result = ProcessResult::Signaled { signal, core_dump };
513 self.set_state(ProcessState::Halted(result))
514 }
515 SignalEffect::Suspend => self.set_state(ProcessState::stopped(signal)),
516 };
517 SignalResult {
518 delivered: true,
519 caught: false,
520 process_state_changed,
521 }
522 }
523 Disposition::Ignore => SignalResult {
524 delivered: true,
525 caught: false,
526 process_state_changed: false,
527 },
528 Disposition::Catch => {
529 self.caught_signals.push(signal);
530 self.caught_signals_count += 1;
531 self.signal_wakers.wake_all();
532 SignalResult {
533 delivered: true,
534 caught: true,
535 process_state_changed: false,
536 }
537 }
538 }
539 }
540
541 #[must_use = "send SIGCHLD if process state has changed"]
551 pub fn raise_signal(&mut self, signal: signal::Number) -> SignalResult {
552 let process_state_changed =
553 signal == signal::SIGCONT && self.set_state(ProcessState::Running);
554
555 let mut result = if signal != signal::SIGKILL
556 && signal != signal::SIGSTOP
557 && self.blocked_signals().contains(signal) == Ok(true)
558 {
559 self.pending_signals.insert(signal).ok();
560 SignalResult::default()
561 } else {
562 self.deliver_signal(signal)
563 };
564
565 result.process_state_changed |= process_state_changed;
566 result
567 }
568
569 #[inline(always)]
572 #[must_use]
573 pub fn last_exec(&self) -> &Option<(CString, Vec<CString>, Vec<CString>)> {
574 &self.last_exec
575 }
576}
577
578#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
580#[non_exhaustive]
581pub struct SignalResult {
582 pub delivered: bool,
584
585 pub caught: bool,
587
588 pub process_state_changed: bool,
592}
593
594impl BitOr for SignalResult {
595 type Output = Self;
596 fn bitor(self, rhs: Self) -> Self::Output {
597 Self {
598 delivered: self.delivered | rhs.delivered,
599 caught: self.caught | rhs.caught,
600 process_state_changed: self.process_state_changed | rhs.process_state_changed,
601 }
602 }
603}
604
605impl BitOrAssign for SignalResult {
606 fn bitor_assign(&mut self, rhs: Self) {
607 *self = *self | rhs;
608 }
609}
610
611#[cfg(test)]
612mod tests {
613 use super::*;
614 use crate::system::file_system::Mode;
615 use crate::system::r#virtual::file_body::FileBody;
616 use crate::system::r#virtual::file_system::Inode;
617 use crate::system::r#virtual::io::OpenFileDescription;
618 use crate::test_helper::WakeFlag;
619 use enumset::EnumSet;
620 use futures_util::FutureExt as _;
621 use futures_util::task::LocalSpawnExt as _;
622 use std::cell::RefCell;
623 use std::collections::VecDeque;
624 use std::future::poll_fn;
625 use std::rc::Rc;
626 use std::sync::Arc;
627 use std::task::Poll;
628
629 #[test]
630 fn min_unused_fd_for_various_arguments() {
631 assert_eq!(min_unused_fd(Fd(0), []), Fd(0));
632 assert_eq!(min_unused_fd(Fd(0), [&Fd(1)]), Fd(0));
633 assert_eq!(min_unused_fd(Fd(0), [&Fd(3), &Fd(4)]), Fd(0));
634 assert_eq!(min_unused_fd(Fd(0), [&Fd(0)]), Fd(1));
635 assert_eq!(min_unused_fd(Fd(0), [&Fd(0), &Fd(2)]), Fd(1));
636 assert_eq!(min_unused_fd(Fd(0), [&Fd(0), &Fd(1)]), Fd(2));
637 assert_eq!(min_unused_fd(Fd(0), [&Fd(0), &Fd(1), &Fd(4)]), Fd(2));
638 assert_eq!(min_unused_fd(Fd(0), [&Fd(0), &Fd(1), &Fd(2)]), Fd(3));
639
640 assert_eq!(min_unused_fd(Fd(1), []), Fd(1));
641 assert_eq!(min_unused_fd(Fd(1), [&Fd(1)]), Fd(2));
642 assert_eq!(min_unused_fd(Fd(1), [&Fd(2)]), Fd(1));
643
644 assert_eq!(min_unused_fd(Fd(1), [&Fd(1), &Fd(3), &Fd(4)]), Fd(2));
645 assert_eq!(min_unused_fd(Fd(2), [&Fd(1), &Fd(3), &Fd(4)]), Fd(2));
646 assert_eq!(min_unused_fd(Fd(3), [&Fd(1), &Fd(3), &Fd(4)]), Fd(5));
647 assert_eq!(min_unused_fd(Fd(4), [&Fd(1), &Fd(3), &Fd(4)]), Fd(5));
648 assert_eq!(min_unused_fd(Fd(5), [&Fd(1), &Fd(3), &Fd(4)]), Fd(5));
649 assert_eq!(min_unused_fd(Fd(6), [&Fd(1), &Fd(3), &Fd(4)]), Fd(6));
650 }
651
652 fn process_with_pipe() -> (Process, Fd, Fd) {
653 let mut process = Process::with_parent_and_group(Pid(10), Pid(11));
654
655 let file = Rc::new(RefCell::new(Inode {
656 body: FileBody::Fifo {
657 content: VecDeque::new(),
658 readers: 0,
659 writers: 0,
660 pending_open_wakers: WakerSet::new(),
661 pending_read_wakers: WakerSet::new(),
662 pending_write_wakers: WakerSet::new(),
663 },
664 permissions: Mode::default(),
665 }));
666 let reader = OpenFileDescription::new(
667 Rc::clone(&file),
668 0,
669 true,
670 false,
671 false,
672 false,
673 );
674 let writer = OpenFileDescription::new(
675 Rc::clone(&file),
676 0,
677 false,
678 true,
679 false,
680 false,
681 );
682
683 let reader = FdBody {
684 open_file_description: Rc::new(RefCell::new(reader)),
685 flags: EnumSet::empty(),
686 };
687 let writer = FdBody {
688 open_file_description: Rc::new(RefCell::new(writer)),
689 flags: EnumSet::empty(),
690 };
691
692 let reader = process.open_fd(reader).unwrap();
693 let writer = process.open_fd(writer).unwrap();
694 (process, reader, writer)
695 }
696
697 #[test]
698 fn process_set_state_wakes_on_resumed() {
699 let mut process = Process::with_parent_and_group(Pid(1), Pid(2));
700 process.state = ProcessState::stopped(signal::SIGTSTP);
701 let process = Rc::new(RefCell::new(process));
702 let process2 = Rc::clone(&process);
703 let waker = Rc::new(Cell::new(None));
704 let task = poll_fn(move |cx| {
705 let mut process = process2.borrow_mut();
706 if process.state() == ProcessState::Running {
707 return Poll::Ready(());
708 }
709 waker.set(Some(cx.waker().clone()));
710 process.wake_on_resumption(Rc::downgrade(&waker));
711 Poll::Pending
712 });
713
714 let mut executor = futures_executor::LocalPool::new();
715 let mut handle = executor.spawner().spawn_local_with_handle(task).unwrap();
716 executor.run_until_stalled();
717 assert_eq!((&mut handle).now_or_never(), None);
718
719 _ = process.borrow_mut().set_state(ProcessState::Running);
720 assert!(executor.try_run_one());
721 assert_eq!(handle.now_or_never(), Some(()));
722 }
723
724 #[test]
725 fn process_set_state_closes_all_fds_on_exit() {
726 let (mut process, _reader, _writer) = process_with_pipe();
727 assert!(process.set_state(ProcessState::exited(3)));
728 assert!(process.fds().is_empty(), "{:?}", process.fds());
729 }
730
731 #[test]
732 fn process_set_state_closes_all_fds_on_signaled() {
733 let (mut process, _reader, _writer) = process_with_pipe();
734 assert!(
735 process.set_state(ProcessState::Halted(ProcessResult::Signaled {
736 signal: signal::SIGINT,
737 core_dump: false
738 }))
739 );
740 assert!(process.fds().is_empty(), "{:?}", process.fds());
741 }
742
743 #[test]
744 fn process_default_signal_blocking_mask() {
745 let process = Process::with_parent_and_group(Pid(10), Pid(11));
746 let initial_set = process.blocked_signals();
747 assert!(initial_set.is_empty(), "{initial_set:?}");
748 }
749
750 #[test]
751 fn process_sigmask_setmask() {
752 let mut process = Process::with_parent_and_group(Pid(10), Pid(11));
753 let result = process.block_signals(SigmaskOp::Set, [signal::SIGINT, signal::SIGCHLD]);
754 assert_eq!(result, SignalResult::default());
755
756 let result_set = process.blocked_signals();
757 assert_eq!(result_set.contains(signal::SIGINT), Ok(true));
758 assert_eq!(result_set.contains(signal::SIGCHLD), Ok(true));
759 assert_eq!(result_set.len(), 2);
760
761 let result = process.block_signals(SigmaskOp::Set, [signal::SIGINT, signal::SIGQUIT]);
762 assert_eq!(result, SignalResult::default());
763
764 let result_set = process.blocked_signals();
765 assert_eq!(result_set.contains(signal::SIGINT), Ok(true));
766 assert_eq!(result_set.contains(signal::SIGQUIT), Ok(true));
767 assert_eq!(result_set.len(), 2);
768 }
769
770 #[test]
771 fn process_sigmask_block() {
772 let mut process = Process::with_parent_and_group(Pid(10), Pid(11));
773 let result = process.block_signals(SigmaskOp::Add, [signal::SIGINT, signal::SIGCHLD]);
774 assert_eq!(result, SignalResult::default());
775
776 let result_set = process.blocked_signals();
777 assert_eq!(result_set.contains(signal::SIGINT), Ok(true));
778 assert_eq!(result_set.contains(signal::SIGCHLD), Ok(true));
779 assert_eq!(result_set.len(), 2);
780
781 let result = process.block_signals(SigmaskOp::Add, [signal::SIGINT, signal::SIGQUIT]);
782 assert_eq!(result, SignalResult::default());
783
784 let result_set = process.blocked_signals();
785 assert_eq!(result_set.contains(signal::SIGINT), Ok(true));
786 assert_eq!(result_set.contains(signal::SIGQUIT), Ok(true));
787 assert_eq!(result_set.contains(signal::SIGCHLD), Ok(true));
788 assert_eq!(result_set.len(), 3);
789 }
790
791 #[test]
792 fn process_sigmask_unblock() {
793 let mut process = Process::with_parent_and_group(Pid(10), Pid(11));
794 let result = process.block_signals(SigmaskOp::Add, [signal::SIGINT, signal::SIGCHLD]);
795 assert_eq!(result, SignalResult::default());
796
797 let result = process.block_signals(SigmaskOp::Remove, [signal::SIGINT, signal::SIGQUIT]);
798 assert_eq!(result, SignalResult::default());
799
800 let result_set = process.blocked_signals();
801 assert_eq!(result_set.contains(signal::SIGCHLD), Ok(true));
802 assert_eq!(result_set.len(), 1);
803 }
804
805 #[test]
806 fn process_set_disposition() {
807 let mut process = Process::with_parent_and_group(Pid(100), Pid(11));
808 let old_disposition = process.set_disposition(signal::SIGINT, Disposition::Ignore);
809 assert_eq!(old_disposition, Disposition::Default);
810 let old_disposition = process.set_disposition(signal::SIGTERM, Disposition::Catch);
811 assert_eq!(old_disposition, Disposition::Default);
812
813 let old_disposition = process.set_disposition(signal::SIGINT, Disposition::Default);
814 assert_eq!(old_disposition, Disposition::Ignore);
815 let old_disposition = process.set_disposition(signal::SIGTERM, Disposition::Ignore);
816 assert_eq!(old_disposition, Disposition::Catch);
817
818 let disposition = process.disposition(signal::SIGINT);
819 assert_eq!(disposition, Disposition::Default);
820 let disposition = process.disposition(signal::SIGTERM);
821 assert_eq!(disposition, Disposition::Ignore);
822 let disposition = process.disposition(signal::SIGQUIT);
823 assert_eq!(disposition, Disposition::Default);
824 }
825
826 #[test]
827 fn process_raise_signal_default_nop() {
828 let mut process = Process::with_parent_and_group(Pid(42), Pid(11));
829 let result = process.raise_signal(signal::SIGCHLD);
830 assert_eq!(
831 result,
832 SignalResult {
833 delivered: true,
834 caught: false,
835 process_state_changed: false,
836 }
837 );
838 assert_eq!(process.state(), ProcessState::Running);
839 }
840
841 #[test]
842 fn process_raise_signal_default_terminating() {
843 let mut process = Process::with_parent_and_group(Pid(42), Pid(11));
844 let result = process.raise_signal(signal::SIGTERM);
845 assert_eq!(
846 result,
847 SignalResult {
848 delivered: true,
849 caught: false,
850 process_state_changed: true,
851 }
852 );
853 assert_eq!(
854 process.state(),
855 ProcessState::Halted(ProcessResult::Signaled {
856 signal: signal::SIGTERM,
857 core_dump: false
858 })
859 );
860 assert_eq!(process.caught_signals, []);
861 }
862
863 #[test]
864 fn process_raise_signal_default_aborting() {
865 let mut process = Process::with_parent_and_group(Pid(42), Pid(11));
866 let result = process.raise_signal(signal::SIGABRT);
867 assert_eq!(
868 result,
869 SignalResult {
870 delivered: true,
871 caught: false,
872 process_state_changed: true,
873 }
874 );
875 assert_eq!(
876 process.state(),
877 ProcessState::Halted(ProcessResult::Signaled {
878 signal: signal::SIGABRT,
879 core_dump: true
880 })
881 );
882 assert_eq!(process.caught_signals, []);
883 }
885
886 #[test]
887 fn process_raise_signal_default_stopping() {
888 let mut process = Process::with_parent_and_group(Pid(42), Pid(11));
889 let result = process.raise_signal(signal::SIGTSTP);
890 assert_eq!(
891 result,
892 SignalResult {
893 delivered: true,
894 caught: false,
895 process_state_changed: true,
896 }
897 );
898 assert_eq!(process.state(), ProcessState::stopped(signal::SIGTSTP));
899 assert_eq!(process.caught_signals, []);
900 }
901
902 #[test]
903 fn process_raise_signal_default_continuing() {
904 let mut process = Process::with_parent_and_group(Pid(42), Pid(11));
905 let _ = process.set_state(ProcessState::stopped(signal::SIGTTOU));
906 let result = process.raise_signal(signal::SIGCONT);
907 assert_eq!(
908 result,
909 SignalResult {
910 delivered: true,
911 caught: false,
912 process_state_changed: true,
913 }
914 );
915 assert_eq!(process.state(), ProcessState::Running);
916 assert_eq!(process.caught_signals, []);
917 }
918
919 #[test]
920 fn process_raise_signal_ignored() {
921 let mut process = Process::with_parent_and_group(Pid(42), Pid(11));
922 process.set_disposition(signal::SIGCHLD, Disposition::Ignore);
923 let result = process.raise_signal(signal::SIGCHLD);
924 assert_eq!(
925 result,
926 SignalResult {
927 delivered: true,
928 caught: false,
929 process_state_changed: false,
930 }
931 );
932 assert_eq!(process.state(), ProcessState::Running);
933 assert_eq!(process.caught_signals, []);
934 }
935
936 #[test]
937 fn process_raise_signal_ignored_and_blocked_sigcont() {
938 let mut process = Process::with_parent_and_group(Pid(42), Pid(11));
939 let _ = process.set_state(ProcessState::stopped(signal::SIGTTOU));
940 let _ = process.set_disposition(signal::SIGCONT, Disposition::Ignore);
941 let _ = process.block_signals(SigmaskOp::Add, [signal::SIGCONT]);
942 let result = process.raise_signal(signal::SIGCONT);
943 assert_eq!(
944 result,
945 SignalResult {
946 delivered: false,
947 caught: false,
948 process_state_changed: true,
949 }
950 );
951 assert_eq!(process.state(), ProcessState::Running);
952 assert_eq!(process.caught_signals, []);
953 assert_eq!(process.pending_signals.contains(signal::SIGCONT), Ok(true));
954 }
955
956 #[test]
957 fn process_raise_signal_caught() {
958 let mut process = Process::with_parent_and_group(Pid(42), Pid(11));
959 process.set_disposition(signal::SIGCHLD, Disposition::Catch);
960 let wake_flag = Arc::new(WakeFlag::new());
961 let waker = Rc::new(Cell::new(Some(Waker::from(wake_flag.clone()))));
962 process.register_signal_waker(Rc::downgrade(&waker));
963
964 let result = process.raise_signal(signal::SIGCHLD);
965 assert_eq!(
966 result,
967 SignalResult {
968 delivered: true,
969 caught: true,
970 process_state_changed: false,
971 }
972 );
973 assert_eq!(process.state(), ProcessState::Running);
974 assert_eq!(process.caught_signals, [signal::SIGCHLD]);
975 assert!(wake_flag.is_woken());
976 }
977
978 #[test]
979 fn process_raise_signal_blocked() {
980 let mut process = Process::with_parent_and_group(Pid(42), Pid(11));
981 process.set_disposition(signal::SIGCHLD, Disposition::Catch);
982 let result = process.block_signals(SigmaskOp::Add, [signal::SIGCHLD]);
983 assert_eq!(
984 result,
985 SignalResult {
986 delivered: false,
987 caught: false,
988 process_state_changed: false,
989 }
990 );
991
992 let result = process.raise_signal(signal::SIGCHLD);
993 assert_eq!(
994 result,
995 SignalResult {
996 delivered: false,
997 caught: false,
998 process_state_changed: false,
999 }
1000 );
1001 assert_eq!(process.state(), ProcessState::Running);
1002 assert_eq!(process.caught_signals, []);
1003
1004 let result = process.block_signals(SigmaskOp::Set, []);
1005 assert_eq!(
1006 result,
1007 SignalResult {
1008 delivered: true,
1009 caught: true,
1010 process_state_changed: false,
1011 }
1012 );
1013 assert_eq!(process.state(), ProcessState::Running);
1014 assert_eq!(process.caught_signals, [signal::SIGCHLD]);
1015 }
1016}