1use crate::device::terminal::{Terminal, TerminalSide};
6use crate::ptrace::StopState;
7use crate::signals::SignalInfo;
8use crate::task::idr::{Idr, IdrGuard};
9use crate::task::memory_attribution::MemoryAttributionLifecycleEvent;
10use crate::task::{Task, ThreadGroup, ThreadGroupLinkAdapter, ThreadGroupLinkNode};
11use fuchsia_rcu::subtle::{RcuPtr, RcuPtrRef};
12use fuchsia_rcu::{RcuDroppable, RcuOptionBox, RcuReadScope, RcuWeak, rcu_drop};
13use fuchsia_rcu_collections::rcu_intrusive_list::RcuIntrusiveList;
14use starnix_sync::PidTableLock;
15use starnix_uapi::errors::Errno;
16use starnix_uapi::signals::Signal;
17use starnix_uapi::{errno, error, pid_t};
18use std::sync::atomic::{AtomicI32, AtomicUsize, Ordering};
19use std::sync::{Arc, Weak};
20
21#[derive(Debug, RcuDroppable)]
22enum ProcessEntry {
23 ThreadGroup(Weak<ThreadGroup>),
24 Zombie(Weak<Task>),
25}
26
27impl ProcessEntry {
28 fn thread_group(&self) -> Option<&Weak<ThreadGroup>> {
29 match self {
30 Self::ThreadGroup(group) => Some(group),
31 _ => None,
32 }
33 }
34}
35
36#[derive(Debug, RcuDroppable)]
38pub struct PidEntry {
39 pub id: pid_t,
40 task: RcuWeak<Task>,
41 process: RcuOptionBox<ProcessEntry>,
42 pgid_thread_groups: RcuIntrusiveList<ThreadGroupLinkNode, ThreadGroupLinkAdapter>,
43 sid_thread_groups: RcuIntrusiveList<ThreadGroupLinkNode, ThreadGroupLinkAdapter>,
44}
45
46impl PidEntry {
47 pub fn get_task(&self) -> Result<Arc<Task>, Errno> {
48 self.task.upgrade().ok_or_else(|| errno!(ESRCH))
49 }
50
51 pub fn get_process_task(&self) -> Option<Arc<Task>> {
54 if let Ok(task) = self.get_task() {
55 return Some(task);
56 }
57 let process = self.process.read()?;
58 match &*process {
59 ProcessEntry::ThreadGroup(thread_group) => {
60 if let Some(task) = thread_group.upgrade().and_then(|tg| tg.read().first_task()) {
61 return Some(task);
62 }
63 match &*self.process.read()? {
64 ProcessEntry::Zombie(task) => task.upgrade(),
65 ProcessEntry::ThreadGroup(_) => None,
66 }
67 }
68 ProcessEntry::Zombie(task) => task.upgrade(),
69 }
70 }
71
72 pub fn get_process(&self) -> Option<ProcessEntryRef> {
73 let process = self.process.read()?;
74 match &*process {
75 ProcessEntry::ThreadGroup(thread_group) => {
76 Some(match thread_group.upgrade() {
80 Some(thread_group) => ProcessEntryRef::Process(thread_group),
81 None => ProcessEntryRef::Zombie,
82 })
83 }
84 ProcessEntry::Zombie(_) => Some(ProcessEntryRef::Zombie),
85 }
86 }
87
88 pub fn get_thread_group(&self) -> Result<Arc<ThreadGroup>, Errno> {
89 match self.get_process() {
90 Some(ProcessEntryRef::Process(tg)) => Ok(tg),
91 _ => error!(ESRCH),
92 }
93 }
94
95 pub fn is_process_group(&self, scope: &RcuReadScope) -> bool {
97 !self.pgid_thread_groups.is_empty(scope)
98 }
99
100 pub fn is_session(&self, scope: &RcuReadScope) -> bool {
102 !self.sid_thread_groups.is_empty(scope)
103 }
104
105 pub fn pgid_thread_groups<'a>(
107 &'a self,
108 scope: &'a RcuReadScope,
109 ) -> impl Iterator<Item = Arc<ThreadGroup>> + 'a {
110 self.pgid_thread_groups.iter(scope).filter_map(|n| n.thread_group.upgrade())
111 }
112
113 pub fn sid_thread_groups<'a>(
115 &'a self,
116 scope: &'a RcuReadScope,
117 ) -> impl Iterator<Item = Arc<ThreadGroup>> + 'a {
118 self.sid_thread_groups.iter(scope).filter_map(|n| n.thread_group.upgrade())
119 }
120
121 pub fn is_process_group_in_session(&self, session: &PidEntry, scope: &RcuReadScope) -> bool {
123 self.pgid_thread_groups(scope).next().is_some_and(|member_tg| {
124 session.sid_thread_groups(scope).any(|tg| Arc::ptr_eq(&tg, &member_tg))
125 })
126 }
127
128 pub fn clear_controlling_terminal(&self, matching: Option<(&Terminal, Option<TerminalSide>)>) {
133 let scope = RcuReadScope::new();
134 for tg in self.sid_thread_groups(&scope) {
135 let mut state = tg.write();
136 if *state.session != *self {
137 continue;
138 }
139 let should_clear = state.controlling_terminal.as_ref().is_some_and(|ct| {
140 let matches = match matching {
141 Some((terminal, Some(side))) => ct.matches(terminal, side),
142 Some((terminal, None)) => std::ptr::eq(terminal, Arc::as_ptr(&ct.terminal)),
143 None => true,
144 };
145 matches && ct.terminal.read().controlling_session().map(Arc::as_ref) != Some(self)
146 });
147 if should_clear {
148 state.controlling_terminal = None;
149 }
150 }
151 }
152
153 pub fn will_become_orphaned_pgrp(
160 &self,
161 scope: &RcuReadScope,
162 ignored_tg: Option<&ThreadGroup>,
163 ) -> bool {
164 for tg in self.pgid_thread_groups(scope) {
165 if ignored_tg.is_some_and(|ignored| std::ptr::eq(tg.as_ref(), ignored)) {
166 continue;
167 }
168
169 let (parent_tg, my_sid) = {
170 let tg_state = tg.read();
171 if !tg_state.is_running() {
172 continue;
173 }
174 (tg_state.parent.as_ref().map(|p| p.upgrade()), tg_state.session.id)
175 };
176
177 let Some(parent_tg) = parent_tg else {
178 continue;
179 };
180
181 if ignored_tg.is_some_and(|ignored| std::ptr::eq(parent_tg.as_ref(), ignored)) {
183 continue;
184 }
185
186 if parent_tg.leader.id == 1 {
188 continue;
189 }
190
191 let (parent_pgid, parent_sid) = {
192 let parent_state = parent_tg.read();
193 if !parent_state.is_running() {
194 continue;
195 }
196 (parent_tg.pgid().id, parent_state.session.id)
197 };
198
199 if parent_pgid != self.id && parent_sid == my_sid {
202 return false;
203 }
204 }
205
206 true
207 }
208
209 pub fn has_stopped_jobs(&self, scope: &RcuReadScope) -> bool {
211 for tg in self.pgid_thread_groups(scope) {
212 let stop_state = tg.load_stopped();
213 if matches!(stop_state, StopState::GroupStopping | StopState::GroupStopped)
214 && tg.read().is_running()
215 {
216 return true;
217 }
218 }
219 false
220 }
221
222 pub fn send_signals_to_pgid(&self, signals: &[Signal]) {
227 let scope = RcuReadScope::new();
228 for &signal in signals {
229 for tg in self.pgid_thread_groups(&scope) {
230 let state = tg.write();
231 if !state.is_exited() {
232 state.send_signal(SignalInfo::kernel(signal));
233 }
234 }
235 }
236 }
237
238 fn attach_thread_group_node(
244 _guard: &PidTableGuard<'_>,
245 list: &RcuIntrusiveList<ThreadGroupLinkNode, ThreadGroupLinkAdapter>,
246 node_slot: &RcuPtr<ThreadGroupLinkNode>,
247 thread_group: &Arc<ThreadGroup>,
248 ) {
249 let scope = RcuReadScope::new();
250 debug_assert!(node_slot.read(&scope).is_null());
251 let node_ptr =
252 Box::into_raw(Box::new(ThreadGroupLinkNode::new(Arc::downgrade(thread_group))));
253 node_slot.assign(node_ptr);
254 unsafe {
257 list.push_back(&scope, RcuPtrRef::new(&scope, node_ptr));
258 }
259 }
260
261 fn detach_thread_group_node(
266 _guard: &PidTableGuard<'_>,
267 list: &RcuIntrusiveList<ThreadGroupLinkNode, ThreadGroupLinkAdapter>,
268 node_slot: &RcuPtr<ThreadGroupLinkNode>,
269 ) -> bool {
270 let scope = RcuReadScope::new();
271 let node_ptr = node_slot.read(&scope);
272 if !node_ptr.is_null() {
273 node_slot.assign(std::ptr::null_mut());
274 unsafe {
277 list.remove(&scope, node_ptr);
278 }
279 rcu_drop(unsafe { Box::from_raw(node_ptr.as_mut_ptr()) });
282 }
283 list.is_empty(&scope)
284 }
285 fn attach_pgid(&self, guard: &PidTableGuard<'_>, thread_group: &Arc<ThreadGroup>) {
287 Self::attach_thread_group_node(
288 guard,
289 &self.pgid_thread_groups,
290 &thread_group.pgrp_node,
291 thread_group,
292 );
293 }
294
295 fn detach_pgid(&self, guard: &PidTableGuard<'_>, thread_group: &ThreadGroup) -> bool {
297 Self::detach_thread_group_node(guard, &self.pgid_thread_groups, &thread_group.pgrp_node)
298 }
299
300 fn attach_sid(&self, guard: &PidTableGuard<'_>, thread_group: &Arc<ThreadGroup>) {
302 Self::attach_thread_group_node(
303 guard,
304 &self.sid_thread_groups,
305 &thread_group.session_node,
306 thread_group,
307 );
308 }
309
310 fn detach_sid(&self, guard: &PidTableGuard<'_>, thread_group: &ThreadGroup) -> bool {
312 Self::detach_thread_group_node(guard, &self.sid_thread_groups, &thread_group.session_node)
313 }
314
315 #[cfg(test)]
316 pub fn new_for_test(id: pid_t) -> Pid {
317 Arc::new(Self::new(id))
318 }
319
320 fn new(id: pid_t) -> Self {
321 Self {
322 id,
323 task: Default::default(),
324 process: Default::default(),
325 pgid_thread_groups: Default::default(),
326 sid_thread_groups: Default::default(),
327 }
328 }
329
330 fn is_empty(&self, scope: &RcuReadScope) -> bool {
331 self.task.strong_count(scope) == 0
332 && self.process.is_none(scope)
333 && self.pgid_thread_groups.is_empty(scope)
334 && self.sid_thread_groups.is_empty(scope)
335 }
336}
337
338impl std::fmt::Display for PidEntry {
339 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
340 write!(f, "{}", self.id)
341 }
342}
343
344impl PartialEq for PidEntry {
345 fn eq(&self, other: &Self) -> bool {
346 std::ptr::eq(self, other)
347 }
348}
349
350impl Eq for PidEntry {}
351
352impl PartialOrd for PidEntry {
353 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
354 Some(self.cmp(other))
355 }
356}
357
358impl Ord for PidEntry {
359 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
360 (self as *const Self).cmp(&(other as *const Self))
361 }
362}
363
364impl std::hash::Hash for PidEntry {
365 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
366 (self as *const Self).hash(state);
367 }
368}
369
370pub enum ProcessEntryRef {
371 Process(Arc<ThreadGroup>),
372 Zombie,
373}
374
375pub type Pid = Arc<PidEntry>;
376
377#[derive(Copy, Clone, Debug, Eq, PartialEq)]
378pub enum TaskEntryScope {
379 Task,
380 ThreadGroup,
381}
382
383#[derive(Clone, Debug)]
385pub struct TaskContainer {
386 pub pid: Pid,
387 pub tid: Pid,
388 pub scope: TaskEntryScope,
389}
390
391impl TaskContainer {
392 pub fn from_task(task: &Task) -> Self {
393 Self { pid: task.pid.clone(), tid: task.tid.clone(), scope: TaskEntryScope::Task }
394 }
395
396 pub fn from_pid(pid: Pid) -> Self {
397 Self { tid: pid.clone(), pid, scope: TaskEntryScope::ThreadGroup }
398 }
399
400 pub fn from_thread_group(pid: Pid, tid: Pid) -> Self {
401 Self { pid, tid, scope: TaskEntryScope::ThreadGroup }
402 }
403
404 pub fn get_task(&self) -> Result<Arc<Task>, Errno> {
405 if let Ok(task) = self.tid.get_task() {
406 return Ok(task);
407 }
408 if self.scope == TaskEntryScope::ThreadGroup && self.tid == self.pid {
409 return self.pid.get_process_task().ok_or_else(|| errno!(ESRCH));
410 }
411 error!(ESRCH)
412 }
413}
414
415pub const RESERVED_PIDS: u32 = 300;
417
418pub const PID_MAX_DEFAULT: pid_t = 1 << 15;
420
421pub const PID_MAX_LIMIT: pid_t = 1 << 22;
423
424pub const PIDS_PER_CPU_DEFAULT: pid_t = 1024;
426
427fn actual_pid_limit(limit: pid_t) -> pid_t {
429 actual_pid_limit_with_cpus(limit, zx::system_get_num_cpus())
430}
431
432fn actual_pid_limit_with_cpus(limit: pid_t, num_cpus: u32) -> pid_t {
434 let cpu_limit = (num_cpus as pid_t).saturating_mul(PIDS_PER_CPU_DEFAULT);
435 limit.max(cpu_limit).min(PID_MAX_LIMIT)
436}
437
438pub struct PidTable {
439 last_pid: AtomicI32,
441
442 num_tasks: AtomicUsize,
444
445 idr: Idr<PidEntry, PidTableLock>,
447
448 thread_group_notifier: RcuOptionBox<std::sync::mpsc::Sender<MemoryAttributionLifecycleEvent>>,
450}
451
452impl Default for PidTable {
453 fn default() -> Self {
454 let idr = Idr::new_cyclic(Some(RESERVED_PIDS));
455 idr.set_max(actual_pid_limit(PID_MAX_DEFAULT) as u32);
456 idr.lock().reserve_id(0);
457 Self {
458 last_pid: AtomicI32::new(0),
459 num_tasks: AtomicUsize::new(0),
460 idr,
461 thread_group_notifier: Default::default(),
462 }
463 }
464}
465
466impl std::fmt::Debug for PidTable {
467 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
468 f.debug_struct("PidTable")
469 .field("last_pid", &self.last_pid.load(Ordering::Relaxed))
470 .finish()
471 }
472}
473
474pub struct PidTableGuard<'a> {
479 table: &'a PidTable,
480 idr: IdrGuard<'a, PidEntry, PidTableLock>,
481}
482
483impl<'a> std::ops::Deref for PidTableGuard<'a> {
484 type Target = PidTable;
485
486 fn deref(&self) -> &Self::Target {
487 self.table
488 }
489}
490
491impl<'a> PidTableGuard<'a> {
492 pub fn allocate_pid(&mut self) -> Result<Pid, Errno> {
494 self.idr
495 .alloc(|id| Arc::new(PidEntry::new(id as pid_t)))
496 .map(|(_, pid)| pid)
497 .ok_or_else(|| errno!(EAGAIN))
498 }
499
500 pub fn add_task(&mut self, task: Arc<Task>) {
501 let scope = RcuReadScope::new();
502 let entry =
503 self.idr.lookup(task.tid.id as u32, &scope).expect("task.tid should be in pid table");
504 assert_eq!(entry.task.strong_count(&scope), 0);
505 if task.is_leader() {
506 assert!(entry.process.is_none(&scope));
507 self.table.last_pid.store(task.tid.id, Ordering::Relaxed);
508 entry
513 .process
514 .update(Some(ProcessEntry::ThreadGroup(Arc::downgrade(task.thread_group()))));
515 }
516 entry.task.update(Arc::downgrade(&task));
517 self.table.num_tasks.fetch_add(1, Ordering::Relaxed);
518
519 if task.is_leader() {
520 if let Some(notifier) = self.table.thread_group_notifier.as_ref(&scope) {
522 let mut tg_state = task.thread_group.write();
523 let _ = notifier.send(MemoryAttributionLifecycleEvent::creation(task.tid.id));
524 tg_state.notifier = Some(notifier.clone());
525 }
526 }
527 }
528
529 fn remove_item<F>(&mut self, pid: &Pid, do_remove: F)
530 where
531 F: FnOnce(&PidEntry),
532 {
533 let scope = RcuReadScope::new();
534 debug_assert_eq!(self.idr.lookup(pid.id as u32, &scope).as_ref(), Some(pid));
535 do_remove(pid);
536 if pid.is_empty(&scope) {
537 self.idr.remove(pid.id as u32);
538 }
539 }
540
541 pub fn remove_task(&mut self, tid: &Pid) {
542 self.table.num_tasks.fetch_sub(1, Ordering::Relaxed);
543 self.remove_item(tid, |entry| {
544 let scope = RcuReadScope::new();
545 assert!(entry.task.strong_count(&scope) > 0);
546 entry.task.update(Weak::new());
547 });
548 }
549
550 pub fn kill_process(&mut self, pid: &Pid, zombie_task: Weak<Task>) {
552 let scope = RcuReadScope::new();
553 debug_assert_eq!(self.idr.lookup(pid.id as u32, &scope).as_ref(), Some(pid));
554 assert!(matches!(pid.process.read().as_deref(), Some(ProcessEntry::ThreadGroup(_))));
555
556 pid.process.update(Some(ProcessEntry::Zombie(zombie_task)));
557 }
558
559 pub fn remove_zombie(&mut self, pid: &Pid) {
560 let scope = RcuReadScope::new();
561
562 self.remove_item(pid, |entry| {
563 assert!(matches!(entry.process.read().as_deref(), Some(ProcessEntry::Zombie(_))));
564 entry.process.update(None);
565 });
566
567 if let Some(notifier) = self.table.thread_group_notifier.as_ref(&scope) {
569 let _ = notifier.send(MemoryAttributionLifecycleEvent::destruction(pid.id));
570 }
571 }
572
573 pub fn attach_pgid(&self, pid: &PidEntry, thread_group: &Arc<ThreadGroup>) {
574 pid.attach_pgid(self, thread_group);
575 }
576
577 pub fn detach_pgid(&mut self, pid: &Pid, thread_group: &ThreadGroup) -> bool {
578 let scope = RcuReadScope::new();
579 let is_empty = pid.detach_pgid(self, thread_group);
580 if pid.is_empty(&scope) && self.idr.lookup(pid.id as u32, &scope).as_ref() == Some(pid) {
581 self.idr.remove(pid.id as u32);
582 }
583 is_empty
584 }
585
586 pub fn attach_sid(&self, pid: &PidEntry, thread_group: &Arc<ThreadGroup>) {
587 pid.attach_sid(self, thread_group);
588 }
589
590 pub fn detach_sid(&mut self, pid: &Pid, thread_group: &ThreadGroup) -> bool {
591 let scope = RcuReadScope::new();
592 let is_empty = pid.detach_sid(self, thread_group);
593 if pid.is_empty(&scope) && self.idr.lookup(pid.id as u32, &scope).as_ref() == Some(pid) {
594 self.idr.remove(pid.id as u32);
595 }
596 is_empty
597 }
598}
599
600impl PidTable {
601 pub fn lock(&self) -> PidTableGuard<'_> {
603 PidTableGuard { table: self, idr: self.idr.lock() }
604 }
605
606 pub fn get(&self, pid: pid_t) -> Result<Pid, Errno> {
607 if pid <= 0 {
608 return error!(ESRCH);
609 }
610 let scope = RcuReadScope::new();
611 self.idr.lookup(pid as u32, &scope).ok_or_else(|| errno!(ESRCH))
612 }
613
614 pub fn set_thread_group_notifier(
615 &self,
616 notifier: std::sync::mpsc::Sender<MemoryAttributionLifecycleEvent>,
617 ) {
618 self.thread_group_notifier.update(Some(notifier));
619 }
620
621 pub fn get_thread_groups<'a>(
622 &'a self,
623 scope: &'a RcuReadScope,
624 ) -> impl Iterator<Item = Arc<ThreadGroup>> + 'a {
625 self.idr.iter(&scope).flat_map(move |(_, entry)| {
626 entry
627 .process
628 .as_ref(&scope)
629 .and_then(ProcessEntry::thread_group)
630 .and_then(|g| g.upgrade())
631 })
632 }
633
634 pub fn num_tasks(&self) -> usize {
636 self.num_tasks.load(Ordering::Relaxed)
637 }
638
639 pub fn process_ids(&self) -> Vec<pid_t> {
641 let scope = RcuReadScope::new();
642 self.idr
643 .iter(&scope)
644 .flat_map(|(_, entry)| entry.process.is_some(&scope).then_some(entry.id))
645 .collect()
646 }
647
648 pub fn running_task_ids<'a>(
650 &'a self,
651 scope: &'a RcuReadScope,
652 ) -> impl Iterator<Item = &'a Pid> {
653 self.idr
654 .iter(scope)
655 .map(|(_, entry)| entry)
656 .filter(|entry| entry.task.strong_count(scope) > 0)
657 }
658
659 pub fn last_pid(&self) -> pid_t {
660 self.last_pid.load(Ordering::Relaxed)
661 }
662
663 pub fn max(&self) -> pid_t {
665 self.idr.max() as pid_t
666 }
667
668 pub fn set_max(&self, max: pid_t) {
670 self.idr.set_max(actual_pid_limit(max) as u32);
671 }
672}
673
674#[cfg(test)]
675mod tests {
676 use super::*;
677 use crate::task::ExitStatus;
678 use crate::testing::spawn_kernel_and_run;
679 use starnix_types::ownership::Releasable;
680 use starnix_uapi::signals::{SIGCHLD, SIGCONT};
681 use starnix_uapi::user_address::UserRef;
682 use starnix_uapi::{CLONE_CHILD_SETTID, CLONE_SIGHAND, CLONE_THREAD, CLONE_VM};
683 use std::collections::HashSet;
684 use std::sync::atomic::AtomicBool;
685
686 #[test]
687 fn test_pid_table_allocation() {
688 let table = PidTable::default();
689 let pid1 = table.lock().allocate_pid().unwrap();
690 assert_eq!(pid1.id, 1);
691
692 let pid2 = table.lock().allocate_pid().unwrap();
693 assert_eq!(pid2.id, 2);
694
695 assert_eq!(table.get(1).unwrap().id, 1);
696 assert_eq!(table.get(2).unwrap().id, 2);
697 assert!(table.get(0).is_err());
698 assert!(table.get(-1).is_err());
699 assert!(table.get(3).is_err());
700 }
701
702 #[test]
703 fn test_pid_table_lock_guard() {
704 let table = PidTable::default();
705 let pid1 = {
706 let mut guard = table.lock();
707 let pid = guard.allocate_pid().unwrap();
708 assert_eq!(pid.id, 1);
709 pid
710 };
711 assert_eq!(table.get(1).unwrap(), pid1);
712 }
713
714 #[test]
715 fn test_pid_table_empty_state() {
716 let table = PidTable::default();
717 assert_eq!(table.last_pid(), 0);
718 assert_eq!(table.num_tasks(), 0);
719 assert_eq!(table.process_ids().len(), 0);
720 let scope = RcuReadScope::new();
721 assert_eq!(table.running_task_ids(&scope).count(), 0);
722 }
723
724 #[test]
725 fn test_pid_table_max_and_wrap() {
726 let table = PidTable::default();
727 assert_eq!(table.max(), actual_pid_limit(PID_MAX_DEFAULT));
728
729 let max = table.max();
731 for expected in 1..=max {
732 let pid = table.lock().allocate_pid().unwrap();
733 assert_eq!(pid.id, expected);
734 }
735
736 assert_eq!(table.lock().allocate_pid().unwrap_err(), errno!(EAGAIN));
738
739 table.idr.lock().remove(2);
741 table.idr.lock().remove(302);
742
743 let pid = table.lock().allocate_pid().unwrap();
746 assert_eq!(pid.id, 302);
747
748 assert_eq!(table.lock().allocate_pid().unwrap_err(), errno!(EAGAIN));
750
751 table.idr.lock().remove(300);
753 let pid = table.lock().allocate_pid().unwrap();
754 assert_eq!(pid.id, 300);
755
756 let new_max = max + 10;
758 table.set_max(new_max);
759 assert_eq!(table.max(), new_max);
760 let pid = table.lock().allocate_pid().unwrap();
761 assert_eq!(pid.id, max + 1);
762 }
763
764 #[test]
765 fn test_actual_pid_limit() {
766 assert_eq!(actual_pid_limit_with_cpus(PID_MAX_DEFAULT, 1), PID_MAX_DEFAULT);
768 assert_eq!(actual_pid_limit_with_cpus(500, 1), 1024);
769
770 assert_eq!(actual_pid_limit_with_cpus(PID_MAX_DEFAULT, 64), 65536);
772 assert_eq!(actual_pid_limit_with_cpus(100_000, 64), 100_000);
773
774 assert_eq!(actual_pid_limit_with_cpus(PID_MAX_LIMIT + 1000, 1), PID_MAX_LIMIT);
776 assert_eq!(actual_pid_limit_with_cpus(PID_MAX_DEFAULT, 10_000), PID_MAX_LIMIT);
777 }
778
779 #[test]
780 fn test_get_process_after_thread_group_release() {
781 let pid = PidEntry::new_for_test(1);
786 pid.process.update(Some(ProcessEntry::ThreadGroup(Weak::new())));
787
788 assert!(matches!(pid.get_process(), Some(ProcessEntryRef::Zombie)));
789 }
790
791 #[::fuchsia::test]
792 async fn test_pid_table_last_pid_on_thread_group() {
793 spawn_kernel_and_run(async |current_task| {
794 let kernel = current_task.kernel();
795 let initial_last_pid = kernel.pids.last_pid();
796
797 let _allocated = kernel.pids.lock().allocate_pid().unwrap();
799 assert_eq!(kernel.pids.last_pid(), initial_last_pid);
800
801 let _thread = current_task.clone_task_for_test(
803 (CLONE_THREAD | CLONE_VM | CLONE_SIGHAND) as u64,
804 Some(SIGCHLD),
805 );
806 assert_eq!(kernel.pids.last_pid(), initial_last_pid);
807
808 let child = current_task.clone_task_for_test(0, Some(SIGCHLD));
810 assert_eq!(kernel.pids.last_pid(), child.get_pid());
811 })
812 .await;
813 }
814
815 #[::fuchsia::test]
816 async fn test_pid_entry_intrusive_lists() {
817 spawn_kernel_and_run(async |current_task| {
818 let kernel = current_task.kernel();
819 let pid_entry = kernel.pids.lock().allocate_pid().unwrap();
820 let current_pid = kernel.pids.get(current_task.get_pid()).unwrap();
821 let scope = RcuReadScope::new();
822
823 assert!(!pid_entry.is_process_group(&scope));
824 assert!(!pid_entry.is_session(&scope));
825
826 let guard = kernel.pids.lock();
828 current_pid.detach_pgid(&guard, current_task.thread_group());
829 current_pid.detach_sid(&guard, current_task.thread_group());
830 pid_entry.attach_pgid(&guard, current_task.thread_group());
831 pid_entry.attach_sid(&guard, current_task.thread_group());
832
833 let pgid_members: Vec<_> =
835 pid_entry.pgid_thread_groups(&scope).map(|tg| tg.leader.id).collect();
836 assert_eq!(pgid_members, vec![current_task.get_pid()]);
837
838 let sid_members: Vec<_> =
840 pid_entry.sid_thread_groups(&scope).map(|tg| tg.leader.id).collect();
841 assert_eq!(sid_members, vec![current_task.get_pid()]);
842
843 let pgid_empty = pid_entry.detach_pgid(&guard, current_task.thread_group());
845 assert!(pgid_empty);
846 let sid_empty = pid_entry.detach_sid(&guard, current_task.thread_group());
847 assert!(sid_empty);
848 current_pid.attach_pgid(&guard, current_task.thread_group());
849 current_pid.attach_sid(&guard, current_task.thread_group());
850 })
851 .await;
852 }
853
854 #[::fuchsia::test]
855 async fn test_pid_entry_empty_traversal() {
856 spawn_kernel_and_run(async |current_task| {
857 let kernel = current_task.kernel();
858 let pid_entry = kernel.pids.lock().allocate_pid().unwrap();
859 let scope = RcuReadScope::new();
860
861 assert!(!pid_entry.is_process_group(&scope));
863 assert!(!pid_entry.is_session(&scope));
864 assert!(pid_entry.pgid_thread_groups(&scope).next().is_none());
865 assert!(pid_entry.sid_thread_groups(&scope).next().is_none());
866 })
867 .await;
868 }
869
870 #[::fuchsia::test]
871 async fn test_pid_entry_multiple_tasks_ordered_and_reverse_detach() {
872 spawn_kernel_and_run(async |current_task| {
873 let kernel = current_task.kernel();
874 let pid_entry = kernel.pids.lock().allocate_pid().unwrap();
875 let scope = RcuReadScope::new();
876
877 let child1 = current_task.clone_task_for_test(0, Some(SIGCHLD));
878 let child2 = current_task.clone_task_for_test(0, Some(SIGCHLD));
879 let child3 = current_task.clone_task_for_test(0, Some(SIGCHLD));
880
881 let guard = kernel.pids.lock();
882 let current_pid = kernel.pids.get(current_task.get_pid()).unwrap();
883 current_pid.detach_pgid(&guard, child1.thread_group());
884 current_pid.detach_pgid(&guard, child2.thread_group());
885 current_pid.detach_pgid(&guard, child3.thread_group());
886
887 pid_entry.attach_pgid(&guard, child1.thread_group());
888 pid_entry.attach_pgid(&guard, child2.thread_group());
889 pid_entry.attach_pgid(&guard, child3.thread_group());
890
891 let initial: Vec<_> =
892 pid_entry.pgid_thread_groups(&scope).map(|tg| tg.leader.id).collect();
893 assert_eq!(initial, vec![child1.get_pid(), child2.get_pid(), child3.get_pid()]);
894
895 let is_empty = pid_entry.detach_pgid(&guard, child3.thread_group());
897 assert!(!is_empty);
898 let state1: Vec<_> =
899 pid_entry.pgid_thread_groups(&scope).map(|tg| tg.leader.id).collect();
900 assert_eq!(state1, vec![child1.get_pid(), child2.get_pid()]);
901
902 let is_empty = pid_entry.detach_pgid(&guard, child2.thread_group());
904 assert!(!is_empty);
905 let state2: Vec<_> =
906 pid_entry.pgid_thread_groups(&scope).map(|tg| tg.leader.id).collect();
907 assert_eq!(state2, vec![child1.get_pid()]);
908
909 let is_empty = pid_entry.detach_pgid(&guard, child1.thread_group());
911 assert!(is_empty);
912 assert!(pid_entry.pgid_thread_groups(&scope).next().is_none());
913
914 current_pid.attach_pgid(&guard, child1.thread_group());
915 current_pid.attach_pgid(&guard, child2.thread_group());
916 current_pid.attach_pgid(&guard, child3.thread_group());
917 })
918 .await;
919 }
920
921 #[::fuchsia::test]
922 async fn test_pid_entry_head_detach() {
923 spawn_kernel_and_run(async |current_task| {
924 let kernel = current_task.kernel();
925 let pid_entry = kernel.pids.lock().allocate_pid().unwrap();
926 let scope = RcuReadScope::new();
927
928 let child1 = current_task.clone_task_for_test(0, Some(SIGCHLD));
929 let child2 = current_task.clone_task_for_test(0, Some(SIGCHLD));
930 let child3 = current_task.clone_task_for_test(0, Some(SIGCHLD));
931
932 let guard = kernel.pids.lock();
933 let current_pid = kernel.pids.get(current_task.get_pid()).unwrap();
934 current_pid.detach_pgid(&guard, child1.thread_group());
935 current_pid.detach_pgid(&guard, child2.thread_group());
936 current_pid.detach_pgid(&guard, child3.thread_group());
937
938 pid_entry.attach_pgid(&guard, child1.thread_group());
939 pid_entry.attach_pgid(&guard, child2.thread_group());
940 pid_entry.attach_pgid(&guard, child3.thread_group());
941
942 let is_empty = pid_entry.detach_pgid(&guard, child1.thread_group());
944 assert!(!is_empty);
945 let state1: Vec<_> =
946 pid_entry.pgid_thread_groups(&scope).map(|tg| tg.leader.id).collect();
947 assert_eq!(state1, vec![child2.get_pid(), child3.get_pid()]);
948
949 let is_empty = pid_entry.detach_pgid(&guard, child2.thread_group());
951 assert!(!is_empty);
952 let state2: Vec<_> =
953 pid_entry.pgid_thread_groups(&scope).map(|tg| tg.leader.id).collect();
954 assert_eq!(state2, vec![child3.get_pid()]);
955
956 let is_empty = pid_entry.detach_pgid(&guard, child3.thread_group());
958 assert!(is_empty);
959 assert!(pid_entry.pgid_thread_groups(&scope).next().is_none());
960
961 current_pid.attach_pgid(&guard, child1.thread_group());
962 current_pid.attach_pgid(&guard, child2.thread_group());
963 current_pid.attach_pgid(&guard, child3.thread_group());
964 })
965 .await;
966 }
967
968 #[::fuchsia::test]
969 async fn test_pid_entry_middle_detach() {
970 spawn_kernel_and_run(async |current_task| {
971 let kernel = current_task.kernel();
972 let pid_entry = kernel.pids.lock().allocate_pid().unwrap();
973 let scope = RcuReadScope::new();
974
975 let child1 = current_task.clone_task_for_test(0, Some(SIGCHLD));
976 let child2 = current_task.clone_task_for_test(0, Some(SIGCHLD));
977 let child3 = current_task.clone_task_for_test(0, Some(SIGCHLD));
978
979 let guard = kernel.pids.lock();
980 let current_pid = kernel.pids.get(current_task.get_pid()).unwrap();
981 current_pid.detach_pgid(&guard, child1.thread_group());
982 current_pid.detach_pgid(&guard, child2.thread_group());
983 current_pid.detach_pgid(&guard, child3.thread_group());
984
985 pid_entry.attach_pgid(&guard, child1.thread_group());
986 pid_entry.attach_pgid(&guard, child2.thread_group());
987 pid_entry.attach_pgid(&guard, child3.thread_group());
988
989 let is_empty = pid_entry.detach_pgid(&guard, child2.thread_group());
991 assert!(!is_empty);
992 let state1: Vec<_> =
993 pid_entry.pgid_thread_groups(&scope).map(|tg| tg.leader.id).collect();
994 assert_eq!(state1, vec![child1.get_pid(), child3.get_pid()]);
995
996 let is_empty = pid_entry.detach_pgid(&guard, child3.thread_group());
998 assert!(!is_empty);
999 let state2: Vec<_> =
1000 pid_entry.pgid_thread_groups(&scope).map(|tg| tg.leader.id).collect();
1001 assert_eq!(state2, vec![child1.get_pid()]);
1002
1003 let is_empty = pid_entry.detach_pgid(&guard, child1.thread_group());
1005 assert!(is_empty);
1006 assert!(pid_entry.pgid_thread_groups(&scope).next().is_none());
1007
1008 current_pid.attach_pgid(&guard, child1.thread_group());
1009 current_pid.attach_pgid(&guard, child2.thread_group());
1010 current_pid.attach_pgid(&guard, child3.thread_group());
1011 })
1012 .await;
1013 }
1014
1015 #[::fuchsia::test]
1016 async fn test_pid_table_reclaims_pid_when_last_pgid_and_sid_task_detaches() {
1017 spawn_kernel_and_run(async |current_task| {
1018 let kernel = current_task.kernel();
1019
1020 let leader = current_task.clone_task_for_test(0, Some(SIGCHLD));
1022 leader.thread_group().setsid().expect("setsid leader");
1023 let leader_pid_id = leader.get_pid();
1024
1025 let member = leader.clone_task_for_test(0, Some(SIGCHLD));
1027
1028 leader.thread_group().kill(ExitStatus::Exit(0), None);
1030 drop(leader);
1031 {
1032 let mut pids = kernel.pids.lock();
1033 let zombie = current_task
1034 .thread_group()
1035 .write()
1036 .zombie_children
1037 .pop()
1038 .expect("leader zombie");
1039 zombie.release(&mut pids);
1040 }
1041
1042 assert!(kernel.pids.get(leader_pid_id).is_ok());
1044
1045 member.thread_group().setsid().expect("setsid member");
1047
1048 assert_eq!(kernel.pids.get(leader_pid_id), error!(ESRCH));
1050 })
1051 .await;
1052 }
1053
1054 #[::fuchsia::test]
1055 async fn test_pid_entry_reattach_after_detach() {
1056 spawn_kernel_and_run(async |current_task| {
1057 let kernel = current_task.kernel();
1058 let pid_entry = kernel.pids.lock().allocate_pid().unwrap();
1059 let scope = RcuReadScope::new();
1060
1061 let child1 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1062 let child2 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1063 let child3 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1064
1065 let guard = kernel.pids.lock();
1066 let current_pid = kernel.pids.get(current_task.get_pid()).unwrap();
1067 current_pid.detach_pgid(&guard, child1.thread_group());
1068 current_pid.detach_pgid(&guard, child2.thread_group());
1069 current_pid.detach_pgid(&guard, child3.thread_group());
1070
1071 pid_entry.attach_pgid(&guard, child1.thread_group());
1072 pid_entry.attach_pgid(&guard, child2.thread_group());
1073 pid_entry.attach_pgid(&guard, child3.thread_group());
1074
1075 let is_empty = pid_entry.detach_pgid(&guard, child2.thread_group());
1077 assert!(!is_empty);
1078 let after_detach: Vec<_> =
1079 pid_entry.pgid_thread_groups(&scope).map(|tg| tg.leader.id).collect();
1080 assert_eq!(after_detach, vec![child1.get_pid(), child3.get_pid()]);
1081
1082 pid_entry.attach_pgid(&guard, child2.thread_group());
1084
1085 let reattached: Vec<_> =
1087 pid_entry.pgid_thread_groups(&scope).take(10).map(|tg| tg.leader.id).collect();
1088 assert_eq!(reattached, vec![child1.get_pid(), child3.get_pid(), child2.get_pid()]);
1089
1090 pid_entry.detach_pgid(&guard, child1.thread_group());
1091 pid_entry.detach_pgid(&guard, child3.thread_group());
1092 pid_entry.detach_pgid(&guard, child2.thread_group());
1093 current_pid.attach_pgid(&guard, child1.thread_group());
1094 current_pid.attach_pgid(&guard, child2.thread_group());
1095 current_pid.attach_pgid(&guard, child3.thread_group());
1096 })
1097 .await;
1098 }
1099
1100 #[::fuchsia::test]
1101 async fn test_pid_entry_move_between_groups() {
1102 spawn_kernel_and_run(async |current_task| {
1103 let kernel = current_task.kernel();
1104 let (pid_entry1, pid_entry2) = {
1105 let mut guard = kernel.pids.lock();
1106 (guard.allocate_pid().unwrap(), guard.allocate_pid().unwrap())
1107 };
1108
1109 let child1 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1110 let child2 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1111 let child3 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1112
1113 let scope = RcuReadScope::new();
1114
1115 let guard = kernel.pids.lock();
1116 let current_pid = kernel.pids.get(current_task.get_pid()).unwrap();
1117 current_pid.detach_pgid(&guard, child1.thread_group());
1118 current_pid.detach_pgid(&guard, child2.thread_group());
1119 current_pid.detach_pgid(&guard, child3.thread_group());
1120
1121 pid_entry1.attach_pgid(&guard, child1.thread_group());
1122 pid_entry1.attach_pgid(&guard, child2.thread_group());
1123 pid_entry1.attach_pgid(&guard, child3.thread_group());
1124
1125 pid_entry1.detach_pgid(&guard, child2.thread_group());
1127 pid_entry2.attach_pgid(&guard, child2.thread_group());
1128
1129 let group1_members: Vec<_> =
1130 pid_entry1.pgid_thread_groups(&scope).take(10).map(|tg| tg.leader.id).collect();
1131 assert_eq!(group1_members, vec![child1.get_pid(), child3.get_pid()]);
1132
1133 let group2_members: Vec<_> =
1134 pid_entry2.pgid_thread_groups(&scope).take(10).map(|tg| tg.leader.id).collect();
1135 assert_eq!(group2_members, vec![child2.get_pid()]);
1136
1137 pid_entry1.detach_pgid(&guard, child1.thread_group());
1138 pid_entry1.detach_pgid(&guard, child3.thread_group());
1139 pid_entry2.detach_pgid(&guard, child2.thread_group());
1140 current_pid.attach_pgid(&guard, child1.thread_group());
1141 current_pid.attach_pgid(&guard, child2.thread_group());
1142 current_pid.attach_pgid(&guard, child3.thread_group());
1143 })
1144 .await;
1145 }
1146
1147 #[::fuchsia::test]
1148 async fn test_pid_entry_singleton_reattach_and_detach() {
1149 spawn_kernel_and_run(async |current_task| {
1150 let kernel = current_task.kernel();
1151 let pid_entry = kernel.pids.lock().allocate_pid().unwrap();
1152 let scope = RcuReadScope::new();
1153
1154 let child1 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1155
1156 let guard = kernel.pids.lock();
1157 let current_pid = kernel.pids.get(current_task.get_pid()).unwrap();
1158 current_pid.detach_pgid(&guard, child1.thread_group());
1159
1160 pid_entry.attach_pgid(&guard, child1.thread_group());
1162 assert_eq!(
1163 pid_entry.pgid_thread_groups(&scope).map(|tg| tg.leader.id).collect::<Vec<_>>(),
1164 vec![child1.get_pid()]
1165 );
1166
1167 let is_empty = pid_entry.detach_pgid(&guard, child1.thread_group());
1169 assert!(is_empty);
1170
1171 pid_entry.attach_pgid(&guard, child1.thread_group());
1173 assert_eq!(
1174 pid_entry.pgid_thread_groups(&scope).map(|tg| tg.leader.id).collect::<Vec<_>>(),
1175 vec![child1.get_pid()]
1176 );
1177
1178 let is_empty = pid_entry.detach_pgid(&guard, child1.thread_group());
1180 assert!(is_empty);
1181 current_pid.attach_pgid(&guard, child1.thread_group());
1182 })
1183 .await;
1184 }
1185
1186 #[::fuchsia::test]
1187 async fn test_pid_entry_sid_tasks_adversarial() {
1188 spawn_kernel_and_run(async |current_task| {
1189 let kernel = current_task.kernel();
1190 let (pid_entry1, pid_entry2) = {
1191 let mut guard = kernel.pids.lock();
1192 (guard.allocate_pid().unwrap(), guard.allocate_pid().unwrap())
1193 };
1194 let scope = RcuReadScope::new();
1195
1196 let child1 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1197 let child2 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1198 let child3 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1199
1200 let guard = kernel.pids.lock();
1201 let current_pid = kernel.pids.get(current_task.get_pid()).unwrap();
1202 current_pid.detach_sid(&guard, child1.thread_group());
1203 current_pid.detach_sid(&guard, child2.thread_group());
1204 current_pid.detach_sid(&guard, child3.thread_group());
1205
1206 pid_entry1.attach_sid(&guard, child1.thread_group());
1207 pid_entry1.attach_sid(&guard, child2.thread_group());
1208 pid_entry1.attach_sid(&guard, child3.thread_group());
1209
1210 let initial: Vec<_> =
1212 pid_entry1.sid_thread_groups(&scope).map(|tg| tg.leader.id).collect();
1213 assert_eq!(initial, vec![child1.get_pid(), child2.get_pid(), child3.get_pid()]);
1214
1215 let is_empty = pid_entry1.detach_sid(&guard, child2.thread_group());
1217 assert!(!is_empty);
1218 let state1: Vec<_> =
1219 pid_entry1.sid_thread_groups(&scope).map(|tg| tg.leader.id).collect();
1220 assert_eq!(state1, vec![child1.get_pid(), child3.get_pid()]);
1221
1222 pid_entry2.attach_sid(&guard, child2.thread_group());
1224 let session1_members: Vec<_> =
1225 pid_entry1.sid_thread_groups(&scope).take(10).map(|tg| tg.leader.id).collect();
1226 let session2_members: Vec<_> =
1227 pid_entry2.sid_thread_groups(&scope).take(10).map(|tg| tg.leader.id).collect();
1228 assert_eq!(session1_members, vec![child1.get_pid(), child3.get_pid()]);
1229 assert_eq!(session2_members, vec![child2.get_pid()]);
1230
1231 assert!(!pid_entry1.detach_sid(&guard, child3.thread_group()));
1233 assert!(pid_entry1.detach_sid(&guard, child1.thread_group()));
1234 assert!(pid_entry1.sid_thread_groups(&scope).next().is_none());
1235 assert!(pid_entry2.detach_sid(&guard, child2.thread_group()));
1236
1237 current_pid.attach_sid(&guard, child1.thread_group());
1238 current_pid.attach_sid(&guard, child2.thread_group());
1239 current_pid.attach_sid(&guard, child3.thread_group());
1240 })
1241 .await;
1242 }
1243
1244 #[::fuchsia::test]
1245 async fn test_pid_entry_signal_delivery_under_pid_table_lock() {
1246 spawn_kernel_and_run(async |current_task| {
1247 let kernel = current_task.kernel();
1248 let pid_entry = kernel.pids.lock().allocate_pid().unwrap();
1249
1250 let child1 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1251 let child2 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1252
1253 {
1254 let guard = kernel.pids.lock();
1255 let current_pid = kernel.pids.get(current_task.get_pid()).unwrap();
1256 current_pid.detach_pgid(&guard, child1.thread_group());
1257 current_pid.detach_pgid(&guard, child2.thread_group());
1258
1259 pid_entry.attach_pgid(&guard, child1.thread_group());
1260 pid_entry.attach_pgid(&guard, child2.thread_group());
1261
1262 pid_entry.send_signals_to_pgid(&[SIGCONT]);
1265 }
1266
1267 pid_entry.send_signals_to_pgid(&[SIGCONT]);
1269
1270 let guard = kernel.pids.lock();
1271 let current_pid = kernel.pids.get(current_task.get_pid()).unwrap();
1272 pid_entry.detach_pgid(&guard, child1.thread_group());
1273 pid_entry.detach_pgid(&guard, child2.thread_group());
1274 current_pid.attach_pgid(&guard, child1.thread_group());
1275 current_pid.attach_pgid(&guard, child2.thread_group());
1276 })
1277 .await;
1278 }
1279
1280 #[::fuchsia::test]
1281 async fn test_pid_entry_concurrent_rcu_traversal_under_mutation() {
1282 spawn_kernel_and_run(async |current_task| {
1283 let kernel = current_task.kernel();
1284 let pid_entry = kernel.pids.lock().allocate_pid().unwrap();
1285
1286 let child1 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1287 let child2 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1288 let child3 = current_task.clone_task_for_test(0, Some(SIGCHLD));
1289
1290 {
1291 let guard = kernel.pids.lock();
1292 let current_pid = kernel.pids.get(current_task.get_pid()).unwrap();
1293 current_pid.detach_pgid(&guard, child1.thread_group());
1294 current_pid.detach_pgid(&guard, child2.thread_group());
1295 current_pid.detach_pgid(&guard, child3.thread_group());
1296 current_pid.detach_sid(&guard, child1.thread_group());
1297 current_pid.detach_sid(&guard, child2.thread_group());
1298 current_pid.detach_sid(&guard, child3.thread_group());
1299 }
1300
1301 let valid_pids: HashSet<i32> =
1302 [child1.get_pid(), child2.get_pid(), child3.get_pid()].into_iter().collect();
1303
1304 let running = Arc::new(AtomicBool::new(true));
1305
1306 let r1_pid = pid_entry.clone();
1308 let r1_running = Arc::clone(&running);
1309 let r1_pids = valid_pids.clone();
1310 let reader1 = std::thread::spawn(move || {
1311 while r1_running.load(Ordering::Relaxed) {
1312 let scope = RcuReadScope::new();
1313 let mut count = 0;
1314 for tg in r1_pid.pgid_thread_groups(&scope) {
1315 count += 1;
1316 assert!(r1_pids.contains(&tg.leader.id));
1317 assert!(
1318 count <= 3,
1319 "Infinite loop or cycle detected in pgid_thread_groups"
1320 );
1321 }
1322 }
1323 });
1324
1325 let r2_pid = pid_entry.clone();
1327 let r2_running = Arc::clone(&running);
1328 let r2_pids = valid_pids.clone();
1329 let reader2 = std::thread::spawn(move || {
1330 while r2_running.load(Ordering::Relaxed) {
1331 let scope = RcuReadScope::new();
1332 let tgs: Vec<_> = r2_pid.sid_thread_groups(&scope).take(10).collect();
1333 assert!(tgs.len() <= 3, "Infinite loop or cycle detected in sid_thread_groups");
1334 for tg in tgs {
1335 assert!(r2_pids.contains(&tg.leader.id));
1336 }
1337 }
1338 });
1339
1340 let r3_pid = pid_entry.clone();
1342 let r3_running = Arc::clone(&running);
1343 let signal_thread = std::thread::spawn(move || {
1344 while r3_running.load(Ordering::Relaxed) {
1345 r3_pid.send_signals_to_pgid(&[SIGCONT]);
1346 }
1347 });
1348
1349 for _ in 0..150 {
1351 {
1352 let guard = kernel.pids.lock();
1353 pid_entry.attach_pgid(&guard, child1.thread_group());
1354 pid_entry.attach_pgid(&guard, child2.thread_group());
1355 pid_entry.attach_sid(&guard, child2.thread_group());
1356 pid_entry.attach_sid(&guard, child3.thread_group());
1357 }
1358
1359 {
1360 let guard = kernel.pids.lock();
1361 pid_entry.detach_pgid(&guard, child2.thread_group());
1362 pid_entry.attach_pgid(&guard, child3.thread_group());
1363 pid_entry.detach_sid(&guard, child2.thread_group());
1364 }
1365
1366 {
1367 let guard = kernel.pids.lock();
1368 pid_entry.detach_pgid(&guard, child1.thread_group());
1369 pid_entry.detach_pgid(&guard, child3.thread_group());
1370 pid_entry.detach_sid(&guard, child3.thread_group());
1371 }
1372 }
1373
1374 running.store(false, Ordering::Relaxed);
1375 reader1.join().expect("Reader 1 join failed");
1376 reader2.join().expect("Reader 2 join failed");
1377 signal_thread.join().expect("Signal thread join failed");
1378
1379 let scope = RcuReadScope::new();
1381 assert!(pid_entry.pgid_thread_groups(&scope).next().is_none());
1382 assert!(pid_entry.sid_thread_groups(&scope).next().is_none());
1383
1384 let guard = kernel.pids.lock();
1385 let current_pid = kernel.pids.get(current_task.get_pid()).unwrap();
1386 current_pid.attach_pgid(&guard, child1.thread_group());
1387 current_pid.attach_pgid(&guard, child2.thread_group());
1388 current_pid.attach_pgid(&guard, child3.thread_group());
1389 current_pid.attach_sid(&guard, child1.thread_group());
1390 current_pid.attach_sid(&guard, child2.thread_group());
1391 current_pid.attach_sid(&guard, child3.thread_group());
1392 })
1393 .await;
1394 }
1395
1396 #[::fuchsia::test]
1397 async fn test_pid_table_num_tasks_tracks_live_tasks() {
1398 spawn_kernel_and_run(async |current_task| {
1399 let kernel = current_task.kernel();
1400 let scope = RcuReadScope::new();
1401 let initial_tasks = kernel.pids.num_tasks();
1402 let initial_processes = kernel.pids.process_ids().len();
1403 assert!(initial_tasks >= 1);
1404 assert_eq!(initial_tasks, kernel.pids.running_task_ids(&scope).count());
1405
1406 let _allocated = kernel.pids.lock().allocate_pid().unwrap();
1408 assert_eq!(kernel.pids.num_tasks(), initial_tasks);
1409
1410 let thread = current_task.clone_task_for_test(
1413 (CLONE_THREAD | CLONE_VM | CLONE_SIGHAND) as u64,
1414 Some(SIGCHLD),
1415 );
1416 assert_eq!(kernel.pids.num_tasks(), initial_tasks + 1);
1417 assert_eq!(kernel.pids.num_tasks(), kernel.pids.running_task_ids(&scope).count());
1418 std::mem::drop(thread);
1419 assert_eq!(kernel.pids.num_tasks(), initial_tasks);
1420 assert_eq!(kernel.pids.num_tasks(), kernel.pids.running_task_ids(&scope).count());
1421
1422 let child = current_task.clone_task_for_test(0, Some(SIGCHLD));
1424 assert_eq!(kernel.pids.num_tasks(), initial_tasks + 1);
1425 assert_eq!(kernel.pids.num_tasks(), kernel.pids.running_task_ids(&scope).count());
1426
1427 std::mem::drop(child);
1431 assert_eq!(kernel.pids.num_tasks(), initial_tasks);
1432 assert_eq!(kernel.pids.num_tasks(), kernel.pids.running_task_ids(&scope).count());
1433 assert_eq!(kernel.pids.process_ids().len(), initial_processes + 1);
1434
1435 let zombies: Vec<_> =
1438 current_task.thread_group().write().zombie_children.drain(..).collect();
1439 assert_eq!(zombies.len(), 1);
1440 {
1441 let mut pids = kernel.pids.lock();
1442 for zombie in zombies {
1443 zombie.release(&mut pids);
1444 }
1445 }
1446 assert_eq!(kernel.pids.num_tasks(), initial_tasks);
1447 assert_eq!(kernel.pids.process_ids().len(), initial_processes);
1448 })
1449 .await;
1450 }
1451
1452 #[::fuchsia::test]
1453 async fn test_pid_table_num_tasks_failed_clone_rollback() {
1454 spawn_kernel_and_run(async |current_task| {
1455 let kernel = current_task.kernel();
1456 let scope = RcuReadScope::new();
1457 let initial_tasks = kernel.pids.num_tasks();
1458 let initial_processes = kernel.pids.process_ids().len();
1459 assert!(initial_tasks >= 1);
1460 assert_eq!(initial_tasks, kernel.pids.running_task_ids(&scope).count());
1461
1462 let Err(err) = current_task.clone_task(
1466 CLONE_CHILD_SETTID as u64,
1467 Some(SIGCHLD),
1468 UserRef::default(),
1469 UserRef::default(),
1470 UserRef::default(),
1471 ) else {
1472 panic!("clone_task with null user_child_tid should fail");
1473 };
1474 assert_eq!(err, errno!(EFAULT));
1475 assert_eq!(kernel.pids.num_tasks(), initial_tasks);
1476 assert_eq!(kernel.pids.num_tasks(), kernel.pids.running_task_ids(&scope).count());
1477
1478 let Err(err) = current_task.clone_task(
1479 (CLONE_THREAD | CLONE_VM | CLONE_SIGHAND | CLONE_CHILD_SETTID) as u64,
1480 Some(SIGCHLD),
1481 UserRef::default(),
1482 UserRef::default(),
1483 UserRef::default(),
1484 ) else {
1485 panic!("thread clone_task with null user_child_tid should fail");
1486 };
1487 assert_eq!(err, errno!(EFAULT));
1488 assert_eq!(kernel.pids.num_tasks(), initial_tasks);
1489 assert_eq!(kernel.pids.num_tasks(), kernel.pids.running_task_ids(&scope).count());
1490
1491 let zombies: Vec<_> =
1492 current_task.thread_group().write().zombie_children.drain(..).collect();
1493 {
1494 let mut pids = kernel.pids.lock();
1495 for zombie in zombies {
1496 zombie.release(&mut pids);
1497 }
1498 }
1499 assert_eq!(kernel.pids.num_tasks(), initial_tasks);
1500 assert_eq!(kernel.pids.process_ids().len(), initial_processes);
1501 })
1502 .await;
1503 }
1504}