constellation/
process_manager.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::process::Child;
6
7use crossbeam_channel::{Receiver, Select};
8use log::{debug, warn};
9use profile_traits::mem::{ProfilerChan, ProfilerMsg};
10
11pub enum Process {
12    Unsandboxed(Child),
13    Sandboxed(u32),
14}
15
16impl Process {
17    fn pid(&self) -> u32 {
18        match self {
19            Self::Unsandboxed(child) => child.id(),
20            Self::Sandboxed(pid) => *pid,
21        }
22    }
23
24    fn wait(&mut self) {
25        match self {
26            Self::Unsandboxed(child) => {
27                let _ = child.wait();
28            },
29            Self::Sandboxed(_pid) => {
30                // TODO: use nix::waitpid() on supported platforms.
31                warn!("wait() is not yet implemented for sandboxed processes.");
32            },
33        }
34    }
35}
36
37type ProcessReceiver = Receiver<Result<(), ipc_channel::Error>>;
38
39pub(crate) struct ProcessManager {
40    processes: Vec<(Process, ProcessReceiver)>,
41    mem_profiler_chan: ProfilerChan,
42}
43
44impl ProcessManager {
45    pub fn new(mem_profiler_chan: ProfilerChan) -> Self {
46        Self {
47            processes: vec![],
48            mem_profiler_chan,
49        }
50    }
51
52    pub fn add(&mut self, receiver: ProcessReceiver, process: Process) {
53        debug!("Adding process pid={}", process.pid());
54        self.processes.push((process, receiver));
55    }
56
57    pub fn register<'a>(&'a self, select: &mut Select<'a>) {
58        for (_, receiver) in &self.processes {
59            select.recv(receiver);
60        }
61    }
62
63    pub fn receiver_at(&self, index: usize) -> &ProcessReceiver {
64        let (_, receiver) = &self.processes[index];
65        receiver
66    }
67
68    pub fn remove(&mut self, index: usize) {
69        let (mut process, _) = self.processes.swap_remove(index);
70        debug!("Removing process pid={}", process.pid());
71        // Unregister this process system memory profiler
72        self.mem_profiler_chan
73            .send(ProfilerMsg::UnregisterReporter(format!(
74                "system-content-{}",
75                process.pid()
76            )));
77        process.wait();
78    }
79}