Implement waitpid on PGID
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
2
syscall
2
syscall
Submodule syscall updated: 8f01290058...7c805d2a28
Reference in New Issue
Block a user