Skip to content
Snippets Groups Projects
Commit 25743a89 authored by Jeremy Soller's avatar Jeremy Soller
Browse files

Correct init process, allow waiting on any children, reap zombies in init

parent ff227737
No related branches found
No related tags found
No related merge requests found
...@@ -7,7 +7,7 @@ use arch; ...@@ -7,7 +7,7 @@ use arch;
use context::file::File; use context::file::File;
use context::memory::{Grant, Memory, SharedMemory, Tls}; use context::memory::{Grant, Memory, SharedMemory, Tls};
use syscall::data::Event; use syscall::data::Event;
use sync::{WaitCondition, WaitQueue}; use sync::{WaitMap, WaitQueue};
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status { pub enum Status {
...@@ -40,7 +40,7 @@ pub struct Context { ...@@ -40,7 +40,7 @@ pub struct Context {
/// Context is halting parent /// Context is halting parent
pub vfork: bool, pub vfork: bool,
/// Context is being waited on /// Context is being waited on
pub waitpid: Arc<WaitCondition>, pub waitpid: Arc<WaitMap<usize, usize>>,
/// Context should wake up at specified time /// Context should wake up at specified time
pub wake: Option<(u64, u64)>, pub wake: Option<(u64, u64)>,
/// The architecture specific context /// The architecture specific context
...@@ -85,7 +85,7 @@ impl Context { ...@@ -85,7 +85,7 @@ impl Context {
running: false, running: false,
cpu_id: None, cpu_id: None,
vfork: false, vfork: false,
waitpid: Arc::new(WaitCondition::new()), waitpid: Arc::new(WaitMap::new()),
wake: None, wake: None,
arch: arch::context::Context::new(), arch: arch::context::Context::new(),
kfx: None, kfx: None,
......
use collections::BTreeMap; use collections::BTreeMap;
use core::mem;
use spin::Mutex; use spin::Mutex;
use sync::WaitCondition; use sync::WaitCondition;
...@@ -9,7 +10,7 @@ pub struct WaitMap<K, V> { ...@@ -9,7 +10,7 @@ pub struct WaitMap<K, V> {
condition: WaitCondition condition: WaitCondition
} }
impl<K, V> WaitMap<K, V> where K: Ord { impl<K, V> WaitMap<K, V> where K: Clone + Ord {
pub fn new() -> WaitMap<K, V> { pub fn new() -> WaitMap<K, V> {
WaitMap { WaitMap {
inner: Mutex::new(BTreeMap::new()), inner: Mutex::new(BTreeMap::new()),
...@@ -17,17 +18,45 @@ impl<K, V> WaitMap<K, V> where K: Ord { ...@@ -17,17 +18,45 @@ impl<K, V> WaitMap<K, V> where K: Ord {
} }
} }
pub fn send(&self, key: K, value: V) { pub fn receive_nonblock(&self, key: &K) -> Option<V> {
self.inner.lock().insert(key, value); self.inner.lock().remove(key)
self.condition.notify();
} }
pub fn receive(&self, key: &K) -> V { pub fn receive(&self, key: &K) -> V {
loop { loop {
if let Some(value) = self.inner.lock().remove(key) { if let Some(value) = self.receive_nonblock(key) {
return value; return value;
} }
self.condition.wait(); self.condition.wait();
} }
} }
pub fn receive_any_nonblock(&self) -> Option<(K, V)> {
let mut inner = self.inner.lock();
if let Some(key) = inner.keys().next().map(|key| key.clone()) {
inner.remove(&key).map(|value| (key, value))
} else {
None
}
}
pub fn receive_any(&self) -> (K, V) {
loop {
if let Some(entry) = self.receive_any_nonblock() {
return entry;
}
self.condition.wait();
}
}
pub fn receive_all(&self) -> BTreeMap<K, V> {
let mut ret = BTreeMap::new();
mem::swap(&mut ret, &mut *self.inner.lock());
ret
}
pub fn send(&self, key: K, value: V) {
self.inner.lock().insert(key, value);
self.condition.notify();
}
} }
...@@ -691,13 +691,14 @@ pub fn exit(status: usize) -> ! { ...@@ -691,13 +691,14 @@ pub fn exit(status: usize) -> ! {
}; };
let mut close_files = Vec::new(); let mut close_files = Vec::new();
{ let (pid, ppid) = {
let mut context = context_lock.write(); let mut context = context_lock.write();
if Arc::strong_count(&context.files) == 1 { if Arc::strong_count(&context.files) == 1 {
mem::swap(context.files.lock().deref_mut(), &mut close_files); mem::swap(context.files.lock().deref_mut(), &mut close_files);
} }
context.files = Arc::new(Mutex::new(Vec::new())); context.files = Arc::new(Mutex::new(Vec::new()));
} (context.id, context.ppid)
};
/// Files must be closed while context is valid so that messages can be passed /// Files must be closed while context is valid so that messages can be passed
for (fd, file_option) in close_files.drain(..).enumerate() { for (fd, file_option) in close_files.drain(..).enumerate() {
...@@ -716,7 +717,19 @@ pub fn exit(status: usize) -> ! { ...@@ -716,7 +717,19 @@ pub fn exit(status: usize) -> ! {
} }
} }
let (vfork, ppid) = { /// Transfer child processes to parent
{
let contexts = context::contexts();
for (_id, context_lock) in contexts.iter() {
let mut context = context_lock.write();
if context.ppid == pid {
context.ppid = ppid;
context.vfork = false;
}
}
}
let (vfork, children) = {
let mut context = context_lock.write(); let mut context = context_lock.write();
context.image.clear(); context.image.clear();
...@@ -730,18 +743,28 @@ pub fn exit(status: usize) -> ! { ...@@ -730,18 +743,28 @@ pub fn exit(status: usize) -> ! {
context.status = context::Status::Exited(status); context.status = context::Status::Exited(status);
context.waitpid.notify(); let children = context.waitpid.receive_all();
(vfork, context.ppid) (vfork, children)
}; };
if vfork { {
let contexts = context::contexts(); let contexts = context::contexts();
if let Some(parent_lock) = contexts.get(ppid) { if let Some(parent_lock) = contexts.get(ppid) {
let mut parent = parent_lock.write(); let waitpid = {
if ! parent.unblock() { let mut parent = parent_lock.write();
println!("{} not blocked for exit vfork unblock", ppid); if vfork {
if ! parent.unblock() {
println!("{} not blocked for exit vfork unblock", ppid);
}
}
parent.waitpid.clone()
};
for (c_pid, c_status) in children {
waitpid.send(c_pid, c_status);
} }
waitpid.send(pid, status);
} else { } else {
println!("{} not found for exit vfork unblock", ppid); println!("{} not found for exit vfork unblock", ppid);
} }
...@@ -977,45 +1000,64 @@ pub fn virttophys(virtual_address: usize) -> Result<usize> { ...@@ -977,45 +1000,64 @@ pub fn virttophys(virtual_address: usize) -> Result<usize> {
} }
} }
pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result<usize> { fn reap(pid: usize) -> Result<usize> {
loop { // Spin until not running
let mut exited = false; let mut running = false;
let mut running; while running {
let waitpid;
{ {
let contexts = context::contexts(); let contexts = context::contexts();
let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?; let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?;
let context = context_lock.read(); let context = context_lock.read();
if let context::Status::Exited(status) = context.status {
if status_ptr != 0 {
let status_slice = validate_slice_mut(status_ptr as *mut usize, 1)?;
status_slice[0] = status;
}
exited = true;
}
running = context.running; running = context.running;
waitpid = context.waitpid.clone();
} }
if exited { arch::interrupt::pause();
// Spin until not running }
while running {
{
let contexts = context::contexts();
let context_lock = contexts.get(pid).ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
running = context.running;
}
arch::interrupt::pause(); let mut contexts = context::contexts_mut();
} contexts.remove(pid).ok_or(Error::new(ESRCH)).and(Ok(pid))
}
let mut contexts = context::contexts_mut(); pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result<usize> {
return contexts.remove(pid).ok_or(Error::new(ESRCH)).and(Ok(pid)); let waitpid = {
} else if flags & WNOHANG == WNOHANG { let contexts = context::contexts();
return Ok(0); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
context.waitpid.clone()
};
let mut tmp = [0];
let status_slice = if status_ptr != 0 {
validate_slice_mut(status_ptr as *mut usize, 1)?
} else {
&mut tmp
};
if pid == 0 {
if flags & WNOHANG == WNOHANG {
if let Some((w_pid, status)) = waitpid.receive_any_nonblock() {
status_slice[0] = status;
reap(w_pid)
} else {
Ok(0)
}
} else {
let (w_pid, status) = waitpid.receive_any();
status_slice[0] = status;
reap(w_pid)
}
} else {
if flags & WNOHANG == WNOHANG {
if let Some(status) = waitpid.receive_nonblock(&pid) {
status_slice[0] = status;
reap(pid)
} else {
Ok(0)
}
} else { } else {
waitpid.wait(); let status = waitpid.receive(&pid);
status_slice[0] = status;
reap(pid)
} }
} }
} }
...@@ -89,4 +89,9 @@ pub fn main() { ...@@ -89,4 +89,9 @@ pub fn main() {
if let Err(err) = run("initfs:etc/init.rc") { if let Err(err) = run("initfs:etc/init.rc") {
println!("init: failed to run initfs:etc/init.rc: {}", err); println!("init: failed to run initfs:etc/init.rc: {}", err);
} }
loop {
let mut status = 0;
syscall::waitpid(0, &mut status, 0).unwrap();
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment