1use crate::signals::{SignalInfo, send_freeze_signal};
11use crate::task::{Kernel, Pid, ThreadGroup, WaitQueue, Waiter};
12use crate::vfs::{FsStr, FsString, PathBuilder};
13use starnix_logging::{CATEGORY_STARNIX, log_warn, track_stub};
14use starnix_sync::{
15 CgroupChildrenLock, CgroupPidTableLock, CgroupStateLock, CgroupV1Level, LockDepGuard,
16 LockDepMutex, allow_subclass,
17};
18use starnix_uapi::errors::Errno;
19use starnix_uapi::signals::SIGKILL;
20use starnix_uapi::{errno, error, pid_t};
21use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map, hash_map};
22use std::ops::{Deref, DerefMut};
23use std::sync::atomic::{AtomicU64, Ordering};
24use std::sync::{Arc, Weak};
25
26use crate::signals::KernelSignal;
27use zx;
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub enum ControllerType {
31 Cpu,
32 Cpuacct,
33 Cpuset,
34 Memory,
35 Freezer,
36 Blkio,
37}
38
39impl ControllerType {
40 pub const ALL: [Self; 6] =
41 [Self::Cpu, Self::Cpuacct, Self::Cpuset, Self::Memory, Self::Freezer, Self::Blkio];
42
43 pub fn as_str(&self) -> &'static str {
44 match self {
45 Self::Cpu => "cpu",
46 Self::Cpuacct => "cpuacct",
47 Self::Cpuset => "cpuset",
48 Self::Memory => "memory",
49 Self::Freezer => "freezer",
50 Self::Blkio => "blkio",
51 }
52 }
53}
54
55impl std::str::FromStr for ControllerType {
56 type Err = ();
57 fn from_str(s: &str) -> Result<Self, Self::Err> {
58 match s {
59 "cpu" => Ok(Self::Cpu),
60 "cpuacct" => Ok(Self::Cpuacct),
61 "cpuset" => Ok(Self::Cpuset),
62 "memory" => Ok(Self::Memory),
63 "freezer" => Ok(Self::Freezer),
64 "blkio" => Ok(Self::Blkio),
65 _ => Err(()),
66 }
67 }
68}
69
70impl std::fmt::Display for ControllerType {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 write!(f, "{}", self.as_str())
73 }
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
77pub struct CgroupV1Key {
78 pub controllers: BTreeSet<ControllerType>,
79 pub name: Option<String>,
80}
81
82#[derive(Default, Debug)]
83pub struct CgroupV1State {
84 pub controllers: HashMap<ControllerType, Arc<CgroupRoot>>,
89 pub named: HashMap<String, Arc<CgroupRoot>>,
91 pub hierarchies: BTreeMap<CgroupV1Key, Arc<CgroupRoot>>,
93 next_hierarchy_id: u32,
95}
96
97#[derive(Debug)]
100pub struct KernelCgroups {
101 pub cgroup2: Arc<CgroupRoot>,
103 pub cgroup1: LockDepMutex<CgroupV1State, CgroupV1Level>,
105}
106
107impl KernelCgroups {
108 pub fn lock_cgroup2_pid_table(&self) -> LockDepGuard<'_, CgroupPidTable> {
115 self.cgroup2.pid_table.lock()
116 }
117
118 pub fn get_or_create_cgroup1(
119 &self,
120 controllers: &BTreeSet<ControllerType>,
121 name: Option<&str>,
122 ) -> Result<Arc<CgroupRoot>, Errno> {
123 let mut cgroup1 = self.cgroup1.lock();
124
125 let key = CgroupV1Key { controllers: controllers.clone(), name: name.map(String::from) };
126
127 if let Some(root) = cgroup1.hierarchies.get(&key) {
128 return Ok(root.clone());
129 }
130
131 for c in controllers {
132 if cgroup1.controllers.contains_key(c) {
133 return error!(EBUSY);
134 }
135 }
136
137 if let Some(n) = name {
138 if cgroup1.named.contains_key(n) {
139 return error!(EBUSY);
140 }
141 }
142
143 cgroup1.next_hierarchy_id += 1;
144 let hierarchy_id = cgroup1.next_hierarchy_id;
145 let root = CgroupRoot::new(hierarchy_id, controllers.clone());
146 cgroup1.hierarchies.insert(key, root.clone());
147 for c in controllers {
148 cgroup1.controllers.insert(*c, root.clone());
149 }
150 if let Some(n) = name {
151 cgroup1.named.insert(n.to_string(), root.clone());
152 }
153
154 Ok(root)
155 }
156
157 pub fn get_cgroup1(&self, controller: ControllerType, pid: &Pid) -> Option<Weak<Cgroup>> {
158 let cgroup1 = self.cgroup1.lock();
159 let root = cgroup1.controllers.get(&controller)?;
160 root.get_cgroup(pid)
161 }
162}
163
164impl Default for KernelCgroups {
165 fn default() -> Self {
166 Self {
167 cgroup2: CgroupRoot::new(0, ControllerType::ALL.iter().copied().collect()),
168 cgroup1: Default::default(),
169 }
170 }
171}
172
173#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
174pub enum FreezerState {
175 Thawed,
176 Frozen,
177}
178
179impl Default for FreezerState {
180 fn default() -> Self {
181 FreezerState::Thawed
182 }
183}
184
185impl std::fmt::Display for FreezerState {
186 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187 match self {
188 FreezerState::Frozen => write!(f, "1"),
189 FreezerState::Thawed => write!(f, "0"),
190 }
191 }
192}
193
194#[derive(Default)]
195pub struct CgroupFreezerState {
196 pub self_freezer_state: FreezerState,
198 pub effective_freezer_state: FreezerState,
202}
203
204#[derive(Debug, Default, Clone, PartialEq, Eq)]
205pub struct CpusetControllerState {
206 pub cpus: Option<Vec<u32>>,
207}
208
209#[derive(Debug, Default, Clone, PartialEq, Eq)]
210pub struct FreezerControllerState {
211 pub self_freezer_state: FreezerState,
212 pub inherited_freezer_state: FreezerState,
213}
214
215#[derive(Debug, Clone, PartialEq, Eq)]
216pub enum ControllerState {
217 Cpuset(CpusetControllerState),
218 Freezer(FreezerControllerState),
219}
220
221pub trait FreezerOps: Send + Sync + 'static {
222 fn get_freezer_state(&self) -> CgroupFreezerState;
224
225 fn freeze(&self);
227
228 fn thaw(&self);
230}
231
232pub trait CpusetOps: Send + Sync + 'static {
233 fn cpuset_cpus(&self) -> Vec<u32>;
235
236 fn set_cpuset_cpus(&self, cpus: Vec<u32>);
238}
239
240pub trait CgroupOps: Send + Sync + 'static {
242 fn id(&self) -> u64;
244
245 fn add_process(&self, thread_group: &ThreadGroup) -> Result<(), Errno>;
247
248 fn new_child(&self, name: &FsStr) -> Result<CgroupHandle, Errno>;
251
252 fn get_children(&self) -> Result<Vec<CgroupHandle>, Errno>;
254
255 fn get_child(&self, name: &FsStr) -> Result<CgroupHandle, Errno>;
257
258 fn remove_child(&self, name: &FsStr) -> Result<CgroupHandle, Errno>;
261
262 fn get_pids(&self, kernel: &Kernel) -> Vec<pid_t>;
264
265 fn kill(&self);
267
268 fn is_populated(&self) -> bool;
270
271 fn freezer(&self) -> Option<&dyn FreezerOps>;
273
274 fn cpuset(&self) -> Option<&dyn CpusetOps>;
276}
277
278#[derive(Debug, Default)]
281pub struct CgroupPidTable(HashMap<Pid, Weak<Cgroup>>);
282impl Deref for CgroupPidTable {
283 type Target = HashMap<Pid, Weak<Cgroup>>;
284
285 fn deref(&self) -> &Self::Target {
286 &self.0
287 }
288}
289impl DerefMut for CgroupPidTable {
290 fn deref_mut(&mut self) -> &mut Self::Target {
291 &mut self.0
292 }
293}
294
295impl CgroupPidTable {
296 pub fn inherit_cgroup(&mut self, parent: &ThreadGroup, child: &ThreadGroup) {
299 assert!(child.read().tasks_count() == 0, "threadgroup must be newly created");
300 if let Some(weak_cgroup) = self.0.get(&parent.leader).cloned() {
301 let Some(cgroup) = weak_cgroup.upgrade() else {
302 log_warn!("ignored attempt to inherit a non-existant cgroup");
303 return;
304 };
305 assert!(
306 self.0.insert(child.leader.clone(), weak_cgroup).is_none(),
307 "child pid should not exist when inheriting"
308 );
309 cgroup.state.lock().processes.insert(child.leader.clone());
311 }
312 }
313
314 pub fn maybe_create_freeze_signal(&self, pid: &Pid) -> Option<KernelSignal> {
316 let Some(weak_cgroup) = self.0.get(pid) else {
317 return None;
318 };
319 let Some(cgroup) = weak_cgroup.upgrade() else {
320 return None;
321 };
322 let state = cgroup.state.lock();
323 if state.get_effective_freezer_state() != FreezerState::Frozen {
324 return None;
325 }
326 Some(KernelSignal::Freeze(state.create_freeze_waiter()))
327 }
328
329 pub fn remove_process(&mut self, pid: &Pid) {
331 if let Some(entry) = self.remove(pid) {
332 if let Some(cgroup) = entry.upgrade() {
333 cgroup.state.lock().processes.remove(pid);
334 }
335 }
336 }
337}
338
339#[derive(Debug)]
351pub struct CgroupRoot {
352 pub hierarchy_id: u32,
354
355 pub controllers: BTreeSet<ControllerType>,
357
358 pid_table: LockDepMutex<CgroupPidTable, CgroupPidTableLock>,
360
361 children: LockDepMutex<CgroupChildren, CgroupChildrenLock>,
363
364 weak_self: Weak<CgroupRoot>,
366
367 next_id: AtomicU64,
369}
370
371impl CgroupRoot {
372 pub fn new(hierarchy_id: u32, controllers: BTreeSet<ControllerType>) -> Arc<CgroupRoot> {
373 Arc::new_cyclic(|weak_self| Self {
374 hierarchy_id,
375 controllers,
376 pid_table: Default::default(),
377 children: Default::default(),
378 weak_self: weak_self.clone(),
379 next_id: AtomicU64::new(1),
380 })
381 }
382
383 pub fn has_controller(&self, controller: ControllerType) -> bool {
384 self.controllers.contains(&controller)
385 }
386
387 fn get_next_id(&self) -> u64 {
388 self.next_id.fetch_add(1, Ordering::Relaxed)
389 }
390
391 pub fn get_cgroup(&self, pid: &Pid) -> Option<Weak<Cgroup>> {
392 self.pid_table.lock().get(pid).cloned()
393 }
394
395 pub fn get_cgroup_inspect(&self) -> fuchsia_inspect::Inspector {
396 let inspector = fuchsia_inspect::Inspector::default();
397 let cgroups = inspector.root();
398 cgroups.record_uint("pids", self.pid_table.lock().len() as u64);
399 cgroups.record_uint("count", self.children.lock().count_descendants());
400 inspector
401 }
402}
403
404impl CgroupOps for CgroupRoot {
405 fn id(&self) -> u64 {
406 0
407 }
408
409 fn add_process(&self, thread_group: &ThreadGroup) -> Result<(), Errno> {
410 let mut pid_table = self.pid_table.lock();
411 if let Some(entry) = pid_table.remove(&thread_group.leader) {
415 if let Some(cgroup) = entry.upgrade() {
416 cgroup.state.lock().remove_process(thread_group)?;
417 }
418 }
419
420 let tasks = thread_group.read().tasks();
421 if self.has_controller(ControllerType::Cpuset) {
422 for task in &tasks {
423 task.write().cpuset_path = "/".to_string();
424 }
425 }
426
427 for task in tasks {
429 if let Err(e) = task.sync_scheduler_state_to_role() {
430 log_warn!("Failed to set thread role for task {}: {:?}", task.tid, e);
431 }
432 }
433
434 Ok(())
435 }
436
437 fn new_child(&self, name: &FsStr) -> Result<CgroupHandle, Errno> {
438 let id = self.get_next_id();
439 let new_child = Cgroup::new(id, name, &self.weak_self, None);
440 let mut children = self.children.lock();
441 children.insert_child(name.into(), new_child)
442 }
443
444 fn get_child(&self, name: &FsStr) -> Result<CgroupHandle, Errno> {
445 let children = self.children.lock();
446 children.get_child(name).ok_or_else(|| errno!(ENOENT))
447 }
448
449 fn remove_child(&self, name: &FsStr) -> Result<CgroupHandle, Errno> {
450 let mut children = self.children.lock();
451 children.remove_child(name)
452 }
453
454 fn get_children(&self) -> Result<Vec<CgroupHandle>, Errno> {
455 let children = self.children.lock();
456 Ok(children.get_children())
457 }
458
459 fn get_pids(&self, kernel: &Kernel) -> Vec<pid_t> {
460 let controlled_pids: HashSet<pid_t> = self
461 .pid_table
462 .lock()
463 .keys()
464 .filter_map(|v| v.get_thread_group().ok().map(|tg| tg.leader.id))
465 .collect();
466 let kernel_pids = kernel.pids.process_ids();
467 kernel_pids.into_iter().filter(|pid| !controlled_pids.contains(pid)).collect()
468 }
469
470 fn kill(&self) {
471 unreachable!("Root cgroup cannot kill its processes.");
472 }
473
474 fn is_populated(&self) -> bool {
475 false
476 }
477
478 fn freezer(&self) -> Option<&dyn FreezerOps> {
479 None
480 }
481
482 fn cpuset(&self) -> Option<&dyn CpusetOps> {
483 if self.controllers.contains(&ControllerType::Cpuset) { Some(self) } else { None }
484 }
485}
486
487impl CpusetOps for CgroupRoot {
488 fn cpuset_cpus(&self) -> Vec<u32> {
489 (0..zx::system_get_num_cpus()).collect()
490 }
491
492 fn set_cpuset_cpus(&self, _cpus: Vec<u32>) {}
493}
494
495#[derive(Debug, Default)]
496struct CgroupChildren(BTreeMap<FsString, CgroupHandle>);
497impl CgroupChildren {
498 fn insert_child(&mut self, name: FsString, child: CgroupHandle) -> Result<CgroupHandle, Errno> {
499 let btree_map::Entry::Vacant(child_entry) = self.0.entry(name) else {
500 return error!(EEXIST);
501 };
502 Ok(child_entry.insert(child).clone())
503 }
504
505 fn remove_child(&mut self, name: &FsStr) -> Result<CgroupHandle, Errno> {
506 let btree_map::Entry::Occupied(child_entry) = self.0.entry(name.into()) else {
507 return error!(ENOENT);
508 };
509 let child = child_entry.get();
510
511 let _token = allow_subclass();
515 let mut child_state = child.state.lock();
516 assert!(!child_state.deleted, "child cannot be deleted");
517
518 child_state.update_processes();
519 if !child_state.processes.is_empty() {
520 return error!(EBUSY);
521 }
522 if !child_state.children.is_empty() {
523 return error!(EBUSY);
524 }
525
526 child_state.deleted = true;
527 drop(child_state);
528
529 Ok(child_entry.remove())
530 }
531
532 fn get_child(&self, name: &FsStr) -> Option<CgroupHandle> {
533 self.0.get(name).cloned()
534 }
535
536 fn get_children(&self) -> Vec<CgroupHandle> {
537 self.0.values().cloned().collect()
538 }
539
540 fn count_descendants(&self) -> u64 {
541 self.0
542 .values()
543 .map(|child| {
544 1 + {
545 let _token = allow_subclass();
549 child.count_descendants()
550 }
551 })
552 .sum()
553 }
554}
555
556impl Deref for CgroupChildren {
557 type Target = BTreeMap<FsString, CgroupHandle>;
558
559 fn deref(&self) -> &Self::Target {
560 &self.0
561 }
562}
563
564#[derive(Debug, Default)]
565struct CgroupState {
566 children: CgroupChildren,
568
569 processes: HashSet<Pid>,
571
572 deleted: bool,
574
575 wait_queue: WaitQueue,
577
578 controllers: HashMap<ControllerType, ControllerState>,
580}
581
582impl CgroupState {
583 fn freezer(&self) -> Option<&FreezerControllerState> {
584 match self.controllers.get(&ControllerType::Freezer) {
585 Some(ControllerState::Freezer(state)) => Some(state),
586 _ => None,
587 }
588 }
589
590 fn freezer_mut(&mut self) -> Option<&mut FreezerControllerState> {
591 match self.controllers.get_mut(&ControllerType::Freezer) {
592 Some(ControllerState::Freezer(state)) => Some(state),
593 _ => None,
594 }
595 }
596
597 fn cpuset(&self) -> Option<&CpusetControllerState> {
598 match self.controllers.get(&ControllerType::Cpuset) {
599 Some(ControllerState::Cpuset(state)) => Some(state),
600 _ => None,
601 }
602 }
603
604 fn cpuset_mut(&mut self) -> Option<&mut CpusetControllerState> {
605 match self.controllers.get_mut(&ControllerType::Cpuset) {
606 Some(ControllerState::Cpuset(state)) => Some(state),
607 _ => None,
608 }
609 }
610
611 fn create_freeze_waiter(&self) -> Waiter {
614 let waiter = Waiter::new();
615 self.wait_queue.wait_async(&waiter);
616 waiter
617 }
618
619 fn update_processes(&mut self) {
621 self.processes.retain(|thread_group| {
622 let Ok(thread_group) = thread_group.get_thread_group() else {
623 return false;
624 };
625 let running = thread_group.read().is_running();
626 running
627 });
628 }
629
630 fn freeze_thread_group(&self, thread_group: &ThreadGroup) {
631 let tasks = thread_group.read().tasks();
632 for task in tasks {
633 send_freeze_signal(&task, self.create_freeze_waiter())
634 .expect("sending freeze signal should not fail");
635 }
636 }
637
638 fn thaw_thread_group(&self, thread_group: &ThreadGroup) {
639 let tasks = thread_group.read().tasks();
640 for task in tasks {
641 task.write().thaw();
642 task.interrupt();
643 }
644 }
645
646 fn get_effective_freezer_state(&self) -> FreezerState {
647 if let Some(freezer) = self.freezer() {
648 std::cmp::max(freezer.self_freezer_state, freezer.inherited_freezer_state)
649 } else {
650 FreezerState::Thawed
651 }
652 }
653
654 fn add_process(&mut self, thread_group: &ThreadGroup) -> Result<(), Errno> {
655 if self.deleted {
656 return error!(ENOENT);
657 }
658 self.processes.insert(thread_group.leader.clone());
659
660 if self.get_effective_freezer_state() == FreezerState::Frozen {
661 self.freeze_thread_group(&thread_group);
662 }
663 Ok(())
664 }
665
666 fn remove_process(&mut self, thread_group: &ThreadGroup) -> Result<(), Errno> {
667 if self.deleted {
668 return error!(ENOENT);
669 }
670 self.processes.remove(&thread_group.leader);
671
672 if self.get_effective_freezer_state() == FreezerState::Frozen {
673 self.thaw_thread_group(thread_group);
674 }
675 Ok(())
676 }
677
678 fn propagate_freeze(&mut self, inherited_freezer_state: FreezerState) {
679 let prev_effective_freezer_state = self.get_effective_freezer_state();
680 if let Some(freezer) = self.freezer_mut() {
681 freezer.inherited_freezer_state = inherited_freezer_state;
682 }
683 if prev_effective_freezer_state == FreezerState::Frozen {
684 return;
685 }
686
687 for pid in self.processes.iter() {
688 let Ok(thread_group) = pid.get_thread_group() else {
689 continue;
690 };
691 self.freeze_thread_group(&thread_group);
692 }
693
694 for child in self.children.get_children() {
696 let _token = allow_subclass();
700 child.state.lock().propagate_freeze(FreezerState::Frozen);
701 }
702 }
703
704 fn propagate_thaw(&mut self, inherited_freezer_state: FreezerState) {
705 if let Some(freezer) = self.freezer_mut() {
706 freezer.inherited_freezer_state = inherited_freezer_state;
707 }
708 if self.get_effective_freezer_state() == FreezerState::Thawed {
709 self.wait_queue.notify_all();
710 for child in self.children.get_children() {
711 let _token = allow_subclass();
715 child.state.lock().propagate_thaw(FreezerState::Thawed);
716 }
717 }
718 }
719
720 fn propagate_kill(&self) {
721 for pid in self.processes.iter() {
722 let Ok(thread_group) = pid.get_thread_group() else {
723 continue;
724 };
725 thread_group.write().send_signal(SignalInfo::kernel(SIGKILL));
726 }
727
728 for child in self.children.get_children() {
730 let _token = allow_subclass();
734 child.state.lock().propagate_kill();
735 }
736 }
737}
738
739#[derive(Debug)]
741pub struct Cgroup {
742 root: Weak<CgroupRoot>,
743
744 id: u64,
746
747 name: FsString,
749
750 parent: Option<Weak<Cgroup>>,
753
754 state: LockDepMutex<CgroupState, CgroupStateLock>,
756
757 weak_self: Weak<Cgroup>,
758}
759pub type CgroupHandle = Arc<Cgroup>;
760
761pub fn path_from_root(weak_cgroup: Option<Weak<Cgroup>>) -> Result<FsString, Errno> {
763 let cgroup = match weak_cgroup {
764 Some(weak_cgroup) => Weak::upgrade(&weak_cgroup).ok_or_else(|| errno!(ENODEV))?,
765 None => return Ok("/".into()),
766 };
767 let mut path = PathBuilder::new();
768 let mut current = Some(cgroup);
769 while let Some(cgroup) = current {
770 path.prepend_element(cgroup.name());
771 current = cgroup.parent()?;
772 }
773 Ok(path.build_absolute())
774}
775
776impl Cgroup {
777 pub fn new(
778 id: u64,
779 name: &FsStr,
780 root: &Weak<CgroupRoot>,
781 parent: Option<Weak<Cgroup>>,
782 ) -> CgroupHandle {
783 let root_shared = root.upgrade().expect("root must exist");
784 let mut controllers = HashMap::new();
785 for controller in &root_shared.controllers {
786 match controller {
787 ControllerType::Cpuset => {
788 controllers.insert(
789 *controller,
790 ControllerState::Cpuset(CpusetControllerState::default()),
791 );
792 }
793 ControllerType::Freezer => {
794 controllers.insert(
795 *controller,
796 ControllerState::Freezer(FreezerControllerState::default()),
797 );
798 }
799 _ => {}
800 }
801 }
802
803 Arc::new_cyclic(|weak| Self {
804 id,
805 root: root.clone(),
806 name: name.to_owned(),
807 parent,
808 state: LockDepMutex::new(CgroupState {
809 children: Default::default(),
810 processes: Default::default(),
811 deleted: false,
812 wait_queue: Default::default(),
813 controllers,
814 }),
815 weak_self: weak.clone(),
816 })
817 }
818
819 pub fn name(&self) -> &FsStr {
820 self.name.as_ref()
821 }
822
823 fn root(&self) -> Result<Arc<CgroupRoot>, Errno> {
824 self.root.upgrade().ok_or_else(|| errno!(ENODEV))
825 }
826
827 fn parent(&self) -> Result<Option<CgroupHandle>, Errno> {
830 self.parent.as_ref().map(|weak| weak.upgrade().ok_or_else(|| errno!(ENODEV))).transpose()
831 }
832
833 fn count_descendants(&self) -> u64 {
834 self.state.lock().children.count_descendants()
835 }
836
837 fn is_controller_supported(&self, controller: ControllerType) -> bool {
838 self.root().map(|r| r.controllers.contains(&controller)).unwrap_or(false)
839 }
840
841 fn cpuset_path(&self, root: &CgroupRoot) -> Option<String> {
842 if !root.has_controller(ControllerType::Cpuset) {
843 return None;
844 }
845 let bytes = path_from_root(Some(self.weak_self.clone())).ok()?;
846 std::str::from_utf8(&bytes).ok().map(|s| s.to_string())
847 }
848}
849
850impl CgroupOps for Cgroup {
851 fn id(&self) -> u64 {
852 self.id
853 }
854
855 fn add_process(&self, thread_group: &ThreadGroup) -> Result<(), Errno> {
856 let root = self.root()?;
857 let mut pid_table = root.pid_table.lock();
858 match pid_table.entry(thread_group.leader.clone()) {
859 hash_map::Entry::Occupied(mut entry) => {
860 if std::ptr::eq(self, entry.get().as_ptr()) {
863 return Ok(());
864 }
865
866 track_stub!(TODO("https://fxbug.dev/383374687"), "check permissions");
868 if let Some(other_cgroup) = entry.get().upgrade() {
869 other_cgroup.state.lock().remove_process(thread_group)?;
870 }
871
872 self.state.lock().add_process(thread_group)?;
873 entry.insert(self.weak_self.clone());
874 }
875 hash_map::Entry::Vacant(entry) => {
876 self.state.lock().add_process(thread_group)?;
877 entry.insert(self.weak_self.clone());
878 }
879 }
880
881 let tasks = thread_group.read().tasks();
882 if let Some(cpuset_path) = self.cpuset_path(&root) {
883 for task in &tasks {
884 task.write().cpuset_path = cpuset_path.clone();
885 }
886 }
887
888 for task in tasks {
890 if let Err(e) = task.sync_scheduler_state_to_role() {
891 log_warn!("Failed to set thread role for task {}: {:?}", task.tid, e);
892 }
893 }
894
895 Ok(())
896 }
897
898 fn new_child(&self, name: &FsStr) -> Result<CgroupHandle, Errno> {
899 let id = self.root()?.get_next_id();
900 let new_child = Cgroup::new(id, name, &self.root, Some(self.weak_self.clone()));
901 let mut state = self.state.lock();
902 if state.deleted {
903 return error!(ENOENT);
904 }
905 let effective_freezer = state.get_effective_freezer_state();
910 let _token = allow_subclass();
911 if let Some(freezer) = new_child.state.lock().freezer_mut() {
912 freezer.inherited_freezer_state = effective_freezer;
913 }
914 state.children.insert_child(name.into(), new_child)
915 }
916
917 fn get_child(&self, name: &FsStr) -> Result<CgroupHandle, Errno> {
918 let state = self.state.lock();
919 state.children.get_child(name).ok_or_else(|| errno!(ENOENT))
920 }
921
922 fn remove_child(&self, name: &FsStr) -> Result<CgroupHandle, Errno> {
923 let mut state = self.state.lock();
924 if state.deleted {
925 return error!(ENOENT);
926 }
927 state.children.remove_child(name)
928 }
929
930 fn get_children(&self) -> Result<Vec<CgroupHandle>, Errno> {
931 let state = self.state.lock();
932 if state.deleted {
933 return error!(ENOENT);
934 }
935 Ok(state.children.get_children())
936 }
937
938 fn get_pids(&self, _kernel: &Kernel) -> Vec<pid_t> {
939 let mut state = self.state.lock();
940 state.update_processes();
941 state
942 .processes
943 .iter()
944 .filter_map(|v| v.get_thread_group().ok().map(|tg| tg.leader.id))
945 .collect()
946 }
947
948 fn kill(&self) {
949 fuchsia_trace::duration!(CATEGORY_STARNIX, "CgroupKill");
950 let state = self.state.lock();
951 state.propagate_kill();
952 }
953
954 fn is_populated(&self) -> bool {
955 let mut state = self.state.lock();
956 if state.deleted {
957 return false;
958 }
959 state.update_processes();
960 if !state.processes.is_empty() {
961 return true;
962 }
963
964 state.children.get_children().into_iter().any(|child| {
965 let _token = allow_subclass();
969 child.is_populated()
970 })
971 }
972
973 fn freezer(&self) -> Option<&dyn FreezerOps> {
974 if self.is_controller_supported(ControllerType::Freezer) { Some(self) } else { None }
975 }
976
977 fn cpuset(&self) -> Option<&dyn CpusetOps> {
978 if self.is_controller_supported(ControllerType::Cpuset) { Some(self) } else { None }
979 }
980}
981
982impl FreezerOps for Cgroup {
983 fn get_freezer_state(&self) -> CgroupFreezerState {
984 let state = self.state.lock();
985 let self_freezer_state = state.freezer().map(|f| f.self_freezer_state).unwrap_or_default();
986 CgroupFreezerState {
987 self_freezer_state,
988 effective_freezer_state: state.get_effective_freezer_state(),
989 }
990 }
991
992 fn freeze(&self) {
993 fuchsia_trace::duration!(CATEGORY_STARNIX, "CgroupFreeze");
994 let mut state = self.state.lock();
995 let inherited_freezer_state =
996 state.freezer().map(|f| f.inherited_freezer_state).unwrap_or_default();
997 state.propagate_freeze(inherited_freezer_state);
998 if let Some(freezer) = state.freezer_mut() {
999 freezer.self_freezer_state = FreezerState::Frozen;
1000 }
1001 }
1002
1003 fn thaw(&self) {
1004 fuchsia_trace::duration!(CATEGORY_STARNIX, "CgroupThaw");
1005 let mut state = self.state.lock();
1006 if let Some(freezer) = state.freezer_mut() {
1007 freezer.self_freezer_state = FreezerState::Thawed;
1008 }
1009 let inherited_freezer_state =
1010 state.freezer().map(|f| f.inherited_freezer_state).unwrap_or_default();
1011 state.propagate_thaw(inherited_freezer_state);
1012 }
1013}
1014
1015impl CpusetOps for Cgroup {
1016 fn cpuset_cpus(&self) -> Vec<u32> {
1017 self.state
1018 .lock()
1019 .cpuset()
1020 .and_then(|c| c.cpus.clone())
1021 .unwrap_or_else(|| (0..zx::system_get_num_cpus()).collect())
1022 }
1023
1024 fn set_cpuset_cpus(&self, cpus: Vec<u32>) {
1025 let mut state = self.state.lock();
1027 if let Some(cpuset) = state.cpuset_mut() {
1028 cpuset.cpus = Some(cpus);
1029 }
1030 }
1031}
1032
1033#[cfg(test)]
1034mod test {
1035 use super::*;
1036 use crate::testing::spawn_kernel_and_run;
1037 use assert_matches::assert_matches;
1038 use starnix_uapi::signals::SIGCHLD;
1039 use starnix_uapi::{CLONE_SIGHAND, CLONE_THREAD, CLONE_VM};
1040
1041 #[::fuchsia::test]
1042 async fn cgroup_path_from_root() {
1043 spawn_kernel_and_run(async |_| {
1044 let root = CgroupRoot::new(0, BTreeSet::new());
1045
1046 let test_cgroup =
1047 root.new_child("test".into()).expect("new_child on root cgroup succeeds");
1048 let child_cgroup = test_cgroup
1049 .new_child("child".into())
1050 .expect("new_child on non-root cgroup succeeds");
1051
1052 assert_eq!(path_from_root(Some(Arc::downgrade(&test_cgroup))), Ok("/test".into()));
1053 assert_eq!(
1054 path_from_root(Some(Arc::downgrade(&child_cgroup))),
1055 Ok("/test/child".into())
1056 );
1057 })
1058 .await;
1059 }
1060
1061 #[::fuchsia::test]
1062 async fn cgroup_clone_task_in_frozen_cgroup() {
1063 spawn_kernel_and_run(async |current_task| {
1064 let kernel = current_task.kernel();
1065 let root = &kernel.cgroups.cgroup2;
1066 let cgroup = root.new_child("test".into()).expect("new_child on root cgroup succeeds");
1067
1068 let process = current_task.clone_task_for_test(0, Some(SIGCHLD));
1069 cgroup.add_process(process.thread_group()).expect("add process to cgroup");
1070 cgroup.freeze();
1071 assert_eq!(cgroup.get_pids(&kernel).first(), Some(process.get_pid()).as_ref());
1072 assert_eq!(root.get_cgroup(&process.pid).unwrap().as_ptr(), Arc::as_ptr(&cgroup));
1073
1074 let thread = process.clone_task_for_test(
1075 (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM) as u64,
1076 Some(SIGCHLD),
1077 );
1078
1079 let thread_state = thread.read();
1080 let kernel_signals = thread_state.kernel_signals_for_test();
1081 assert_matches!(kernel_signals.front(), Some(KernelSignal::Freeze(_)));
1082 })
1083 .await;
1084 }
1085
1086 #[::fuchsia::test]
1087 async fn cgroup_tg_release_removes_pid() {
1088 spawn_kernel_and_run(async |current_task| {
1089 let kernel = current_task.kernel();
1090 let root = &kernel.cgroups.cgroup2;
1091 let cgroup = root.new_child("test".into()).expect("new_child on root cgroup succeeds");
1092
1093 let process = current_task.clone_task_for_test(0, Some(SIGCHLD));
1094 cgroup.add_process(process.thread_group()).expect("add process to cgroup");
1095
1096 assert_eq!(root.get_cgroup(&process.pid).unwrap().as_ptr(), Arc::as_ptr(&cgroup));
1097
1098 drop(process);
1100
1101 assert!(root.pid_table.lock().is_empty());
1103 })
1104 .await;
1105 }
1106}