1use crate::device::terminal::{Terminal, TerminalController};
6use crate::mutable_state::{state_accessor, state_implementation};
7use crate::ptrace::{
8 AtomicStopState, PtraceAllowedPtracers, PtraceEvent, PtraceOptions, PtraceStatus, StopState,
9 ZombiePtracees, ptrace_detach,
10};
11use crate::security;
12use crate::signals::syscalls::WaitingOptions;
13use crate::signals::{
14 DeliveryAction, IntoSignalInfoOptions, QueuedSignals, SignalActions, SignalDetail, SignalInfo,
15 UncheckedSignalInfo, action_for_signal, send_standard_signal,
16};
17use crate::task::memory_attribution::MemoryAttributionLifecycleEvent;
18use crate::task::{
19 ControllingTerminal, CurrentTask, ExitStatus, Kernel, PidTable, ProcessGroup, Session,
20 SessionDisassociation, Task, TaskMutableState, TaskPersistentInfo, TypedWaitQueue,
21};
22use crate::time::{IntervalTimerHandle, TimerTable};
23use itertools::Itertools;
24use macro_rules_attribute::apply;
25use starnix_lifecycle::{AtomicCounter, DropNotifier};
26use starnix_logging::{log_debug, log_error, log_info, log_warn, track_stub};
27use starnix_sync::{
28 LockBefore, LockDepMutex, LockDepRwLock, Locked, OrderedMutex, ProcessGroupState,
29 RwLockWriteGuard, ThreadGroupLimits, ThreadGroupMutableStateLock,
30 ThreadGroupPendingSignalsLock, ThreadGroupPtraceesLock, Unlocked, allow_subclass,
31 ordered_write_lock,
32};
33use starnix_task_command::TaskCommand;
34use starnix_types::ownership::{OwnedRef, Releasable};
35use starnix_types::stats::TaskTimeStats;
36use starnix_types::time::{itimerspec_from_itimerval, timeval_from_duration};
37use starnix_uapi::arc_key::WeakKey;
38use starnix_uapi::auth::{CAP_SYS_ADMIN, CAP_SYS_RESOURCE, Credentials};
39use starnix_uapi::errors::Errno;
40use starnix_uapi::personality::PersonalityFlags;
41use starnix_uapi::resource_limits::{Resource, ResourceLimits};
42use starnix_uapi::signals::{
43 SIGCHLD, SIGCONT, SIGHUP, SIGKILL, SIGTERM, SIGTTOU, SigSet, Signal, UncheckedSignal,
44};
45use starnix_uapi::user_address::UserAddress;
46use starnix_uapi::{
47 ITIMER_PROF, ITIMER_REAL, ITIMER_VIRTUAL, SI_TKILL, SI_USER, SIG_IGN, errno, error, itimerval,
48 pid_t, rlimit, tid_t, uid_t,
49};
50use std::collections::BTreeMap;
51use std::fmt;
52use std::sync::atomic::{AtomicBool, Ordering};
53use std::sync::{Arc, OnceLock, Weak};
54use zx::{Koid, Status};
55
56#[derive(Debug)]
57pub struct ZirconProcess {
58 process: zx::Process,
59 koid: Result<Koid, Status>,
60}
61
62impl ZirconProcess {
63 pub fn new(process: zx::Process) -> Self {
64 let koid = process.koid();
65 Self { process, koid }
66 }
67
68 pub fn koid(&self) -> Result<Koid, Status> {
69 self.koid
70 }
71}
72
73impl std::ops::Deref for ZirconProcess {
74 type Target = zx::Process;
75 fn deref(&self) -> &Self::Target {
76 &self.process
77 }
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
82pub struct ThreadGroupKey {
83 pid: pid_t,
84 thread_group: WeakKey<ThreadGroup>,
85}
86
87impl ThreadGroupKey {
88 pub fn pid(&self) -> pid_t {
93 self.pid
94 }
95}
96
97impl std::ops::Deref for ThreadGroupKey {
98 type Target = Weak<ThreadGroup>;
99 fn deref(&self) -> &Self::Target {
100 &self.thread_group.0
101 }
102}
103
104impl From<&ThreadGroup> for ThreadGroupKey {
105 fn from(tg: &ThreadGroup) -> Self {
106 Self { pid: tg.leader, thread_group: WeakKey::from(&tg.weak_self.upgrade().unwrap()) }
107 }
108}
109
110impl<T: AsRef<ThreadGroup>> From<T> for ThreadGroupKey {
111 fn from(tg: T) -> Self {
112 tg.as_ref().into()
113 }
114}
115
116#[repr(u64)]
118pub enum ThreadGroupLifecycleWaitValue {
119 ChildStatus,
121 Stopped,
123}
124
125impl Into<u64> for ThreadGroupLifecycleWaitValue {
126 fn into(self) -> u64 {
127 self as u64
128 }
129}
130
131#[derive(Clone, Debug)]
134pub struct DeferredZombiePTracer {
135 pub tracer_thread_group_key: ThreadGroupKey,
137 pub tracee_tid: tid_t,
139 pub tracee_pgid: pid_t,
141 pub tracee_thread_group_key: ThreadGroupKey,
143}
144
145impl DeferredZombiePTracer {
146 fn new(tracer: &ThreadGroup, tracee: &Task, tracee_pgid: pid_t) -> Self {
147 Self {
148 tracer_thread_group_key: tracer.into(),
149 tracee_tid: tracee.tid,
150 tracee_pgid,
151 tracee_thread_group_key: tracee.thread_group_key.clone(),
152 }
153 }
154}
155
156pub struct ThreadGroupMutableState {
158 pub parent: Option<ThreadGroupParent>,
163
164 pub exit_signal: Option<Signal>,
166
167 tasks: BTreeMap<tid_t, TaskContainer>,
174
175 pub children: BTreeMap<pid_t, Weak<ThreadGroup>>,
182
183 pub zombie_children: Vec<OwnedRef<ZombieProcess>>,
185
186 pub zombie_ptracees: ZombiePtracees,
188
189 pub deferred_zombie_ptracers: Vec<DeferredZombiePTracer>,
192
193 pub lifecycle_waiters: TypedWaitQueue<ThreadGroupLifecycleWaitValue>,
195
196 pub is_child_subreaper: bool,
199
200 pub process_group: Arc<ProcessGroup>,
202
203 pub did_exec: bool,
204
205 pub last_signal: Option<SignalInfo>,
209
210 run_state: ThreadGroupRunState,
214
215 pub children_time_stats: TaskTimeStats,
217
218 pub personality: PersonalityFlags,
220
221 pub allowed_ptracers: PtraceAllowedPtracers,
223
224 exit_notifier: Option<futures::channel::oneshot::Sender<()>>,
226
227 pub notifier: Option<std::sync::mpsc::Sender<MemoryAttributionLifecycleEvent>>,
229}
230
231pub struct ThreadGroup {
255 pub weak_self: Weak<ThreadGroup>,
258
259 pub kernel: Arc<Kernel>,
261
262 pub process: ZirconProcess,
271
272 pub root_vmar: zx::Vmar,
274
275 pub leader: pid_t,
279
280 pub leader_task: OnceLock<Weak<Task>>,
287
288 pub signal_actions: Arc<SignalActions>,
290
291 pub timers: TimerTable,
293
294 pub drop_notifier: DropNotifier,
296
297 stop_state: AtomicStopState,
301
302 mutable_state: LockDepRwLock<ThreadGroupMutableState, ThreadGroupMutableStateLock>,
304
305 pub limits: OrderedMutex<ResourceLimits, ThreadGroupLimits>,
309
310 pub next_seccomp_filter_id: AtomicCounter<u64>,
315
316 pub ptracees: LockDepMutex<BTreeMap<tid_t, TaskContainer>, ThreadGroupPtraceesLock>,
318
319 pub pending_signals: LockDepMutex<QueuedSignals, ThreadGroupPendingSignalsLock>,
321
322 pub has_pending_signals: AtomicBool,
325
326 pub start_time: zx::MonotonicInstant,
328
329 log_syscalls_as_info: AtomicBool,
331}
332
333impl fmt::Debug for ThreadGroup {
334 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335 write!(
336 f,
337 "{}({})",
338 self.process.get_name().unwrap_or(zx::Name::new_lossy("<unknown>")),
339 self.leader
340 )
341 }
342}
343
344impl ThreadGroup {
345 pub fn sync_syscall_log_level(&self) {
346 let command = self.read().leader_command();
347 let filters = self.kernel.syscall_log_filters.lock();
348 let should_log = filters.iter().any(|f| f.matches(&command));
349 let prev_should_log = self.log_syscalls_as_info.swap(should_log, Ordering::Relaxed);
350 let change_str = match (should_log, prev_should_log) {
351 (true, false) => Some("Enabled"),
352 (false, true) => Some("Disabled"),
353 _ => None,
354 };
355 if let Some(change_str) = change_str {
356 log_info!(
357 "{change_str} info syscall logs for thread group {} (command: {command})",
358 self.leader
359 );
360 }
361 }
362
363 #[inline]
364 pub fn syscall_log_level(&self) -> starnix_logging::Level {
365 if self.log_syscalls_as_info.load(Ordering::Relaxed) {
366 starnix_logging::Level::Info
367 } else {
368 starnix_logging::Level::Trace
369 }
370 }
371}
372
373impl PartialEq for ThreadGroup {
374 fn eq(&self, other: &Self) -> bool {
375 self.leader == other.leader
376 }
377}
378
379impl Drop for ThreadGroup {
380 fn drop(&mut self) {
381 let state = self.mutable_state.get_mut();
382 assert!(state.tasks.is_empty());
383 assert!(state.children.is_empty());
384 assert!(state.zombie_children.is_empty());
385 assert!(state.zombie_ptracees.is_empty());
386 #[cfg(any(test, debug_assertions))]
387 assert!(
388 state
389 .parent
390 .as_ref()
391 .and_then(|p| p.0.upgrade().as_ref().map(|p| p
392 .read()
393 .children
394 .get(&self.leader)
395 .is_none()))
396 .unwrap_or(true)
397 );
398 }
399}
400
401pub struct ThreadGroupParent(Weak<ThreadGroup>);
404
405impl ThreadGroupParent {
406 pub fn new(t: Weak<ThreadGroup>) -> Self {
407 debug_assert!(t.upgrade().is_some());
408 Self(t)
409 }
410
411 pub fn upgrade(&self) -> Arc<ThreadGroup> {
412 self.0.upgrade().expect("ThreadGroupParent references must always be valid")
413 }
414}
415
416impl Clone for ThreadGroupParent {
417 fn clone(&self) -> Self {
418 Self(self.0.clone())
419 }
420}
421
422#[derive(Debug, Clone)]
425pub enum ProcessSelector {
426 Any,
428 Pid(pid_t),
430 Pgid(pid_t),
432 Process(ThreadGroupKey),
434}
435
436impl ProcessSelector {
437 pub fn match_tid(&self, tid: tid_t, pid_table: &PidTable) -> bool {
438 match *self {
439 ProcessSelector::Pid(p) => {
440 if p == tid {
441 true
442 } else {
443 if let Ok(task_ref) = pid_table.get_task(tid) {
444 task_ref.get_pid() == p
445 } else {
446 false
447 }
448 }
449 }
450 ProcessSelector::Any => true,
451 ProcessSelector::Pgid(pgid) => {
452 if let Ok(task_ref) = pid_table.get_task(tid) {
453 pid_table.get_process_group(pgid).as_ref()
454 == Some(&task_ref.thread_group().read().process_group)
455 } else {
456 false
457 }
458 }
459 ProcessSelector::Process(ref key) => {
460 if let Some(tg) = key.upgrade() {
461 tg.read().tasks.contains_key(&tid)
462 } else {
463 false
464 }
465 }
466 }
467 }
468}
469
470#[derive(Clone, Debug, PartialEq, Eq)]
471pub struct ProcessExitInfo {
472 pub status: ExitStatus,
473 pub exit_signal: Option<Signal>,
474}
475
476#[derive(Clone, Debug, Default, PartialEq, Eq)]
477enum ThreadGroupRunState {
478 #[default]
479 Running,
480 Exiting(ExitStatus),
481 Exited(ExitStatus),
482}
483
484#[derive(Clone, Debug, PartialEq, Eq)]
485pub struct WaitResult {
486 pub pid: pid_t,
487 pub uid: uid_t,
488
489 pub exit_info: ProcessExitInfo,
490
491 pub time_stats: TaskTimeStats,
493}
494
495impl WaitResult {
496 pub fn as_signal_info(&self) -> SignalInfo {
498 SignalInfo::with_detail(
499 SIGCHLD,
500 self.exit_info.status.signal_info_code(),
501 SignalDetail::SIGCHLD {
502 pid: self.pid,
503 uid: self.uid,
504 status: self.exit_info.status.signal_info_status(),
505 },
506 )
507 }
508}
509
510#[derive(Debug)]
511pub struct ZombieProcess {
512 pub thread_group_key: ThreadGroupKey,
513 pub pgid: pid_t,
514 pub uid: uid_t,
515
516 pub exit_info: ProcessExitInfo,
517
518 pub time_stats: TaskTimeStats,
520
521 pub is_canonical: bool,
524}
525
526impl PartialEq for ZombieProcess {
527 fn eq(&self, other: &Self) -> bool {
528 self.thread_group_key == other.thread_group_key
530 && self.pgid == other.pgid
531 && self.uid == other.uid
532 && self.is_canonical == other.is_canonical
533 }
534}
535
536impl Eq for ZombieProcess {}
537
538impl PartialOrd for ZombieProcess {
539 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
540 Some(self.cmp(other))
541 }
542}
543
544impl Ord for ZombieProcess {
545 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
546 self.thread_group_key.cmp(&other.thread_group_key)
547 }
548}
549
550impl ZombieProcess {
551 pub fn new(
552 thread_group: ThreadGroupStateRef<'_>,
553 credentials: &Credentials,
554 exit_info: ProcessExitInfo,
555 ) -> OwnedRef<Self> {
556 let time_stats = thread_group.base.time_stats() + thread_group.children_time_stats;
557 OwnedRef::new(ZombieProcess {
558 thread_group_key: thread_group.base.into(),
559 pgid: thread_group.process_group.leader,
560 uid: credentials.uid,
561 exit_info,
562 time_stats,
563 is_canonical: true,
564 })
565 }
566
567 pub fn pid(&self) -> pid_t {
568 self.thread_group_key.pid()
569 }
570
571 pub fn to_wait_result(&self) -> WaitResult {
572 WaitResult {
573 pid: self.pid(),
574 uid: self.uid,
575 exit_info: self.exit_info.clone(),
576 time_stats: self.time_stats,
577 }
578 }
579
580 pub fn as_artificial(&self) -> Self {
581 ZombieProcess {
582 thread_group_key: self.thread_group_key.clone(),
583 pgid: self.pgid,
584 uid: self.uid,
585 exit_info: self.exit_info.clone(),
586 time_stats: self.time_stats,
587 is_canonical: false,
588 }
589 }
590
591 pub fn matches_selector(&self, selector: &ProcessSelector) -> bool {
592 match *selector {
593 ProcessSelector::Any => true,
594 ProcessSelector::Pid(pid) => self.pid() == pid,
595 ProcessSelector::Pgid(pgid) => self.pgid == pgid,
596 ProcessSelector::Process(ref key) => self.thread_group_key == *key,
597 }
598 }
599
600 pub fn matches_selector_and_waiting_option(
601 &self,
602 selector: &ProcessSelector,
603 options: &WaitingOptions,
604 ) -> bool {
605 if !self.matches_selector(selector) {
606 return false;
607 }
608
609 if options.wait_for_all {
610 true
611 } else {
612 options.wait_for_clone == (self.exit_info.exit_signal != Some(SIGCHLD))
615 }
616 }
617}
618
619impl Releasable for ZombieProcess {
620 type Context<'a> = &'a mut PidTable;
621
622 fn release<'a>(self, pids: &'a mut PidTable) {
623 if self.is_canonical {
624 pids.remove_zombie(self.pid());
625 }
626 }
627}
628
629pub struct ZombieNotification {
647 pub recipient: Weak<ThreadGroup>,
649
650 pub zombie: OwnedRef<ZombieProcess>,
652}
653
654impl ZombieNotification {
655 pub fn new(recipient: Weak<ThreadGroup>, zombie: OwnedRef<ZombieProcess>) -> Self {
656 Self { recipient, zombie }
657 }
658
659 pub fn deliver(self, pids: &mut PidTable) {
665 if let Some(parent) = self.recipient.upgrade() {
666 parent.do_zombie_notifications(self.zombie);
667 } else {
668 log_warn!("Zombie {} reaped silently", self.zombie.pid());
669 self.zombie.release(pids);
670 }
671 }
672}
673
674impl ThreadGroup {
675 pub fn new<L>(
677 locked: &mut Locked<L>,
678 kernel: Arc<Kernel>,
679 process: zx::Process,
680 root_vmar: zx::Vmar,
681 parent: Option<ThreadGroupWriteGuard<'_>>,
682 leader: pid_t,
683 exit_signal: Option<Signal>,
684 process_group: Arc<ProcessGroup>,
685 signal_actions: Arc<SignalActions>,
686 ) -> Arc<ThreadGroup>
687 where
688 L: LockBefore<ProcessGroupState>,
689 {
690 debug_assert!(!process.is_invalid());
691 debug_assert!(!root_vmar.is_invalid());
692 Self::new_internal(
693 locked,
694 kernel,
695 process,
696 root_vmar,
697 parent,
698 leader,
699 exit_signal,
700 process_group,
701 signal_actions,
702 )
703 }
704
705 pub fn for_system<L>(
707 locked: &mut Locked<L>,
708 kernel: Arc<Kernel>,
709 leader: pid_t,
710 process_group: Arc<ProcessGroup>,
711 ) -> Arc<ThreadGroup>
712 where
713 L: LockBefore<ProcessGroupState>,
714 {
715 Self::new_internal(
716 locked,
717 kernel,
718 zx::Process::invalid(),
719 zx::Vmar::invalid(),
720 None,
721 leader,
722 Some(SIGCHLD),
723 process_group,
724 SignalActions::default(),
725 )
726 }
727
728 pub fn for_test<L>(
736 locked: &mut Locked<L>,
737 kernel: Arc<Kernel>,
738 process: zx::Process,
739 parent: ThreadGroupWriteGuard<'_>,
740 leader: pid_t,
741 process_group: Arc<ProcessGroup>,
742 ) -> Arc<ThreadGroup>
743 where
744 L: LockBefore<ProcessGroupState>,
745 {
746 Self::new_internal(
747 locked,
748 kernel,
749 process,
750 zx::Vmar::invalid(),
751 Some(parent),
752 leader,
753 Some(SIGCHLD),
754 process_group,
755 SignalActions::default(),
756 )
757 }
758
759 fn new_internal<L>(
760 locked: &mut Locked<L>,
761 kernel: Arc<Kernel>,
762 process: zx::Process,
763 root_vmar: zx::Vmar,
764 parent: Option<ThreadGroupWriteGuard<'_>>,
765 leader: pid_t,
766 exit_signal: Option<Signal>,
767 process_group: Arc<ProcessGroup>,
768 signal_actions: Arc<SignalActions>,
769 ) -> Arc<ThreadGroup>
770 where
771 L: LockBefore<ProcessGroupState>,
772 {
773 Arc::new_cyclic(|weak_self| {
774 let process = ZirconProcess::new(process);
775 let mut thread_group = ThreadGroup {
776 weak_self: weak_self.clone(),
777 kernel,
778 process,
779 root_vmar,
780 leader,
781 leader_task: OnceLock::new(),
782 signal_actions,
783 timers: Default::default(),
784 drop_notifier: Default::default(),
785 limits: OrderedMutex::new(
788 parent
789 .as_ref()
790 .map(|p| p.base.limits.lock(locked.cast_locked()).clone())
791 .unwrap_or(Default::default()),
792 ),
793 next_seccomp_filter_id: Default::default(),
794 ptracees: Default::default(),
795 stop_state: AtomicStopState::new(StopState::Awake),
796 pending_signals: Default::default(),
797 has_pending_signals: Default::default(),
798 start_time: zx::MonotonicInstant::get(),
799 mutable_state: ThreadGroupMutableState {
800 parent: parent
801 .as_ref()
802 .map(|p| ThreadGroupParent::new(p.base.weak_self.clone())),
803 exit_signal,
804 tasks: BTreeMap::new(),
805 children: BTreeMap::new(),
806 zombie_children: vec![],
807 zombie_ptracees: ZombiePtracees::new(),
808 deferred_zombie_ptracers: vec![],
809 lifecycle_waiters: TypedWaitQueue::<ThreadGroupLifecycleWaitValue>::default(),
810 is_child_subreaper: false,
811 process_group: Arc::clone(&process_group),
812 did_exec: false,
813 last_signal: None,
814 run_state: Default::default(),
815 children_time_stats: Default::default(),
816 personality: parent
817 .as_ref()
818 .map(|p| p.personality)
819 .unwrap_or(Default::default()),
820 allowed_ptracers: PtraceAllowedPtracers::None,
821 exit_notifier: None,
822 notifier: None,
823 }
824 .into(),
825 log_syscalls_as_info: AtomicBool::new(false),
826 };
827
828 if let Some(mut parent) = parent {
829 thread_group.next_seccomp_filter_id.reset(parent.base.next_seccomp_filter_id.get());
830 parent.children.insert(leader, weak_self.clone());
831 process_group.insert(locked, &thread_group);
832 };
833 thread_group
834 })
835 }
836
837 state_accessor!(ThreadGroup, mutable_state);
838
839 pub fn load_stopped(&self) -> StopState {
840 self.stop_state.load(Ordering::Relaxed)
841 }
842
843 pub fn kill(
852 &self,
853 locked: &mut Locked<Unlocked>,
854 exit_status: ExitStatus,
855 mut current_task: Option<&mut CurrentTask>,
856 ) {
857 if let Some(ref mut current_task) = current_task {
858 current_task.ptrace_event(
859 locked,
860 PtraceOptions::TRACEEXIT,
861 exit_status.signal_info_status() as u64,
862 );
863 }
864 let mut pids = self.kernel.pids.write();
865 let mut state = self.write();
866 if !state.is_running() {
867 return;
868 }
869
870 state.run_state = ThreadGroupRunState::Exiting(exit_status.clone());
871
872 let zombie_notifications = state.zombie_ptracees.detach_all(&mut pids);
874
875 let tasks = state.tasks();
878 drop(state);
879
880 for notification in zombie_notifications {
881 notification.deliver(&mut pids);
882 }
883 self.detach_ptracees(locked, &mut pids);
884
885 for task in tasks {
886 task.write().set_exit_status(exit_status.clone());
887 send_standard_signal(locked, &task, SignalInfo::kernel(SIGKILL));
888 }
889 }
890
891 pub fn add(&self, task: Arc<Task>) -> Result<(), Errno> {
892 let mut state = self.write();
893 if !state.is_running() {
894 if state.tasks_count() == 0 {
895 log_warn!(
896 "Task {} with leader {} not running while adding its first task, \
897 not sending creation notification",
898 task.tid,
899 self.leader
900 );
901 }
902 return error!(EINVAL);
903 }
904 if task.tid == self.leader {
905 let _ = self.leader_task.set(Arc::downgrade(&task));
906 }
907 state.tasks.insert(task.tid, (&task).into());
908
909 Ok(())
910 }
911
912 pub fn remove<L>(
917 &self,
918 locked: &mut Locked<L>,
919 mut pids: RwLockWriteGuard<'_, PidTable>,
920 task: &Arc<Task>,
921 ) where
922 L: LockBefore<ProcessGroupState> + LockBefore<ThreadGroupLimits>,
923 {
924 task.set_ptrace_zombie(&mut pids);
925 pids.remove_task(task.tid);
926
927 let mut state = self.write();
928
929 let persistent_info: TaskPersistentInfo =
930 if let Some(container) = state.tasks.remove(&task.tid) {
931 container.into()
932 } else {
933 debug_assert!(!state.is_running());
936 return;
937 };
938
939 if state.tasks.is_empty() {
940 let exit_status = if let ThreadGroupRunState::Exiting(exit_status) = &state.run_state {
941 exit_status.clone()
942 } else {
943 let exit_status = task.exit_status().unwrap_or_else(|| {
944 log_error!("Exiting without an exit code.");
945 ExitStatus::Exit(u8::MAX)
946 });
947 state.set_exiting(exit_status.clone());
948 exit_status
949 };
950
951 let zombie_notifications = state.zombie_ptracees.detach_all(&mut pids);
953
954 let exit_info =
956 ProcessExitInfo { status: exit_status, exit_signal: state.exit_signal.clone() };
957 let zombie =
958 ZombieProcess::new(state.as_ref(), &persistent_info.real_creds(), exit_info);
959 pids.kill_process(self.leader, OwnedRef::downgrade(&zombie));
960
961 let session = state.leave_process_group(locked, &pids);
962
963 std::mem::drop(state);
973
974 session.disassociate_controlling_terminal(locked);
977
978 for notification in zombie_notifications {
979 notification.deliver(&mut pids);
980 }
981
982 self.kernel.cgroups.lock_cgroup2_pid_table().remove_process(self.into());
986
987 self.detach_ptracees(locked, &mut pids);
988
989 let parent = self.read().parent.clone();
992 let reaper = self.find_reaper();
993
994 {
995 if let Some(reaper) = reaper {
997 let reaper = reaper.upgrade();
998 {
999 let mut reaper_state = reaper.write();
1000 let _token = allow_subclass();
1004 let mut state = self.write();
1005 for (_pid, weak_child) in std::mem::take(&mut state.children) {
1006 if let Some(child) = weak_child.upgrade() {
1007 let _token = allow_subclass();
1012 let mut child_state = child.write();
1013
1014 child_state.exit_signal = Some(SIGCHLD);
1015 child_state.parent =
1016 Some(ThreadGroupParent::new(Arc::downgrade(&reaper)));
1017 reaper_state.children.insert(child.leader, weak_child.clone());
1018 }
1019 }
1020 reaper_state.zombie_children.append(&mut state.zombie_children);
1021 }
1022 ZombiePtracees::reparent(self, &reaper);
1023 } else {
1024 let mut state = self.write();
1026 for zombie in state.zombie_children.drain(..) {
1027 zombie.release(&mut pids);
1028 }
1029 }
1030 }
1031
1032 self.write().parent = None;
1034
1035 #[cfg(any(test, debug_assertions))]
1036 {
1037 let state = self.read();
1038 assert!(state.zombie_children.is_empty());
1039 assert!(state.zombie_ptracees.is_empty());
1040 }
1041
1042 if let Some(ref parent) = parent {
1043 let parent = parent.upgrade();
1044
1045 let tracer_tg = task
1046 .read()
1047 .ptrace
1048 .as_ref()
1049 .and_then(|ptrace| ptrace.core_state.thread_group.upgrade());
1050
1051 let maybe_zombie = match tracer_tg {
1052 Some(tracer_tg) => {
1053 tracer_tg.maybe_notify_tracer(task, &mut pids, &parent, zombie)
1054 }
1055 None => Some(zombie),
1056 };
1057
1058 if let Some(zombie) = maybe_zombie {
1059 parent.do_zombie_notifications(zombie);
1060 }
1061 } else {
1062 zombie.release(&mut pids);
1063 }
1064
1065 if let Some(parent) = parent {
1071 let parent = parent.upgrade();
1072 parent.check_orphans(locked, &pids);
1073 }
1074
1075 self.write().set_exited();
1076 }
1077 }
1078
1079 fn detach_ptracees<L>(&self, locked: &mut Locked<L>, pids: &mut PidTable)
1081 where
1082 L: LockBefore<ThreadGroupLimits>,
1083 {
1084 let tracee_tids = self.ptracees.lock().keys().cloned().collect_vec();
1085 for tracee_tid in tracee_tids {
1086 let Ok(tracee) = pids.get_task(tracee_tid) else {
1087 continue;
1088 };
1089
1090 let mut should_send_sigkill = false;
1091 if let Some(ptrace) = &tracee.read().ptrace {
1092 should_send_sigkill = ptrace.has_option(PtraceOptions::EXITKILL);
1093 }
1094 if should_send_sigkill {
1095 send_standard_signal(locked, tracee.as_ref(), SignalInfo::kernel(SIGKILL));
1096 }
1097
1098 let _ = ptrace_detach(locked, pids, self, tracee.as_ref(), &UserAddress::NULL);
1099 }
1100 }
1101
1102 pub fn do_zombie_notifications(&self, zombie: OwnedRef<ZombieProcess>) {
1103 let mut state = self.write();
1104
1105 state.children.remove(&zombie.pid());
1106 state
1107 .deferred_zombie_ptracers
1108 .retain(|dzp| dzp.tracee_thread_group_key != zombie.thread_group_key);
1109
1110 let exit_signal = zombie.exit_info.exit_signal;
1111 let mut signal_info = zombie.to_wait_result().as_signal_info();
1112
1113 state.zombie_children.push(zombie);
1114 state.lifecycle_waiters.notify_value(ThreadGroupLifecycleWaitValue::ChildStatus);
1115
1116 if let Some(exit_signal) = exit_signal {
1118 signal_info.signal = exit_signal;
1119 state.send_signal(signal_info);
1120 }
1121 }
1122
1123 fn maybe_notify_tracer(
1127 &self,
1128 tracee: &Task,
1129 mut pids: &mut PidTable,
1130 parent: &ThreadGroup,
1131 zombie: OwnedRef<ZombieProcess>,
1132 ) -> Option<OwnedRef<ZombieProcess>> {
1133 let mut state = self.write();
1134 if state.zombie_ptracees.has_tracee(tracee.tid) {
1135 if self == parent {
1136 let zombie_notification = state.zombie_ptracees.detach(pids, tracee.tid);
1140 drop(state);
1141 if let Some(zombie_notification) = zombie_notification {
1142 zombie_notification.deliver(pids);
1143 }
1144 return Some(zombie);
1145 } else {
1146 if !state.is_running() {
1149 return Some(zombie);
1151 }
1152
1153 drop(state);
1156 {
1157 let tracee_pgid = tracee.thread_group().read().process_group.leader;
1159 let mut parent_state = parent.write();
1160 parent_state.deferred_zombie_ptracers.push(DeferredZombiePTracer::new(
1161 self,
1162 tracee,
1163 tracee_pgid,
1164 ));
1165 parent_state.children.remove(&tracee.get_pid());
1166 }
1167
1168 let mut state = self.write();
1174 state.zombie_ptracees.set_parent_of(tracee.tid, Some(zombie), parent);
1175 tracee.write().notify_ptracers();
1176 return None;
1177 }
1178 } else if self == parent {
1179 parent.write().children.remove(&tracee.tid);
1182 zombie.release(&mut pids);
1183 return None;
1184 }
1185 Some(zombie)
1188 }
1189
1190 fn find_reaper(&self) -> Option<ThreadGroupParent> {
1192 let mut weak_parent = self.read().parent.clone()?;
1193 loop {
1194 weak_parent = {
1195 let parent = weak_parent.upgrade();
1196 let parent_state = parent.read();
1197 if parent_state.is_child_subreaper {
1198 break;
1199 }
1200 match parent_state.parent {
1201 Some(ref next_parent) => next_parent.clone(),
1202 None => break,
1203 }
1204 };
1205 }
1206 Some(weak_parent)
1207 }
1208
1209 pub fn setsid<L>(&self, locked: &mut Locked<L>) -> Result<(), Errno>
1210 where
1211 L: LockBefore<ProcessGroupState>,
1212 {
1213 let pids = self.kernel.pids.read();
1214 if pids.get_process_group(self.leader).is_some() {
1215 return error!(EPERM);
1216 }
1217 let process_group = ProcessGroup::new(self.leader, None);
1218 pids.add_process_group(process_group.clone());
1219 let session = self.write().set_process_group(locked, process_group, &pids);
1220 session.disassociate_controlling_terminal(locked);
1221 self.check_orphans(locked, &pids);
1222
1223 Ok(())
1224 }
1225
1226 pub fn setpgid<L>(
1227 &self,
1228 locked: &mut Locked<L>,
1229 current_task: &CurrentTask,
1230 target: &Task,
1231 pgid: pid_t,
1232 ) -> Result<(), Errno>
1233 where
1234 L: LockBefore<ProcessGroupState>,
1235 {
1236 let pids = self.kernel.pids.read();
1237
1238 {
1239 let current_process_group = Arc::clone(&self.read().process_group);
1240
1241 let mut target_thread_group = target.thread_group().write();
1243 let is_target_current_process_child =
1244 target_thread_group.parent.as_ref().map(|tg| tg.upgrade().leader)
1245 == Some(self.leader);
1246 if target_thread_group.leader() != self.leader && !is_target_current_process_child {
1247 return error!(ESRCH);
1248 }
1249
1250 if is_target_current_process_child && target_thread_group.did_exec {
1253 return error!(EACCES);
1254 }
1255
1256 let new_process_group;
1257 {
1258 let target_process_group = &target_thread_group.process_group;
1259
1260 if target_thread_group.leader() == target_process_group.session.leader
1262 || current_process_group.session != target_process_group.session
1263 {
1264 return error!(EPERM);
1265 }
1266
1267 let target_pgid = if pgid == 0 { target_thread_group.leader() } else { pgid };
1268 if target_pgid < 0 {
1269 return error!(EINVAL);
1270 }
1271
1272 if target_pgid == target_process_group.leader {
1273 return Ok(());
1274 }
1275
1276 if target_pgid != target_thread_group.leader() {
1279 new_process_group =
1280 pids.get_process_group(target_pgid).ok_or_else(|| errno!(EPERM))?;
1281 if new_process_group.session != target_process_group.session {
1282 return error!(EPERM);
1283 }
1284 security::check_setpgid_access(current_task, target)?;
1285 } else {
1286 security::check_setpgid_access(current_task, target)?;
1287 new_process_group =
1289 ProcessGroup::new(target_pgid, Some(target_process_group.session.clone()));
1290 pids.add_process_group(new_process_group.clone());
1291 }
1292 }
1293
1294 let session = target_thread_group.set_process_group(locked, new_process_group, &pids);
1295 std::mem::drop(target_thread_group);
1296 session.disassociate_controlling_terminal(locked);
1299 }
1300
1301 target.thread_group().check_orphans(locked, &pids);
1302
1303 Ok(())
1304 }
1305
1306 fn itimer_real(&self) -> IntervalTimerHandle {
1307 self.timers.itimer_real()
1308 }
1309
1310 pub fn set_itimer(
1311 &self,
1312 current_task: &CurrentTask,
1313 which: u32,
1314 value: itimerval,
1315 ) -> Result<itimerval, Errno> {
1316 if which == ITIMER_PROF || which == ITIMER_VIRTUAL {
1317 if value.it_value.tv_sec == 0 && value.it_value.tv_usec == 0 {
1321 return Ok(itimerval::default());
1322 }
1323 track_stub!(TODO("https://fxbug.dev/322874521"), "Unsupported itimer type", which);
1324 return error!(ENOTSUP);
1325 }
1326
1327 if which != ITIMER_REAL {
1328 return error!(EINVAL);
1329 }
1330 let itimer_real = self.itimer_real();
1331 let prev_remaining = itimer_real.time_remaining();
1332 if value.it_value.tv_sec != 0 || value.it_value.tv_usec != 0 {
1333 itimer_real.arm(current_task, itimerspec_from_itimerval(value), false)?;
1334 } else {
1335 itimer_real.disarm(current_task)?;
1336 }
1337 Ok(itimerval {
1338 it_value: timeval_from_duration(prev_remaining.remainder),
1339 it_interval: timeval_from_duration(prev_remaining.interval),
1340 })
1341 }
1342
1343 pub fn get_itimer(&self, which: u32) -> Result<itimerval, Errno> {
1344 if which == ITIMER_PROF || which == ITIMER_VIRTUAL {
1345 return Ok(itimerval::default());
1347 }
1348 if which != ITIMER_REAL {
1349 return error!(EINVAL);
1350 }
1351 let remaining = self.itimer_real().time_remaining();
1352 Ok(itimerval {
1353 it_value: timeval_from_duration(remaining.remainder),
1354 it_interval: timeval_from_duration(remaining.interval),
1355 })
1356 }
1357
1358 fn check_stopped_state(
1361 &self,
1362 new_stopped: StopState,
1363 finalize_only: bool,
1364 ) -> Option<StopState> {
1365 let stopped = self.load_stopped();
1366 if finalize_only && !stopped.is_stopping_or_stopped() {
1367 return Some(stopped);
1368 }
1369
1370 if stopped.is_illegal_transition(new_stopped) {
1371 return Some(stopped);
1372 }
1373
1374 return None;
1375 }
1376
1377 pub fn set_stopped(
1384 &self,
1385 new_stopped: StopState,
1386 siginfo: Option<SignalInfo>,
1387 finalize_only: bool,
1388 ) -> StopState {
1389 if let Some(stopped) = self.check_stopped_state(new_stopped, finalize_only) {
1391 return stopped;
1392 }
1393
1394 self.write().set_stopped(new_stopped, siginfo, finalize_only)
1395 }
1396
1397 fn check_terminal_controller(
1400 session: &Arc<Session>,
1401 terminal_controller: &Option<TerminalController>,
1402 ) -> Result<(), Errno> {
1403 if let Some(terminal_controller) = terminal_controller {
1404 if let Some(terminal_session) = terminal_controller.session.upgrade() {
1405 if Arc::ptr_eq(session, &terminal_session) {
1406 return Ok(());
1407 }
1408 }
1409 }
1410 error!(ENOTTY)
1411 }
1412
1413 pub fn get_foreground_process_group(&self, terminal: &Terminal) -> Result<pid_t, Errno> {
1414 let state = self.read();
1415 let process_group = &state.process_group;
1416 let terminal_state = terminal.read();
1417
1418 Self::check_terminal_controller(&process_group.session, &terminal_state.controller)?;
1421 let pid = process_group.session.read().get_foreground_process_group_leader();
1422 Ok(pid)
1423 }
1424
1425 pub fn set_foreground_process_group<L>(
1426 &self,
1427 locked: &mut Locked<L>,
1428 current_task: &CurrentTask,
1429 terminal: &Terminal,
1430 pgid: pid_t,
1431 ) -> Result<(), Errno>
1432 where
1433 L: LockBefore<ProcessGroupState>,
1434 {
1435 let process_group;
1436 let send_ttou;
1437 {
1438 let pids = self.kernel.pids.read();
1440 let state = self.read();
1441 process_group = Arc::clone(&state.process_group);
1442 let terminal_state = terminal.read();
1443 Self::check_terminal_controller(&process_group.session, &terminal_state.controller)?;
1444
1445 if pgid < 0 {
1447 return error!(EINVAL);
1448 }
1449
1450 let new_process_group = pids.get_process_group(pgid).ok_or_else(|| errno!(ESRCH))?;
1451 if new_process_group.session != process_group.session {
1452 return error!(EPERM);
1453 }
1454
1455 let mut session_state = process_group.session.write();
1456 send_ttou = process_group.leader != session_state.get_foreground_process_group_leader()
1459 && !current_task.read().signal_mask().has_signal(SIGTTOU)
1460 && self.signal_actions.get(SIGTTOU).sa_handler != SIG_IGN;
1461
1462 if !send_ttou {
1463 session_state.set_foreground_process_group(&new_process_group);
1464 }
1465 }
1466
1467 if send_ttou {
1469 process_group.send_signals(locked, &[SIGTTOU]);
1470 return error!(EINTR);
1471 }
1472
1473 Ok(())
1474 }
1475
1476 pub fn set_controlling_terminal(
1477 &self,
1478 current_task: &CurrentTask,
1479 terminal: &Terminal,
1480 is_main: bool,
1481 steal: bool,
1482 is_readable: bool,
1483 ) -> Result<(), Errno> {
1484 let state = self.read();
1486 let process_group = &state.process_group;
1487 let mut terminal_state = terminal.write();
1488
1489 let other_session = terminal_state.controller.as_ref().and_then(|cs| cs.session.upgrade());
1492 let (mut session_writer, other_session) =
1493 if let Some(other_session) = other_session.as_ref() {
1494 if *other_session == process_group.session {
1495 (process_group.session.mutable_state.write(), None)
1496 } else {
1497 let (session_writer, other_session_writer) = ordered_write_lock(
1498 &process_group.session.mutable_state,
1499 &other_session.mutable_state,
1500 );
1501 (session_writer, Some((other_session, other_session_writer)))
1502 }
1503 } else {
1504 (process_group.session.mutable_state.write(), None)
1505 };
1506
1507 if process_group.session.leader != self.leader
1510 || session_writer.controlling_terminal.is_some()
1511 {
1512 return error!(EINVAL);
1513 }
1514
1515 let mut has_admin_capability_determined = false;
1516
1517 if let Some((other_session, mut other_session_writer)) = other_session {
1523 debug_assert!(*other_session != process_group.session);
1524 if !steal {
1525 return error!(EPERM);
1526 }
1527 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1528 has_admin_capability_determined = true;
1529
1530 other_session_writer.controlling_terminal = None;
1532 }
1533
1534 if !is_readable && !has_admin_capability_determined {
1535 security::check_task_capable(current_task, CAP_SYS_ADMIN)?;
1536 }
1537
1538 session_writer.controlling_terminal = Some(ControllingTerminal::new(terminal, is_main));
1539 terminal_state.controller = TerminalController::new(&process_group.session);
1540 Ok(())
1541 }
1542
1543 pub fn release_controlling_terminal<L>(
1544 &self,
1545 locked: &mut Locked<L>,
1546 _current_task: &CurrentTask,
1547 terminal: &Terminal,
1548 is_main: bool,
1549 ) -> Result<(), Errno>
1550 where
1551 L: LockBefore<ProcessGroupState>,
1552 {
1553 let process_group;
1554 {
1555 let state = self.read();
1557 process_group = Arc::clone(&state.process_group);
1558 let mut terminal_state = terminal.write();
1559 let mut session_writer = process_group.session.write();
1560
1561 Self::check_terminal_controller(&process_group.session, &terminal_state.controller)?;
1563 if !session_writer
1564 .controlling_terminal
1565 .as_ref()
1566 .map_or(false, |ct| ct.matches(terminal, is_main))
1567 {
1568 return error!(ENOTTY);
1569 }
1570
1571 session_writer.controlling_terminal = None;
1579 terminal_state.controller = None;
1580 }
1581
1582 if process_group.session.leader == self.leader {
1583 process_group.send_signals(locked, &[SIGHUP, SIGCONT]);
1584 }
1585
1586 Ok(())
1587 }
1588
1589 fn check_orphans<L>(&self, locked: &mut Locked<L>, pids: &PidTable)
1590 where
1591 L: LockBefore<ProcessGroupState>,
1592 {
1593 let mut thread_groups = self.read().children().collect::<Vec<_>>();
1594 let this = self.weak_self.upgrade().unwrap();
1595 thread_groups.push(this);
1596 let process_groups =
1597 thread_groups.iter().map(|tg| Arc::clone(&tg.read().process_group)).unique();
1598 for pg in process_groups {
1599 pg.check_orphaned(locked, pids);
1600 }
1601 }
1602
1603 pub fn get_rlimit<L>(&self, locked: &mut Locked<L>, resource: Resource) -> u64
1604 where
1605 L: LockBefore<ThreadGroupLimits>,
1606 {
1607 self.limits.lock(locked).get(resource).rlim_cur
1608 }
1609
1610 pub fn adjust_rlimits<L>(
1612 locked: &mut Locked<L>,
1613 current_task: &CurrentTask,
1614 target_task: &Task,
1615 resource: Resource,
1616 maybe_new_limit: Option<rlimit>,
1617 ) -> Result<rlimit, Errno>
1618 where
1619 L: LockBefore<ThreadGroupLimits>,
1620 {
1621 let thread_group = target_task.thread_group();
1622 let can_increase_rlimit = security::is_task_capable_noaudit(current_task, CAP_SYS_RESOURCE);
1623 let mut limit_state = thread_group.limits.lock(locked);
1624 let old_limit = limit_state.get(resource);
1625 if let Some(new_limit) = maybe_new_limit {
1626 if new_limit.rlim_max > old_limit.rlim_max && !can_increase_rlimit {
1627 return error!(EPERM);
1628 }
1629 security::task_setrlimit(current_task, &target_task, old_limit, new_limit)?;
1630 limit_state.set(resource, new_limit)
1631 }
1632 Ok(old_limit)
1633 }
1634
1635 pub fn time_stats(&self) -> TaskTimeStats {
1636 let process: &zx::Process = if self.process.as_handle_ref().is_invalid() {
1637 assert_eq!(
1640 self as *const ThreadGroup,
1641 Arc::as_ptr(&self.kernel.kthreads.system_thread_group())
1642 );
1643 &self.kernel.kthreads.starnix_process
1644 } else {
1645 &self.process
1646 };
1647
1648 let info =
1649 zx::Task::get_runtime_info(process).expect("Failed to get starnix process stats");
1650 TaskTimeStats {
1651 user_time: zx::MonotonicDuration::from_nanos(info.cpu_time),
1652 system_time: zx::MonotonicDuration::default(),
1654 }
1655 }
1656
1657 pub fn get_ptracees_and(
1661 &self,
1662 selector: &ProcessSelector,
1663 pids: &PidTable,
1664 f: &mut dyn FnMut(&Task, &TaskMutableState),
1665 ) {
1666 for tracee in self
1667 .ptracees
1668 .lock()
1669 .keys()
1670 .filter(|tracee_tid| selector.match_tid(**tracee_tid, &pids))
1671 .map(|tracee_tid| pids.get_task(*tracee_tid))
1672 {
1673 if let Ok(task_ref) = tracee {
1674 let task_state = task_ref.write();
1675 if task_state.ptrace.is_some() {
1676 f(&task_ref, &task_state);
1677 }
1678 }
1679 }
1680 }
1681
1682 pub fn get_waitable_ptracee(
1687 &self,
1688 selector: &ProcessSelector,
1689 options: &WaitingOptions,
1690 pids: &mut PidTable,
1691 ) -> Option<WaitResult> {
1692 let waitable_entry = self.write().zombie_ptracees.get_waitable_entry(selector, options);
1694 match waitable_entry {
1695 None => (),
1696 Some((zombie, None)) => return Some(zombie.to_wait_result()),
1697 Some((zombie, Some((tg, z)))) => {
1698 if let Some(tg) = tg.upgrade() {
1699 if Arc::as_ptr(&tg) != self as *const Self {
1700 tg.do_zombie_notifications(z);
1701 } else {
1702 {
1703 let mut state = tg.write();
1704 state.children.remove(&z.pid());
1705 state
1706 .deferred_zombie_ptracers
1707 .retain(|dzp| dzp.tracee_thread_group_key != z.thread_group_key);
1708 }
1709
1710 z.release(pids);
1711 };
1712 }
1713 return Some(zombie.to_wait_result());
1714 }
1715 }
1716
1717 let mut tasks = vec![];
1718
1719 self.get_ptracees_and(selector, pids, &mut |task: &Task, _| {
1721 tasks.push(task.weak_self.clone());
1722 });
1723 for task in tasks {
1724 let Some(task_ref) = task.upgrade() else {
1725 continue;
1726 };
1727
1728 let process_state = &mut task_ref.thread_group().write();
1729 let mut task_state = task_ref.write();
1730 if task_state
1731 .ptrace
1732 .as_ref()
1733 .is_some_and(|ptrace| ptrace.is_waitable(task_ref.load_stopped(), options))
1734 {
1735 let mut pid: i32 = 0;
1741 let info = process_state.tasks.values().next().unwrap().info().clone();
1742 let uid = info.real_creds().uid;
1743 let mut exit_status = None;
1744 let exit_signal = process_state.exit_signal.clone();
1745 let time_stats =
1746 process_state.base.time_stats() + process_state.children_time_stats;
1747 let task_stopped = task_ref.load_stopped();
1748
1749 #[derive(PartialEq)]
1750 enum ExitType {
1751 None,
1752 Cont,
1753 Stop,
1754 Kill,
1755 }
1756 if process_state.is_waitable() {
1757 let ptrace = &mut task_state.ptrace;
1758 let process_stopped = process_state.base.load_stopped();
1760 let mut fn_type = ExitType::None;
1761 if process_stopped == StopState::Awake && options.wait_for_continued {
1762 fn_type = ExitType::Cont;
1763 }
1764 let mut event = ptrace
1765 .as_ref()
1766 .map_or(PtraceEvent::None, |ptrace| {
1767 ptrace.event_data.as_ref().map_or(PtraceEvent::None, |data| data.event)
1768 })
1769 .clone();
1770 if process_stopped == StopState::GroupStopped
1772 && (options.wait_for_stopped || ptrace.is_some())
1773 {
1774 fn_type = ExitType::Stop;
1775 }
1776 if fn_type != ExitType::None {
1777 let siginfo = if options.keep_waitable_state {
1778 process_state.last_signal.clone()
1779 } else {
1780 process_state.last_signal.take()
1781 };
1782 if let Some(mut siginfo) = siginfo {
1783 if task_ref.thread_group().load_stopped() == StopState::GroupStopped
1784 && ptrace.as_ref().is_some_and(|ptrace| ptrace.is_seized())
1785 {
1786 if event == PtraceEvent::None {
1787 event = PtraceEvent::Stop;
1788 }
1789 siginfo.code |= (PtraceEvent::Stop as i32) << 8;
1790 }
1791 if siginfo.signal == SIGKILL {
1792 fn_type = ExitType::Kill;
1793 }
1794 exit_status = match fn_type {
1795 ExitType::Stop => Some(ExitStatus::Stop(siginfo, event)),
1796 ExitType::Cont => Some(ExitStatus::Continue(siginfo, event)),
1797 ExitType::Kill => Some(ExitStatus::Kill(siginfo)),
1798 _ => None,
1799 };
1800 }
1801 ptrace
1804 .as_mut()
1805 .map(|ptrace| ptrace.get_last_signal(options.keep_waitable_state));
1806 }
1807 pid = process_state.base.leader;
1808 }
1809 if exit_status == None {
1810 if let Some(ptrace) = task_state.ptrace.as_mut() {
1811 let mut fn_type = ExitType::None;
1813 let event = ptrace
1814 .event_data
1815 .as_ref()
1816 .map_or(PtraceEvent::None, |event| event.event);
1817 if task_stopped == StopState::Awake {
1818 fn_type = ExitType::Cont;
1819 }
1820 if task_stopped.is_stopping_or_stopped()
1821 || ptrace.stop_status == PtraceStatus::Listening
1822 {
1823 fn_type = ExitType::Stop;
1824 }
1825 if fn_type != ExitType::None {
1826 if let Some(siginfo) =
1827 ptrace.get_last_signal(options.keep_waitable_state)
1828 {
1829 if siginfo.signal == SIGKILL {
1830 fn_type = ExitType::Kill;
1831 }
1832 exit_status = match fn_type {
1833 ExitType::Stop => Some(ExitStatus::Stop(siginfo, event)),
1834 ExitType::Cont => Some(ExitStatus::Continue(siginfo, event)),
1835 ExitType::Kill => Some(ExitStatus::Kill(siginfo)),
1836 _ => None,
1837 };
1838 }
1839 }
1840 pid = task_ref.get_tid();
1841 }
1842 }
1843 if let Some(exit_status) = exit_status {
1844 return Some(WaitResult {
1845 pid,
1846 uid,
1847 exit_info: ProcessExitInfo { status: exit_status, exit_signal },
1848 time_stats,
1849 });
1850 }
1851 }
1852 }
1853 None
1854 }
1855
1856 pub fn send_signal_unchecked(
1866 &self,
1867 current_task: &CurrentTask,
1868 unchecked_signal: UncheckedSignal,
1869 ) -> Result<(), Errno> {
1870 if let Some(signal) = self.check_signal_access(current_task, unchecked_signal)? {
1871 let signal_info = SignalInfo::with_detail(
1872 signal,
1873 SI_USER as i32,
1874 SignalDetail::Kill {
1875 pid: current_task.thread_group().leader,
1876 uid: current_task.current_creds().uid,
1877 },
1878 );
1879
1880 self.write().send_signal(signal_info);
1881 }
1882
1883 Ok(())
1884 }
1885
1886 pub unsafe fn send_signal_unchecked_debug(
1891 &self,
1892 current_task: &CurrentTask,
1893 unchecked_signal: UncheckedSignal,
1894 ) -> Result<(), Errno> {
1895 let signal = Signal::try_from(unchecked_signal)?;
1896 let signal_info = SignalInfo::with_detail(
1897 signal,
1898 SI_USER as i32,
1899 SignalDetail::Kill {
1900 pid: current_task.thread_group().leader,
1901 uid: current_task.current_creds().uid,
1902 },
1903 );
1904
1905 self.write().send_signal(signal_info);
1906 Ok(())
1907 }
1908
1909 #[track_caller]
1922 pub fn send_signal_unchecked_with_info(
1923 &self,
1924 current_task: &CurrentTask,
1925 unchecked_signal: UncheckedSignal,
1926 siginfo_ref: UserAddress,
1927 options: IntoSignalInfoOptions,
1928 ) -> Result<(), Errno> {
1929 if let Some(signal) = self.check_signal_access(current_task, unchecked_signal)? {
1930 let siginfo = UncheckedSignalInfo::read_from_siginfo(current_task, siginfo_ref)?;
1931 if self.leader != current_task.get_pid()
1932 && (siginfo.code() >= 0 || siginfo.code() == SI_TKILL)
1933 {
1934 return error!(EPERM);
1935 }
1936
1937 self.write().send_signal(siginfo.into_signal_info(signal, options)?);
1938 }
1939
1940 Ok(())
1941 }
1942
1943 fn check_signal_access(
1951 &self,
1952 current_task: &CurrentTask,
1953 unchecked_signal: UncheckedSignal,
1954 ) -> Result<Option<Signal>, Errno> {
1955 let target_task = self.read().get_any_task()?;
1959 current_task.can_signal(&target_task, unchecked_signal)?;
1960
1961 if unchecked_signal.is_zero() {
1963 return Ok(None);
1964 }
1965
1966 let signal = Signal::try_from(unchecked_signal)?;
1967 security::check_signal_access(current_task, &target_task, signal)?;
1968
1969 Ok(Some(signal))
1970 }
1971
1972 pub fn has_signal_queued(&self, signal: Signal) -> bool {
1973 self.pending_signals.lock().has_queued(signal)
1974 }
1975
1976 pub fn num_signals_queued(&self) -> usize {
1977 self.pending_signals.lock().num_queued()
1978 }
1979
1980 pub fn get_pending_signals(&self) -> SigSet {
1981 self.pending_signals.lock().pending()
1982 }
1983
1984 pub fn is_any_signal_allowed_by_mask(&self, mask: SigSet) -> bool {
1985 self.pending_signals.lock().is_any_allowed_by_mask(mask)
1986 }
1987
1988 pub fn take_next_signal_where<F>(&self, predicate: F) -> Option<SignalInfo>
1989 where
1990 F: Fn(&SignalInfo) -> bool,
1991 {
1992 let mut signals = self.pending_signals.lock();
1993 let r = signals.take_next_where(predicate);
1994 self.has_pending_signals.store(!signals.is_empty(), Ordering::Relaxed);
1995 r
1996 }
1997
1998 pub async fn shut_down(this: Weak<Self>) {
2004 const SHUTDOWN_SIGNAL_HANDLING_TIMEOUT: zx::MonotonicDuration =
2005 zx::MonotonicDuration::from_seconds(1);
2006
2007 let (tg_name, mut on_exited) = {
2009 let Some(this) = this.upgrade() else {
2011 return;
2012 };
2013
2014 let mut state = this.write();
2015 if state.is_exited() {
2016 return;
2018 }
2019
2020 let (on_exited_send, on_exited) = futures::channel::oneshot::channel();
2022 state.exit_notifier = Some(on_exited_send);
2023
2024 let tg_name = format!("{this:?}");
2026
2027 (tg_name, on_exited)
2028 };
2029
2030 log_debug!(tg:% = tg_name; "shutting down thread group, sending SIGTERM");
2031 this.upgrade().map(|tg| tg.write().send_signal(SignalInfo::kernel(SIGTERM)));
2032
2033 let timeout = fuchsia_async::Timer::new(SHUTDOWN_SIGNAL_HANDLING_TIMEOUT);
2035 futures::pin_mut!(timeout);
2036
2037 futures::select_biased! {
2039 _ = &mut on_exited => (),
2040 _ = timeout => {
2041 log_debug!(tg:% = tg_name; "sending SIGKILL");
2042 this.upgrade().map(|tg| tg.write().send_signal(SignalInfo::kernel(SIGKILL)));
2043 },
2044 };
2045
2046 log_debug!(tg:% = tg_name; "waiting for exit");
2047 on_exited.await.ok();
2050 log_debug!(tg:% = tg_name; "thread group shutdown complete");
2051 }
2052
2053 pub fn get_process_koid(&self) -> Result<Koid, Status> {
2059 self.process.koid()
2060 }
2061}
2062
2063pub enum WaitableChildResult {
2064 ReadyNow(Box<WaitResult>),
2065 ShouldWait,
2066 NoneFound,
2067}
2068
2069#[apply(state_implementation!)]
2070impl ThreadGroupMutableState<Base = ThreadGroup> {
2071 pub fn leader(&self) -> pid_t {
2072 self.base.leader
2073 }
2074
2075 pub fn leader_command(&self) -> TaskCommand {
2076 self.get_task(self.leader())
2077 .map(|l| l.command())
2078 .unwrap_or_else(|| TaskCommand::new(b"<leader exited>"))
2079 }
2080
2081 pub fn is_running(&self) -> bool {
2082 matches!(self.run_state, ThreadGroupRunState::Running)
2083 }
2084
2085 pub fn is_exited(&self) -> bool {
2086 matches!(self.run_state, ThreadGroupRunState::Exited(_))
2087 }
2088
2089 fn set_exiting(&mut self, exit_status: ExitStatus) {
2090 self.run_state = ThreadGroupRunState::Exiting(exit_status);
2091 }
2092
2093 fn set_exited(&mut self) {
2094 let ThreadGroupRunState::Exiting(exit_status) = std::mem::take(&mut self.run_state) else {
2095 panic!("Must transition from Exiting to Exited");
2096 };
2097 self.run_state = ThreadGroupRunState::Exited(exit_status);
2098
2099 if let Some(notifier) = self.exit_notifier.take() {
2100 let _ = notifier.send(());
2101 }
2102 }
2103
2104 pub fn children(&self) -> impl Iterator<Item = Arc<ThreadGroup>> + '_ {
2105 self.children.values().map(|v| {
2106 v.upgrade().expect("Weak references to processes in ThreadGroup must always be valid")
2107 })
2108 }
2109
2110 pub fn tasks(&self) -> Vec<Arc<Task>> {
2111 self.tasks.values().flat_map(|t| t.upgrade()).collect()
2112 }
2113
2114 pub fn task_ids(&self) -> impl Iterator<Item = &tid_t> {
2115 self.tasks.keys()
2116 }
2117
2118 pub fn contains_task(&self, tid: tid_t) -> bool {
2119 self.tasks.contains_key(&tid)
2120 }
2121
2122 pub fn get_task(&self, tid: tid_t) -> Option<Arc<Task>> {
2123 self.tasks.get(&tid).and_then(|t| t.upgrade())
2124 }
2125
2126 pub fn tasks_count(&self) -> usize {
2127 self.tasks.len()
2128 }
2129
2130 pub fn get_ppid(&self) -> pid_t {
2131 match &self.parent {
2132 Some(parent) => parent.upgrade().leader,
2133 None => 0,
2134 }
2135 }
2136
2137 fn set_process_group<L>(
2145 &mut self,
2146 locked: &mut Locked<L>,
2147 process_group: Arc<ProcessGroup>,
2148 pids: &PidTable,
2149 ) -> SessionDisassociation
2150 where
2151 L: LockBefore<ProcessGroupState>,
2152 {
2153 if self.process_group == process_group {
2154 return SessionDisassociation::new(None);
2155 }
2156 let session = self.leave_process_group(locked, pids);
2157 self.process_group = process_group;
2158 self.process_group.insert(locked, self.base);
2159 session
2160 }
2161
2162 fn leave_process_group<L>(
2170 &mut self,
2171 locked: &mut Locked<L>,
2172 pids: &PidTable,
2173 ) -> SessionDisassociation
2174 where
2175 L: LockBefore<ProcessGroupState>,
2176 {
2177 let (is_empty, disassociation) = self.process_group.remove(locked, self.base);
2178 if is_empty {
2179 self.process_group.session.write().remove(self.process_group.leader);
2180 pids.remove_process_group(self.process_group.leader);
2181 }
2182 disassociation
2183 }
2184
2185 pub fn is_waitable(&self) -> bool {
2188 return self.last_signal.is_some() && !self.base.load_stopped().is_in_progress();
2189 }
2190
2191 pub fn get_waitable_zombie(
2192 &mut self,
2193 zombie_list: &dyn Fn(&mut ThreadGroupMutableState) -> &mut Vec<OwnedRef<ZombieProcess>>,
2194 selector: &ProcessSelector,
2195 options: &WaitingOptions,
2196 pids: &mut PidTable,
2197 ) -> Option<WaitResult> {
2198 let selected_zombie_position = zombie_list(self)
2200 .iter()
2201 .rev()
2202 .position(|zombie| zombie.matches_selector_and_waiting_option(selector, options))
2203 .map(|position_starting_from_the_back| {
2204 zombie_list(self).len() - 1 - position_starting_from_the_back
2205 });
2206
2207 selected_zombie_position.map(|position| {
2208 if options.keep_waitable_state {
2209 zombie_list(self)[position].to_wait_result()
2210 } else {
2211 let zombie = zombie_list(self).remove(position);
2212 self.children_time_stats += zombie.time_stats;
2213 let result = zombie.to_wait_result();
2214 zombie.release(pids);
2215 result
2216 }
2217 })
2218 }
2219
2220 pub fn is_correct_exit_signal(for_clone: bool, exit_code: Option<Signal>) -> bool {
2221 for_clone == (exit_code != Some(SIGCHLD))
2222 }
2223
2224 fn get_waitable_running_children(
2225 &self,
2226 selector: &ProcessSelector,
2227 options: &WaitingOptions,
2228 pids: &PidTable,
2229 ) -> WaitableChildResult {
2230 let filter_children_by_pid_selector = |child: &ThreadGroup| match *selector {
2232 ProcessSelector::Any => true,
2233 ProcessSelector::Pid(pid) => child.leader == pid,
2234 ProcessSelector::Pgid(pgid) => {
2235 let _token = allow_subclass();
2239 pids.get_process_group(pgid).as_ref() == Some(&child.read().process_group)
2240 }
2241 ProcessSelector::Process(ref key) => *key == ThreadGroupKey::from(child),
2242 };
2243
2244 let filter_children_by_waiting_options = |child: &ThreadGroup| {
2246 if options.wait_for_all {
2247 return true;
2248 }
2249 let _token = allow_subclass();
2253 Self::is_correct_exit_signal(options.wait_for_clone, child.read().exit_signal)
2254 };
2255
2256 let mut selected_children = self
2259 .children
2260 .values()
2261 .map(|t| t.upgrade().unwrap())
2262 .filter(|tg| filter_children_by_pid_selector(&tg))
2263 .filter(|tg| filter_children_by_waiting_options(&tg))
2264 .peekable();
2265 if selected_children.peek().is_none() {
2266 if self.deferred_zombie_ptracers.iter().any(|dzp| match *selector {
2268 ProcessSelector::Any => true,
2269 ProcessSelector::Pid(pid) => dzp.tracee_thread_group_key.pid() == pid,
2270 ProcessSelector::Pgid(pgid) => pgid == dzp.tracee_pgid,
2271 ProcessSelector::Process(ref key) => *key == dzp.tracee_thread_group_key,
2272 }) {
2273 return WaitableChildResult::ShouldWait;
2274 }
2275
2276 return WaitableChildResult::NoneFound;
2277 }
2278 for child in selected_children {
2279 let _token = allow_subclass();
2283 let child = child.write();
2284 if child.last_signal.is_some() {
2285 let build_wait_result = |mut child: ThreadGroupWriteGuard<'_>,
2286 exit_status: &dyn Fn(SignalInfo) -> ExitStatus|
2287 -> WaitResult {
2288 let siginfo = if options.keep_waitable_state {
2289 child.last_signal.clone().unwrap()
2290 } else {
2291 child.last_signal.take().unwrap()
2292 };
2293 let exit_status = if siginfo.signal == SIGKILL {
2294 ExitStatus::Kill(siginfo)
2296 } else {
2297 exit_status(siginfo)
2298 };
2299 let info = child.tasks.values().next().unwrap().info();
2300 let uid = info.real_creds().uid;
2301 WaitResult {
2302 pid: child.base.leader,
2303 uid,
2304 exit_info: ProcessExitInfo {
2305 status: exit_status,
2306 exit_signal: child.exit_signal,
2307 },
2308 time_stats: child.base.time_stats() + child.children_time_stats,
2309 }
2310 };
2311 let child_stopped = child.base.load_stopped();
2312 if child_stopped == StopState::Awake && options.wait_for_continued {
2313 return WaitableChildResult::ReadyNow(Box::new(build_wait_result(
2314 child,
2315 &|siginfo| ExitStatus::Continue(siginfo, PtraceEvent::None),
2316 )));
2317 }
2318 if child_stopped == StopState::GroupStopped && options.wait_for_stopped {
2319 return WaitableChildResult::ReadyNow(Box::new(build_wait_result(
2320 child,
2321 &|siginfo| ExitStatus::Stop(siginfo, PtraceEvent::None),
2322 )));
2323 }
2324 }
2325 }
2326
2327 WaitableChildResult::ShouldWait
2328 }
2329
2330 pub fn get_waitable_child(
2336 &mut self,
2337 selector: &ProcessSelector,
2338 options: &WaitingOptions,
2339 pids: &mut PidTable,
2340 ) -> WaitableChildResult {
2341 if options.wait_for_exited {
2342 if let Some(waitable_zombie) = self.get_waitable_zombie(
2343 &|state: &mut ThreadGroupMutableState| &mut state.zombie_children,
2344 selector,
2345 options,
2346 pids,
2347 ) {
2348 return WaitableChildResult::ReadyNow(Box::new(waitable_zombie));
2349 }
2350 }
2351
2352 self.get_waitable_running_children(selector, options, pids)
2353 }
2354
2355 pub fn get_running_task(&self) -> Result<Arc<Task>, Errno> {
2357 self.tasks
2358 .iter()
2359 .find_map(|container| container.1.upgrade().filter(|task| task.is_running()))
2360 .ok_or_else(|| errno!(ESRCH))
2361 }
2362
2363 pub fn get_any_task(&self) -> Result<Arc<Task>, Errno> {
2369 self.get_running_task()
2370 .ok()
2371 .or_else(|| self.base.leader_task.get().and_then(|t| t.upgrade()))
2372 .ok_or_else(|| errno!(ESRCH))
2373 }
2374
2375 pub fn set_stopped(
2382 mut self,
2383 new_stopped: StopState,
2384 siginfo: Option<SignalInfo>,
2385 finalize_only: bool,
2386 ) -> StopState {
2387 if let Some(stopped) = self.base.check_stopped_state(new_stopped, finalize_only) {
2388 return stopped;
2389 }
2390
2391 if self.base.load_stopped() == StopState::Waking
2394 && (new_stopped == StopState::GroupStopping || new_stopped == StopState::GroupStopped)
2395 {
2396 return self.base.load_stopped();
2397 }
2398
2399 self.store_stopped(new_stopped);
2403 if let Some(signal) = &siginfo {
2404 if signal.signal != SIGKILL {
2408 self.last_signal = siginfo;
2409 }
2410 }
2411 if new_stopped == StopState::Waking || new_stopped == StopState::ForceWaking {
2412 self.lifecycle_waiters.notify_value(ThreadGroupLifecycleWaitValue::Stopped);
2413 };
2414
2415 let parent = (!new_stopped.is_in_progress()).then(|| self.parent.clone()).flatten();
2416
2417 std::mem::drop(self);
2419 if let Some(parent) = parent {
2420 let parent = parent.upgrade();
2421 parent
2422 .write()
2423 .lifecycle_waiters
2424 .notify_value(ThreadGroupLifecycleWaitValue::ChildStatus);
2425 }
2426
2427 new_stopped
2428 }
2429
2430 fn store_stopped(&mut self, state: StopState) {
2431 self.base.stop_state.store(state, Ordering::Relaxed)
2436 }
2437
2438 #[allow(unused_mut, reason = "needed for some but not all macro outputs")]
2440 pub fn send_signal(mut self, signal_info: SignalInfo) {
2441 let sigaction = self.base.signal_actions.get(signal_info.signal);
2442 let action = action_for_signal(&signal_info, sigaction);
2443
2444 {
2445 let mut pending_signals = self.base.pending_signals.lock();
2446 pending_signals.enqueue(signal_info.clone());
2447 self.base.has_pending_signals.store(true, Ordering::Relaxed);
2448 }
2449 let tasks: Vec<Weak<Task>> = self.tasks.values().map(|t| t.weak_clone()).collect();
2450
2451 if signal_info.signal == SIGKILL {
2453 self.set_stopped(StopState::ForceWaking, Some(signal_info.clone()), false);
2454 } else if signal_info.signal == SIGCONT {
2455 self.set_stopped(StopState::Waking, Some(signal_info.clone()), false);
2456 }
2457
2458 let mut has_interrupted_task = false;
2459 for task in tasks.iter().flat_map(|t| t.upgrade()) {
2460 let mut task_state = task.write();
2461
2462 if signal_info.signal == SIGKILL {
2463 task_state.thaw();
2464 task_state.set_stopped(StopState::ForceWaking, None, None, None);
2465 } else if signal_info.signal == SIGCONT {
2466 task_state.set_stopped(StopState::Waking, None, None, None);
2467 }
2468
2469 let is_masked = task_state.is_signal_masked(signal_info.signal);
2470 let was_masked = task_state.is_signal_masked_by_saved_mask(signal_info.signal);
2471
2472 let is_queued = action != DeliveryAction::Ignore
2473 || is_masked
2474 || was_masked
2475 || task_state.is_ptraced();
2476
2477 if is_queued {
2478 task_state.notify_signal_waiters(&signal_info.signal);
2479
2480 if !is_masked && action.must_interrupt(Some(sigaction)) && !has_interrupted_task {
2481 drop(task_state);
2484 task.interrupt();
2485 has_interrupted_task = true;
2486 }
2487 }
2488 }
2489 }
2490}
2491
2492pub struct TaskContainer(Weak<Task>, TaskPersistentInfo);
2498
2499impl From<&Arc<Task>> for TaskContainer {
2500 fn from(task: &Arc<Task>) -> Self {
2501 Self(Arc::downgrade(task), task.persistent_info.clone())
2502 }
2503}
2504
2505impl From<TaskContainer> for TaskPersistentInfo {
2506 fn from(container: TaskContainer) -> TaskPersistentInfo {
2507 container.1
2508 }
2509}
2510
2511impl TaskContainer {
2512 fn upgrade(&self) -> Option<Arc<Task>> {
2513 self.0.upgrade()
2514 }
2515
2516 fn weak_clone(&self) -> Weak<Task> {
2517 self.0.clone()
2518 }
2519
2520 fn info(&self) -> &TaskPersistentInfo {
2521 &self.1
2522 }
2523}
2524
2525#[cfg(test)]
2526mod test {
2527 use super::*;
2528 use crate::testing::*;
2529
2530 #[::fuchsia::test]
2531 async fn test_setsid() {
2532 spawn_kernel_and_run(async |locked, current_task| {
2533 fn get_process_group(task: &Task) -> Arc<ProcessGroup> {
2534 Arc::clone(&task.thread_group().read().process_group)
2535 }
2536 assert_eq!(current_task.thread_group().setsid(locked), error!(EPERM));
2537
2538 let child_task = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2539 assert_eq!(get_process_group(¤t_task), get_process_group(&child_task));
2540
2541 let old_process_group = child_task.thread_group().read().process_group.clone();
2542 assert_eq!(child_task.thread_group().setsid(locked), Ok(()));
2543 assert_eq!(
2544 child_task.thread_group().read().process_group.session.leader,
2545 child_task.get_pid()
2546 );
2547 assert!(
2548 !old_process_group.read(locked).thread_groups().contains(child_task.thread_group())
2549 );
2550 })
2551 .await;
2552 }
2553
2554 #[::fuchsia::test]
2555 async fn test_exit_status() {
2556 spawn_kernel_and_run(async |locked, current_task| {
2557 let child = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2558 child.thread_group().kill(locked, ExitStatus::Exit(42), None);
2559 std::mem::drop(child);
2560 assert_eq!(
2561 current_task.thread_group().read().zombie_children[0].exit_info.status,
2562 ExitStatus::Exit(42)
2563 );
2564 })
2565 .await;
2566 }
2567
2568 #[::fuchsia::test]
2569 async fn test_setgpid() {
2570 spawn_kernel_and_run(async |locked, current_task| {
2571 assert_eq!(current_task.thread_group().setsid(locked), error!(EPERM));
2572
2573 let child_task1 = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2574 let child_task2 = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2575 let execd_child_task = current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2576 execd_child_task.thread_group().write().did_exec = true;
2577 let other_session_child_task =
2578 current_task.clone_task_for_test(locked, 0, Some(SIGCHLD));
2579 assert_eq!(other_session_child_task.thread_group().setsid(locked), Ok(()));
2580
2581 assert_eq!(
2582 child_task1.thread_group().setpgid(locked, ¤t_task, ¤t_task, 0),
2583 error!(ESRCH)
2584 );
2585 assert_eq!(
2586 current_task.thread_group().setpgid(locked, ¤t_task, &execd_child_task, 0),
2587 error!(EACCES)
2588 );
2589 assert_eq!(
2590 current_task.thread_group().setpgid(locked, ¤t_task, ¤t_task, 0),
2591 error!(EPERM)
2592 );
2593 assert_eq!(
2594 current_task.thread_group().setpgid(
2595 locked,
2596 ¤t_task,
2597 &other_session_child_task,
2598 0
2599 ),
2600 error!(EPERM)
2601 );
2602 assert_eq!(
2603 current_task.thread_group().setpgid(locked, ¤t_task, &child_task1, -1),
2604 error!(EINVAL)
2605 );
2606 assert_eq!(
2607 current_task.thread_group().setpgid(locked, ¤t_task, &child_task1, 255),
2608 error!(EPERM)
2609 );
2610 assert_eq!(
2611 current_task.thread_group().setpgid(
2612 locked,
2613 ¤t_task,
2614 &child_task1,
2615 other_session_child_task.tid
2616 ),
2617 error!(EPERM)
2618 );
2619
2620 assert_eq!(
2621 child_task1.thread_group().setpgid(locked, ¤t_task, &child_task1, 0),
2622 Ok(())
2623 );
2624 assert_eq!(
2625 child_task1.thread_group().read().process_group.session.leader,
2626 current_task.tid
2627 );
2628 assert_eq!(child_task1.thread_group().read().process_group.leader, child_task1.tid);
2629
2630 let old_process_group = child_task2.thread_group().read().process_group.clone();
2631 assert_eq!(
2632 current_task.thread_group().setpgid(
2633 locked,
2634 ¤t_task,
2635 &child_task2,
2636 child_task1.tid
2637 ),
2638 Ok(())
2639 );
2640 assert_eq!(child_task2.thread_group().read().process_group.leader, child_task1.tid);
2641 assert!(
2642 !old_process_group
2643 .read(locked)
2644 .thread_groups()
2645 .contains(child_task2.thread_group())
2646 );
2647 })
2648 .await;
2649 }
2650
2651 #[::fuchsia::test]
2652 async fn test_adopt_children() {
2653 spawn_kernel_and_run(async |locked, current_task| {
2654 let task1 = current_task.clone_task_for_test(locked, 0, None);
2655 let task2 = task1.clone_task_for_test(locked, 0, None);
2656 let task3 = task2.clone_task_for_test(locked, 0, None);
2657
2658 assert_eq!(task3.thread_group().read().get_ppid(), task2.tid);
2659
2660 task2.thread_group().kill(locked, ExitStatus::Exit(0), None);
2661 std::mem::drop(task2);
2662
2663 assert_eq!(task3.thread_group().read().get_ppid(), current_task.tid);
2665 })
2666 .await;
2667 }
2668
2669 #[::fuchsia::test]
2670 async fn test_getppid_after_self_and_parent_exit() {
2671 spawn_kernel_and_run(async |locked, current_task| {
2672 let task1 = current_task.clone_task_for_test(locked, 0, None);
2673 let task2 = task1.clone_task_for_test(locked, 0, None);
2674
2675 let tg1 = task1.thread_group().clone();
2677 let tg2 = task2.thread_group().clone();
2678
2679 assert_eq!(tg1.read().get_ppid(), current_task.tid);
2680 assert_eq!(tg2.read().get_ppid(), task1.tid);
2681
2682 tg2.kill(locked, ExitStatus::Exit(0), None);
2684 std::mem::drop(task2);
2685
2686 tg1.kill(locked, ExitStatus::Exit(0), None);
2688 std::mem::drop(task1);
2689 std::mem::drop(tg1);
2690
2691 let _ = tg2.read().get_ppid();
2694 })
2695 .await;
2696 }
2697}