mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Prevent zombie processes in multi-process mode. (#36329)
This introduces a process manager that holds for each process a "lifeline": this is the receiving end of a ipc channel that is not used to send anything, but only to monitor the process presence. We turn that ipc receiver into a crossbeam one to integrate the monitoring into the constellation run loop. The sender side is made part of the initial "UnprivilegedContent" data structure sent to the new process, both for content and for service worker processes. When a process dies we currently wait() on it to let the OS do a clean shutdown. Signed-off-by: webbeef <me@webbeef.org>
This commit is contained in:
parent
c09c31ef85
commit
c7a7862574
6 changed files with 177 additions and 44 deletions
68
components/constellation/process_manager.rs
Normal file
68
components/constellation/process_manager.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::process::Child;
|
||||
|
||||
use crossbeam_channel::{Receiver, Select};
|
||||
use log::{debug, warn};
|
||||
|
||||
pub enum Process {
|
||||
Unsandboxed(Child),
|
||||
Sandboxed(u32),
|
||||
}
|
||||
|
||||
impl Process {
|
||||
fn pid(&self) -> u32 {
|
||||
match self {
|
||||
Self::Unsandboxed(child) => child.id(),
|
||||
Self::Sandboxed(pid) => *pid,
|
||||
}
|
||||
}
|
||||
|
||||
fn wait(&mut self) {
|
||||
match self {
|
||||
Self::Unsandboxed(child) => {
|
||||
let _ = child.wait();
|
||||
},
|
||||
Self::Sandboxed(_pid) => {
|
||||
// TODO: use nix::waitpid() on supported platforms.
|
||||
warn!("wait() is not yet implemented for sandboxed processes.");
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ProcessReceiver = Receiver<Result<(), ipc_channel::Error>>;
|
||||
|
||||
pub(crate) struct ProcessManager {
|
||||
processes: Vec<(Process, ProcessReceiver)>,
|
||||
}
|
||||
|
||||
impl ProcessManager {
|
||||
pub fn new() -> Self {
|
||||
Self { processes: vec![] }
|
||||
}
|
||||
|
||||
pub fn add(&mut self, receiver: ProcessReceiver, process: Process) {
|
||||
debug!("Adding process pid={}", process.pid());
|
||||
self.processes.push((process, receiver));
|
||||
}
|
||||
|
||||
pub fn register<'a>(&'a self, select: &mut Select<'a>) {
|
||||
for (_, receiver) in &self.processes {
|
||||
select.recv(receiver);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receiver_at(&self, index: usize) -> &ProcessReceiver {
|
||||
let (_, receiver) = &self.processes[index];
|
||||
receiver
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, index: usize) {
|
||||
let (mut process, _) = self.processes.swap_remove(index);
|
||||
debug!("Removing process pid={}", process.pid());
|
||||
process.wait();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue