wait
This commit is contained in:
parent
0a1e889d54
commit
8dc10d24f0
@ -82,13 +82,11 @@ void printint(int n);
|
|||||||
void proc_mapstacks(pagetable_t);
|
void proc_mapstacks(pagetable_t);
|
||||||
pagetable_t proc_pagetable(struct proc *);
|
pagetable_t proc_pagetable(struct proc *);
|
||||||
void proc_freepagetable(pagetable_t, uint64);
|
void proc_freepagetable(pagetable_t, uint64);
|
||||||
int killed(struct proc *);
|
|
||||||
struct cpu *mycpu(void);
|
struct cpu *mycpu(void);
|
||||||
struct proc *myproc();
|
struct proc *myproc();
|
||||||
void procinit(void);
|
void procinit(void);
|
||||||
void sleep_lock(void *, struct spinlock *);
|
void sleep_lock(void *, struct spinlock *);
|
||||||
void userinit(void);
|
void userinit(void);
|
||||||
int wait(uint64);
|
|
||||||
void wakeup(void *);
|
void wakeup(void *);
|
||||||
int either_copyout(int user_dst, uint64 dst, void *src, uint64 len);
|
int either_copyout(int user_dst, uint64 dst, void *src, uint64 len);
|
||||||
int either_copyin(void *dst, int user_src, uint64 src, uint64 len);
|
int either_copyin(void *dst, int user_src, uint64 src, uint64 len);
|
||||||
|
@ -11,7 +11,6 @@ struct proc proc[NPROC];
|
|||||||
struct proc *initproc;
|
struct proc *initproc;
|
||||||
|
|
||||||
extern void forkret(void);
|
extern void forkret(void);
|
||||||
void freeproc(struct proc *p);
|
|
||||||
|
|
||||||
extern char trampoline[]; // trampoline.S
|
extern char trampoline[]; // trampoline.S
|
||||||
|
|
||||||
@ -105,59 +104,6 @@ userinit(void)
|
|||||||
release(&p->lock);
|
release(&p->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass p's abandoned children to init.
|
|
||||||
// Caller must hold wait_lock.
|
|
||||||
void reparent(struct proc *p);
|
|
||||||
|
|
||||||
// Wait for a child process to exit and return its pid.
|
|
||||||
// Return -1 if this process has no children.
|
|
||||||
int
|
|
||||||
wait(uint64 addr)
|
|
||||||
{
|
|
||||||
struct proc *pp;
|
|
||||||
int havekids, pid;
|
|
||||||
struct proc *p = myproc();
|
|
||||||
|
|
||||||
acquire(&wait_lock);
|
|
||||||
|
|
||||||
for(;;){
|
|
||||||
// Scan through table looking for exited children.
|
|
||||||
havekids = 0;
|
|
||||||
for(pp = proc; pp < &proc[NPROC]; pp++){
|
|
||||||
if(pp->parent == p){
|
|
||||||
// make sure the child isn't still in exit() or swtch().
|
|
||||||
acquire(&pp->lock);
|
|
||||||
|
|
||||||
havekids = 1;
|
|
||||||
if(pp->state == ZOMBIE){
|
|
||||||
// Found one.
|
|
||||||
pid = pp->pid;
|
|
||||||
if(addr != 0 && copyout(p->pagetable, addr, (char *)&pp->xstate,
|
|
||||||
sizeof(pp->xstate)) < 0) {
|
|
||||||
release(&pp->lock);
|
|
||||||
release(&wait_lock);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
freeproc(pp);
|
|
||||||
release(&pp->lock);
|
|
||||||
release(&wait_lock);
|
|
||||||
return pid;
|
|
||||||
}
|
|
||||||
release(&pp->lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No point waiting if we don't have any children.
|
|
||||||
if(!havekids || killed(p)){
|
|
||||||
release(&wait_lock);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for a child to exit.
|
|
||||||
sleep_lock(p, &wait_lock); // DOC: wait-sleep
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A fork child's very first scheduling by scheduler()
|
// A fork child's very first scheduling by scheduler()
|
||||||
// will swtch to forkret.
|
// will swtch to forkret.
|
||||||
void
|
void
|
||||||
@ -200,8 +146,6 @@ void wakeup(void *chan)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int killed(struct proc *p);
|
|
||||||
|
|
||||||
// Copy to either a user address, or kernel address,
|
// Copy to either a user address, or kernel address,
|
||||||
// depending on usr_dst.
|
// depending on usr_dst.
|
||||||
// Returns 0 on success, -1 on error.
|
// Returns 0 on success, -1 on error.
|
||||||
|
@ -108,5 +108,3 @@ struct proc {
|
|||||||
struct inode *cwd; // Current directory
|
struct inode *cwd; // Current directory
|
||||||
char name[16]; // Process name (debugging)
|
char name[16]; // Process name (debugging)
|
||||||
};
|
};
|
||||||
|
|
||||||
int allocpid();
|
|
||||||
|
@ -1,22 +1,30 @@
|
|||||||
#![allow(clippy::comparison_chain)]
|
#![allow(clippy::comparison_chain)]
|
||||||
|
|
||||||
use super::{context::Context, cpu::Cpu, scheduler::{wakeup, sched}, trapframe::Trapframe};
|
use super::{
|
||||||
|
context::Context,
|
||||||
|
cpu::Cpu,
|
||||||
|
scheduler::{sched, wakeup},
|
||||||
|
trapframe::Trapframe,
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::riscv::{Pagetable, PTE_W, PTE_R, PTE_X, PGSIZE, memlayout::{TRAMPOLINE, TRAPFRAME}},
|
arch::riscv::{
|
||||||
|
memlayout::{TRAMPOLINE, TRAPFRAME},
|
||||||
|
Pagetable, PGSIZE, PTE_R, PTE_W, PTE_X,
|
||||||
|
},
|
||||||
fs::{
|
fs::{
|
||||||
file::{File, Inode, filedup, fileclose},
|
file::{fileclose, filedup, File, Inode},
|
||||||
idup,
|
idup, iput,
|
||||||
iput,
|
|
||||||
log::LogOperation,
|
log::LogOperation,
|
||||||
},
|
},
|
||||||
mem::{
|
mem::{
|
||||||
kalloc::{kfree, kalloc},
|
kalloc::{kalloc, kfree},
|
||||||
memset,
|
memset,
|
||||||
virtual_memory::{uvmcreate, uvmfree, uvmunmap, mappages, uvmalloc, uvmdealloc, uvmcopy},
|
virtual_memory::{
|
||||||
|
copyout, mappages, uvmalloc, uvmcopy, uvmcreate, uvmdealloc, uvmfree, uvmunmap,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
sync::spinlock::Spinlock,
|
|
||||||
string::safestrcpy,
|
string::safestrcpy,
|
||||||
println,
|
sync::spinlock::Spinlock,
|
||||||
};
|
};
|
||||||
use core::{
|
use core::{
|
||||||
ffi::{c_char, c_void},
|
ffi::{c_char, c_void},
|
||||||
@ -65,6 +73,9 @@ pub enum ProcessState {
|
|||||||
pub enum ProcessError {
|
pub enum ProcessError {
|
||||||
MaxProcesses,
|
MaxProcesses,
|
||||||
Allocation,
|
Allocation,
|
||||||
|
NoChildren,
|
||||||
|
Killed,
|
||||||
|
PageError,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Per-process state.
|
/// Per-process state.
|
||||||
@ -180,7 +191,11 @@ impl Process {
|
|||||||
|
|
||||||
// Set up new context to start executing at forkret,
|
// Set up new context to start executing at forkret,
|
||||||
// which returns to userspace.
|
// which returns to userspace.
|
||||||
memset(addr_of_mut!(p.context).cast(), 0, core::mem::size_of::<Context>() as u32);
|
memset(
|
||||||
|
addr_of_mut!(p.context).cast(),
|
||||||
|
0,
|
||||||
|
core::mem::size_of::<Context>() as u32,
|
||||||
|
);
|
||||||
p.context.ra = forkret as usize as u64;
|
p.context.ra = forkret as usize as u64;
|
||||||
p.context.sp = p.kstack + PGSIZE;
|
p.context.sp = p.kstack + PGSIZE;
|
||||||
|
|
||||||
@ -213,7 +228,12 @@ impl Process {
|
|||||||
let mut size = self.sz;
|
let mut size = self.sz;
|
||||||
|
|
||||||
if num_bytes > 0 {
|
if num_bytes > 0 {
|
||||||
size = uvmalloc(self.pagetable, size, size.wrapping_add(num_bytes as u64), PTE_W);
|
size = uvmalloc(
|
||||||
|
self.pagetable,
|
||||||
|
size,
|
||||||
|
size.wrapping_add(num_bytes as u64),
|
||||||
|
PTE_W,
|
||||||
|
);
|
||||||
|
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
return Err(ProcessError::Allocation);
|
return Err(ProcessError::Allocation);
|
||||||
@ -239,13 +259,27 @@ impl Process {
|
|||||||
// at the highest user virtual address.
|
// at the highest user virtual address.
|
||||||
// Only the supervisor uses it on the way
|
// Only the supervisor uses it on the way
|
||||||
// to and from user space, so not PTE_U.
|
// to and from user space, so not PTE_U.
|
||||||
if mappages(pagetable, TRAMPOLINE, PGSIZE, addr_of!(trampoline) as usize as u64, PTE_R | PTE_X) < 0 {
|
if mappages(
|
||||||
|
pagetable,
|
||||||
|
TRAMPOLINE,
|
||||||
|
PGSIZE,
|
||||||
|
addr_of!(trampoline) as usize as u64,
|
||||||
|
PTE_R | PTE_X,
|
||||||
|
) < 0
|
||||||
|
{
|
||||||
uvmfree(pagetable, 0);
|
uvmfree(pagetable, 0);
|
||||||
return Err(ProcessError::Allocation);
|
return Err(ProcessError::Allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map the trapframe page just below the trampoline page for trampoline.S.
|
// Map the trapframe page just below the trampoline page for trampoline.S.
|
||||||
if mappages(pagetable, TRAPFRAME, PGSIZE, self.trapframe as usize as u64, PTE_R | PTE_W) < 0 {
|
if mappages(
|
||||||
|
pagetable,
|
||||||
|
TRAPFRAME,
|
||||||
|
PGSIZE,
|
||||||
|
self.trapframe as usize as u64,
|
||||||
|
PTE_R | PTE_W,
|
||||||
|
) < 0
|
||||||
|
{
|
||||||
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
|
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
|
||||||
uvmfree(pagetable, 0);
|
uvmfree(pagetable, 0);
|
||||||
return Err(ProcessError::Allocation);
|
return Err(ProcessError::Allocation);
|
||||||
@ -288,7 +322,11 @@ impl Process {
|
|||||||
}
|
}
|
||||||
child.cwd = idup(parent.cwd);
|
child.cwd = idup(parent.cwd);
|
||||||
|
|
||||||
safestrcpy(addr_of!(child.name[0]).cast_mut().cast(), addr_of!(parent.name[0]).cast_mut().cast(), parent.name.len() as i32);
|
safestrcpy(
|
||||||
|
addr_of!(child.name[0]).cast_mut().cast(),
|
||||||
|
addr_of!(parent.name[0]).cast_mut().cast(),
|
||||||
|
parent.name.len() as i32,
|
||||||
|
);
|
||||||
|
|
||||||
let pid = child.pid;
|
let pid = child.pid;
|
||||||
|
|
||||||
@ -354,9 +392,59 @@ impl Process {
|
|||||||
|
|
||||||
// Jump into the scheduler, never to return.
|
// Jump into the scheduler, never to return.
|
||||||
sched();
|
sched();
|
||||||
loop {
|
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wait for a child process to exit, and return its pid.
|
||||||
|
pub unsafe fn wait_for_child(&mut self, addr: u64) -> Result<i32, ProcessError> {
|
||||||
|
let guard = wait_lock.lock();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// Scan through the table looking for exited children.
|
||||||
|
let mut has_children = false;
|
||||||
|
|
||||||
|
for p in &mut proc {
|
||||||
|
if p.parent == addr_of_mut!(*self) {
|
||||||
|
has_children = true;
|
||||||
|
|
||||||
|
// Ensure the child isn't still in exit() or swtch().
|
||||||
|
p.lock.lock_unguarded();
|
||||||
|
|
||||||
|
if p.state == ProcessState::Zombie {
|
||||||
|
// Found an exited child.
|
||||||
|
let pid = p.pid;
|
||||||
|
|
||||||
|
if addr != 0
|
||||||
|
&& copyout(
|
||||||
|
self.pagetable,
|
||||||
|
addr,
|
||||||
|
addr_of_mut!(p.xstate).cast(),
|
||||||
|
core::mem::size_of::<i32>() as u64,
|
||||||
|
) < 0
|
||||||
|
{
|
||||||
|
p.lock.unlock();
|
||||||
|
return Err(ProcessError::PageError);
|
||||||
|
}
|
||||||
|
|
||||||
|
p.free();
|
||||||
|
p.lock.unlock();
|
||||||
|
return Ok(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
p.lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !has_children {
|
||||||
|
return Err(ProcessError::NoChildren);
|
||||||
|
} else if self.is_killed() {
|
||||||
|
return Err(ProcessError::Killed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for child to exit.
|
||||||
|
// DOC: wait-sleep
|
||||||
|
guard.sleep(addr_of_mut!(*self).cast());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Kill the process with the given pid.
|
/// Kill the process with the given pid.
|
||||||
@ -405,11 +493,6 @@ pub extern "C" fn myproc() -> *mut Process {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn allocpid() -> i32 {
|
|
||||||
Process::alloc_pid()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn allocproc() -> *mut Process {
|
pub unsafe extern "C" fn allocproc() -> *mut Process {
|
||||||
if let Ok(process) = Process::alloc() {
|
if let Ok(process) = Process::alloc() {
|
||||||
@ -419,13 +502,6 @@ pub unsafe extern "C" fn allocproc() -> *mut Process {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Free a proc structure and the data hanging from it, including user pages.
|
|
||||||
/// p->lock must be held.
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn freeproc(p: *mut Process) {
|
|
||||||
(*p).free();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn proc_pagetable(p: *mut Process) -> Pagetable {
|
pub unsafe extern "C" fn proc_pagetable(p: *mut Process) -> Pagetable {
|
||||||
(*p).alloc_pagetable().unwrap_or(null_mut())
|
(*p).alloc_pagetable().unwrap_or(null_mut())
|
||||||
@ -435,39 +511,3 @@ pub unsafe extern "C" fn proc_pagetable(p: *mut Process) -> Pagetable {
|
|||||||
pub unsafe extern "C" fn proc_freepagetable(pagetable: Pagetable, size: u64) {
|
pub unsafe extern "C" fn proc_freepagetable(pagetable: Pagetable, size: u64) {
|
||||||
Process::free_pagetable(pagetable, size as usize)
|
Process::free_pagetable(pagetable, size as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn reparent(p: *mut Process) {
|
|
||||||
(*p).reparent()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn exit(status: i32) -> ! {
|
|
||||||
Process::current().unwrap().exit(status)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Kill the process with the given pid.
|
|
||||||
/// The victim won't exit until it tries to return
|
|
||||||
/// to user space (see usertrap() in trap.c).
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn kill(pid: i32) -> i32 {
|
|
||||||
if Process::kill(pid) {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn setkilled(p: *mut Process) {
|
|
||||||
(*p).set_killed(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn killed(p: *mut Process) -> i32 {
|
|
||||||
if (*p).is_killed() {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
mem::virtual_memory::{copyin, copyinstr},
|
mem::virtual_memory::{copyin, copyinstr},
|
||||||
println,
|
println,
|
||||||
proc::process::{self, Process},
|
proc::process::Process,
|
||||||
string::strlen,
|
string::strlen,
|
||||||
trap::CLOCK_TICKS,
|
trap::CLOCK_TICKS,
|
||||||
NOFILE,
|
NOFILE,
|
||||||
@ -66,7 +66,8 @@ impl Syscall {
|
|||||||
Syscall::Wait => {
|
Syscall::Wait => {
|
||||||
let mut p = 0u64;
|
let mut p = 0u64;
|
||||||
argaddr(0, addr_of_mut!(p));
|
argaddr(0, addr_of_mut!(p));
|
||||||
process::wait(p) as u64
|
Process::current().unwrap().wait_for_child(p).unwrap_or(-1) as i64 as u64
|
||||||
|
// process::wait(p) as u64
|
||||||
}
|
}
|
||||||
Syscall::Pipe => sys_pipe(),
|
Syscall::Pipe => sys_pipe(),
|
||||||
Syscall::Read => {
|
Syscall::Read => {
|
||||||
|
@ -3,7 +3,7 @@ use crate::{
|
|||||||
println,
|
println,
|
||||||
proc::{
|
proc::{
|
||||||
cpu::Cpu,
|
cpu::Cpu,
|
||||||
process::{exit, Process, ProcessState},
|
process::{Process, ProcessState},
|
||||||
scheduler::{r#yield, wakeup},
|
scheduler::{r#yield, wakeup},
|
||||||
},
|
},
|
||||||
sync::mutex::Mutex,
|
sync::mutex::Mutex,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user