wait
This commit is contained in:
parent
0a1e889d54
commit
8dc10d24f0
@ -82,13 +82,11 @@ void printint(int n);
|
||||
void proc_mapstacks(pagetable_t);
|
||||
pagetable_t proc_pagetable(struct proc *);
|
||||
void proc_freepagetable(pagetable_t, uint64);
|
||||
int killed(struct proc *);
|
||||
struct cpu *mycpu(void);
|
||||
struct proc *myproc();
|
||||
void procinit(void);
|
||||
void sleep_lock(void *, struct spinlock *);
|
||||
void userinit(void);
|
||||
int wait(uint64);
|
||||
void wakeup(void *);
|
||||
int either_copyout(int user_dst, uint64 dst, void *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;
|
||||
|
||||
extern void forkret(void);
|
||||
void freeproc(struct proc *p);
|
||||
|
||||
extern char trampoline[]; // trampoline.S
|
||||
|
||||
@ -105,59 +104,6 @@ userinit(void)
|
||||
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()
|
||||
// will swtch to forkret.
|
||||
void
|
||||
@ -200,8 +146,6 @@ void wakeup(void *chan)
|
||||
}
|
||||
}
|
||||
|
||||
int killed(struct proc *p);
|
||||
|
||||
// Copy to either a user address, or kernel address,
|
||||
// depending on usr_dst.
|
||||
// Returns 0 on success, -1 on error.
|
||||
|
@ -108,5 +108,3 @@ struct proc {
|
||||
struct inode *cwd; // Current directory
|
||||
char name[16]; // Process name (debugging)
|
||||
};
|
||||
|
||||
int allocpid();
|
||||
|
@ -1,22 +1,30 @@
|
||||
#![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::{
|
||||
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::{
|
||||
file::{File, Inode, filedup, fileclose},
|
||||
idup,
|
||||
iput,
|
||||
file::{fileclose, filedup, File, Inode},
|
||||
idup, iput,
|
||||
log::LogOperation,
|
||||
},
|
||||
mem::{
|
||||
kalloc::{kfree, kalloc},
|
||||
kalloc::{kalloc, kfree},
|
||||
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,
|
||||
println,
|
||||
sync::spinlock::Spinlock,
|
||||
};
|
||||
use core::{
|
||||
ffi::{c_char, c_void},
|
||||
@ -65,6 +73,9 @@ pub enum ProcessState {
|
||||
pub enum ProcessError {
|
||||
MaxProcesses,
|
||||
Allocation,
|
||||
NoChildren,
|
||||
Killed,
|
||||
PageError,
|
||||
}
|
||||
|
||||
/// Per-process state.
|
||||
@ -180,7 +191,11 @@ impl Process {
|
||||
|
||||
// Set up new context to start executing at forkret,
|
||||
// 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.sp = p.kstack + PGSIZE;
|
||||
|
||||
@ -213,7 +228,12 @@ impl Process {
|
||||
let mut size = self.sz;
|
||||
|
||||
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 {
|
||||
return Err(ProcessError::Allocation);
|
||||
@ -239,13 +259,27 @@ impl Process {
|
||||
// at the highest user virtual address.
|
||||
// Only the supervisor uses it on the way
|
||||
// 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);
|
||||
return Err(ProcessError::Allocation);
|
||||
}
|
||||
|
||||
// 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);
|
||||
uvmfree(pagetable, 0);
|
||||
return Err(ProcessError::Allocation);
|
||||
@ -288,7 +322,11 @@ impl Process {
|
||||
}
|
||||
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;
|
||||
|
||||
@ -354,9 +392,59 @@ impl Process {
|
||||
|
||||
// Jump into the scheduler, never to return.
|
||||
sched();
|
||||
loop {
|
||||
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.
|
||||
@ -405,11 +493,6 @@ pub extern "C" fn myproc() -> *mut Process {
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn allocpid() -> i32 {
|
||||
Process::alloc_pid()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn allocproc() -> *mut Process {
|
||||
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]
|
||||
pub unsafe extern "C" fn proc_pagetable(p: *mut Process) -> Pagetable {
|
||||
(*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) {
|
||||
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},
|
||||
println,
|
||||
proc::process::{self, Process},
|
||||
proc::process::Process,
|
||||
string::strlen,
|
||||
trap::CLOCK_TICKS,
|
||||
NOFILE,
|
||||
@ -66,7 +66,8 @@ impl Syscall {
|
||||
Syscall::Wait => {
|
||||
let mut p = 0u64;
|
||||
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::Read => {
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
println,
|
||||
proc::{
|
||||
cpu::Cpu,
|
||||
process::{exit, Process, ProcessState},
|
||||
process::{Process, ProcessState},
|
||||
scheduler::{r#yield, wakeup},
|
||||
},
|
||||
sync::mutex::Mutex,
|
||||
|
Loading…
x
Reference in New Issue
Block a user