Correct init process, allow waiting on any children, reap zombies in init
This commit is contained in:
parent
ff227737bf
commit
25743a89a2
|
@ -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 {
|
||||||
/// 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 {
|
||||||
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,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
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> {
|
||||||
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 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) -> ! {
|
||||||
};
|
};
|
||||||
|
|
||||||
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) -> ! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) -> ! {
|
||||||
|
|
||||||
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> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result<usize> {
|
||||||
|
let waitpid = {
|
||||||
|
let contexts = context::contexts();
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut contexts = context::contexts_mut();
|
|
||||||
return contexts.remove(pid).ok_or(Error::new(ESRCH)).and(Ok(pid));
|
|
||||||
} else if flags & WNOHANG == WNOHANG {
|
|
||||||
return Ok(0);
|
|
||||||
} else {
|
} else {
|
||||||
waitpid.wait();
|
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 {
|
||||||
|
let status = waitpid.receive(&pid);
|
||||||
|
status_slice[0] = status;
|
||||||
|
reap(pid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue