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