-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
to be able to catch children exiting Signed-off-by: Peter Hunt <pehunt@redhat.com>
- Loading branch information
1 parent
ac8f527
commit b544347
Showing
3 changed files
with
154 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
//! Child process reaping and management. | ||
use anyhow::{bail, Result}; | ||
use getset::Getters; | ||
use log::{debug, error}; | ||
use nix::sys::signal::{kill, Signal}; | ||
use nix::sys::wait::{waitpid, WaitStatus}; | ||
use nix::unistd::Pid; | ||
use std::path::PathBuf; | ||
use std::thread; | ||
use std::{collections::HashMap, fs::File, io::Write, sync::Arc, sync::Mutex}; | ||
|
||
impl ChildReaper { | ||
pub fn init_reaper(&self) -> Result<()> { | ||
let children = Arc::clone(&self.children); | ||
thread::spawn(move || { | ||
loop { | ||
let children = Arc::clone(&children); | ||
match waitpid(Pid::from_raw(-1), None) { | ||
Ok(status) => { | ||
if let WaitStatus::Exited(child_pid, exit_status) = status { | ||
// Immediately spawn a thread to reduce risk of dropping | ||
// a SIGCHLD. | ||
thread::spawn(move || { | ||
if let Err(e) = Self::reap_child(children, child_pid, exit_status) { | ||
error!("Failed to reap child for pid {}: {}", child_pid, e); | ||
} | ||
}); | ||
} | ||
} | ||
|
||
Err(err) => { | ||
// TODO FIXME this busy loops right now while there are no children. | ||
// There should be a broadcast mechanism so we only run this loop | ||
// while there are children | ||
if err != nix::errno::Errno::ECHILD { | ||
error!("caught error in reading for sigchld {}", err); | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
Ok(()) | ||
} | ||
|
||
fn reap_child( | ||
locked_map: Arc<Mutex<HashMap<i32, ReapableChild>>>, | ||
child_pid: Pid, | ||
exit_status: i32, | ||
) -> Result<()> { | ||
debug!("caught signal for pid {}", child_pid); | ||
|
||
let mut map = locked_map.lock().unwrap(); | ||
let child = match map.remove(&(i32::from(child_pid))) { | ||
Some(c) => c, | ||
None => { | ||
// If we have an unregistered PID, then there's nothing to do. | ||
return Ok(()); | ||
} | ||
}; | ||
|
||
debug!( | ||
"PID {} associated with container {} exited with {}", | ||
child_pid, child.id, exit_status | ||
); | ||
if let Err(e) = write_to_exit_paths(exit_status, child.exit_paths) { | ||
error!( | ||
"failed to write to exit paths process for id {} :{}", | ||
child.id, e | ||
); | ||
} | ||
Ok(()) | ||
} | ||
|
||
pub fn add_child(&self, id: String, pid: i32, exit_paths: Vec<PathBuf>) -> Result<()> { | ||
let locked_children = Arc::clone(&self.children); | ||
let mut map = locked_children.lock().unwrap(); | ||
|
||
let reapable_child = ReapableChild { id, exit_paths }; | ||
if let Some(old) = map.insert(pid, reapable_child) { | ||
bail!("Repeat PID for container {} found", old.id); | ||
} | ||
Ok(()) | ||
} | ||
pub fn kill_children(&self, s: Signal) -> Result<()> { | ||
for (pid, kc) in Arc::clone(&self.children).lock().unwrap().iter() { | ||
debug!("killing pid {} for container {}", pid, kc.id); | ||
kill(Pid::from_raw(*pid), s)?; | ||
} | ||
Ok(()) | ||
} | ||
} | ||
|
||
#[derive(Debug, Default)] | ||
pub struct ChildReaper { | ||
children: Arc<Mutex<HashMap<i32, ReapableChild>>>, | ||
} | ||
|
||
#[derive(Debug, Getters)] | ||
pub struct ReapableChild { | ||
#[getset(get)] | ||
id: String, | ||
#[getset(get)] | ||
exit_paths: Vec<PathBuf>, | ||
} | ||
|
||
fn write_to_exit_paths(code: i32, paths: Vec<PathBuf>) -> Result<()> { | ||
let code_str = format!("{}", code); | ||
for path in paths { | ||
debug!("writing exit code {} to {}", code, path.display()); | ||
File::create(path)?.write_all(code_str.as_bytes())?; | ||
} | ||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters