Implement waitpid on PGID

This commit is contained in:
Jeremy Soller
2018-01-05 20:31:15 -07:00
parent 9313909fe9
commit 083c444a68
6 changed files with 136 additions and 40 deletions

4
Cargo.lock generated
View File

@@ -135,7 +135,7 @@ dependencies = [
"clippy 0.0.177 (registry+https://github.com/rust-lang/crates.io-index)",
"goblin 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-cpuid 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.35",
"redox_syscall 0.1.37",
"spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"x86 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -224,7 +224,7 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.1.35"
version = "0.1.37"
[[package]]
name = "regex"

View File

@@ -1,6 +1,7 @@
use alloc::arc::Arc;
use alloc::boxed::Box;
use alloc::{BTreeMap, Vec, VecDeque};
use core::cmp::Ordering;
use core::mem;
use spin::Mutex;
@@ -27,6 +28,65 @@ pub enum Status {
Exited(usize)
}
#[derive(Copy, Clone, Debug)]
pub struct WaitpidKey {
pub pid: Option<ContextId>,
pub pgid: Option<ContextId>,
}
impl Ord for WaitpidKey {
fn cmp(&self, other: &WaitpidKey) -> Ordering {
// If both have pid set, compare that
if let Some(s_pid) = self.pid {
if let Some(o_pid) = other.pid {
return s_pid.cmp(&o_pid);
}
}
// If both have pgid set, compare that
if let Some(s_pgid) = self.pgid {
if let Some(o_pgid) = other.pgid {
return s_pgid.cmp(&o_pgid);
}
}
// If either has pid set, it is greater
if self.pid.is_some() {
return Ordering::Greater;
}
if other.pid.is_some() {
return Ordering::Less;
}
// If either has pgid set, it is greater
if self.pgid.is_some() {
return Ordering::Greater;
}
if other.pgid.is_some() {
return Ordering::Less;
}
// If all pid and pgid are None, they are equal
Ordering::Equal
}
}
impl PartialOrd for WaitpidKey {
fn partial_cmp(&self, other: &WaitpidKey) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for WaitpidKey {
fn eq(&self, other: &WaitpidKey) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Eq for WaitpidKey {}
/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
@@ -59,7 +119,7 @@ pub struct Context {
/// Context is halting parent
pub vfork: bool,
/// Context is being waited on
pub waitpid: Arc<WaitMap<ContextId, usize>>,
pub waitpid: Arc<WaitMap<WaitpidKey, (ContextId, usize)>>,
/// Context should handle pending signals
pub pending: VecDeque<u8>,
/// Context should wake up at specified time

View File

@@ -5,7 +5,7 @@ use alloc::heap::Heap;
use core::sync::atomic::Ordering;
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
pub use self::context::{Context, ContextId, Status};
pub use self::context::{Context, ContextId, Status, WaitpidKey};
pub use self::list::ContextList;
pub use self::switch::switch;

View File

@@ -1,7 +1,7 @@
use alloc::arc::Arc;
use core::mem;
use context::{contexts, switch, Status};
use context::{contexts, switch, Status, WaitpidKey};
use start::usermode;
use syscall;
use syscall::flag::{SIG_DFL, SIG_IGN, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU};
@@ -19,19 +19,19 @@ pub extern "C" fn signal_handler(sig: usize) {
if handler == SIG_DFL {
match sig {
SIGCHLD => {
println!("SIGCHLD");
// println!("SIGCHLD");
},
SIGCONT => {
println!("Continue");
// println!("Continue");
{
let contexts = contexts();
let (pid, ppid) = {
let (pid, pgid, ppid) = {
let context_lock = contexts.current().expect("context::signal_handler not inside of context");
let mut context = context_lock.write();
context.status = Status::Runnable;
(context.id, context.ppid)
(context.id, context.pgid, context.ppid)
};
if let Some(parent_lock) = contexts.get(ppid) {
@@ -40,23 +40,26 @@ pub extern "C" fn signal_handler(sig: usize) {
Arc::clone(&parent.waitpid)
};
waitpid.send(pid, 0xFFFF);
waitpid.send(WaitpidKey {
pid: Some(pid),
pgid: Some(pgid)
}, (pid, 0xFFFF));
} else {
println!("{}: {} not found for continue", pid.into(), ppid.into());
}
}
},
SIGSTOP | SIGTSTP | SIGTTIN | SIGTTOU => {
println!("Stop {}", sig);
// println!("Stop {}", sig);
{
let contexts = contexts();
let (pid, ppid) = {
let (pid, pgid, ppid) = {
let context_lock = contexts.current().expect("context::signal_handler not inside of context");
let mut context = context_lock.write();
context.status = Status::Stopped(sig);
(context.id, context.ppid)
(context.id, context.pgid, context.ppid)
};
if let Some(parent_lock) = contexts.get(ppid) {
@@ -65,7 +68,10 @@ pub extern "C" fn signal_handler(sig: usize) {
Arc::clone(&parent.waitpid)
};
waitpid.send(pid, (sig << 8) | 0x7F);
waitpid.send(WaitpidKey {
pid: Some(pid),
pgid: Some(pgid)
}, (pid, (sig << 8) | 0x7F));
} else {
println!("{}: {} not found for stop", pid.into(), ppid.into());
}
@@ -74,14 +80,14 @@ pub extern "C" fn signal_handler(sig: usize) {
unsafe { switch() };
},
_ => {
println!("Exit {}", sig);
// println!("Exit {}", sig);
syscall::exit(sig);
}
}
} else if handler == SIG_IGN {
println!("Ignore");
// println!("Ignore");
} else {
println!("Call {:X}", handler);
// println!("Call {:X}", handler);
unsafe {
let mut sp = ::USER_SIGSTACK_OFFSET + ::USER_SIGSTACK_SIZE - 256;

View File

@@ -14,7 +14,7 @@ use paging::temporary_page::TemporaryPage;
use start::usermode;
use interrupt;
use context;
use context::ContextId;
use context::{ContextId, WaitpidKey};
use context::file::FileDescriptor;
#[cfg(not(feature="doc"))]
use elf::{self, program_header};
@@ -22,7 +22,7 @@ use scheme::FileHandle;
use syscall;
use syscall::data::{SigAction, Stat};
use syscall::error::*;
use syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, SIG_DFL, SIGCONT, SIGTERM, WCONTINUED, WNOHANG, WUNTRACED};
use syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, SIG_DFL, SIGCONT, SIGTERM, WCONTINUED, WNOHANG, WUNTRACED, wifcontinued, wifstopped};
use syscall::validate::{validate_slice, validate_slice_mut};
pub fn brk(address: usize) -> Result<usize> {
@@ -863,10 +863,10 @@ pub fn exit(status: usize) -> ! {
}
}
// PPID must be grabbed after close, as context switches could change PPID if parent exits
let ppid = {
// PGID and PPID must be grabbed after close, as context switches could change PGID or PPID if parent exits
let (pgid, ppid) = {
let context = context_lock.read();
context.ppid
(context.pgid, context.ppid)
};
// Transfer child processes to parent
@@ -912,7 +912,11 @@ pub fn exit(status: usize) -> ! {
for (c_pid, c_status) in children {
waitpid.send(c_pid, c_status);
}
waitpid.send(pid, status);
waitpid.send(WaitpidKey {
pid: Some(pid),
pgid: Some(pgid)
}, (pid, status));
} else {
println!("{}: {} not found for exit vfork unblock", pid.into(), ppid.into());
}
@@ -965,8 +969,6 @@ pub fn getppid() -> Result<ContextId> {
}
pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
println!("Kill {} {}", pid.into() as isize, sig);
let (ruid, euid, current_pgid) = {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
@@ -1109,8 +1111,6 @@ pub fn sigaction(sig: usize, act_opt: Option<&SigAction>, oldact_opt: Option<&mu
}
pub fn sigreturn() -> Result<usize> {
println!("Sigreturn");
{
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
@@ -1165,14 +1165,14 @@ pub fn waitpid(pid: ContextId, status_ptr: usize, flags: usize) -> Result<Contex
};
let mut grim_reaper = |w_pid: ContextId, status: usize| -> Option<Result<ContextId>> {
if status == 0xFFFF {
if wifcontinued(status) {
if flags & WCONTINUED == WCONTINUED {
status_slice[0] = status;
Some(Ok(w_pid))
} else {
None
}
} else if status & 0xFF == 0x7F {
} else if wifstopped(status) {
if flags & WUNTRACED == WUNTRACED {
status_slice[0] = status;
Some(Ok(w_pid))
@@ -1188,17 +1188,36 @@ pub fn waitpid(pid: ContextId, status_ptr: usize, flags: usize) -> Result<Contex
loop {
let res_opt = if pid.into() == 0 {
if flags & WNOHANG == WNOHANG {
if let Some((w_pid, status)) = waitpid.receive_any_nonblock() {
if let Some((_wid, (w_pid, status))) = waitpid.receive_any_nonblock() {
grim_reaper(w_pid, status)
} else {
Some(Ok(ContextId::from(0)))
}
} else {
let (w_pid, status) = waitpid.receive_any();
let (_wid, (w_pid, status)) = waitpid.receive_any();
grim_reaper(w_pid, status)
}
} else if (pid.into() as isize) < 0 {
let pgid = ContextId::from(-(pid.into() as isize) as usize);
//TODO: Check for existence of child in process group PGID
if flags & WNOHANG == WNOHANG {
if let Some((w_pid, status)) = waitpid.receive_nonblock(&WaitpidKey {
pid: None,
pgid: Some(pgid)
}) {
grim_reaper(w_pid, status)
} else {
Some(Ok(ContextId::from(0)))
}
} else {
let (w_pid, status) = waitpid.receive(&WaitpidKey {
pid: None,
pgid: Some(pgid)
});
grim_reaper(w_pid, status)
}
} else {
let status = {
let hack_status = {
let contexts = context::contexts();
let context_lock = contexts.get(pid).ok_or(Error::new(ECHILD))?;
let mut context = context_lock.write();
@@ -1206,22 +1225,33 @@ pub fn waitpid(pid: ContextId, status_ptr: usize, flags: usize) -> Result<Contex
println!("Hack for rustc - changing ppid of {} from {} to {}", context.id.into(), context.ppid.into(), ppid.into());
context.ppid = ppid;
//return Err(Error::new(ECHILD));
Some(context.status)
} else {
None
}
context.status
};
if let context::Status::Exited(status) = status {
let _ = waitpid.receive_nonblock(&pid);
if let Some(context::Status::Exited(status)) = hack_status {
let _ = waitpid.receive_nonblock(&WaitpidKey {
pid: Some(pid),
pgid: None
});
grim_reaper(pid, status)
} else if flags & WNOHANG == WNOHANG {
if let Some(status) = waitpid.receive_nonblock(&pid) {
grim_reaper(pid, status)
if let Some((w_pid, status)) = waitpid.receive_nonblock(&WaitpidKey {
pid: Some(pid),
pgid: None
}) {
grim_reaper(w_pid, status)
} else {
Some(Ok(ContextId::from(0)))
}
} else {
let status = waitpid.receive(&pid);
grim_reaper(pid, status)
let (w_pid, status) = waitpid.receive(&WaitpidKey {
pid: Some(pid),
pgid: None
});
grim_reaper(w_pid, status)
}
};

Submodule syscall updated: 8f01290058...7c805d2a28