This commit is contained in:
Garen Tyler 2023-11-03 21:05:01 -06:00
parent 0a1e889d54
commit 8dc10d24f0
Signed by: garentyler
GPG Key ID: D7A048C454CB7054
7 changed files with 111 additions and 130 deletions

View File

@ -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);

View File

@ -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.

View File

@ -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();

View File

@ -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,8 +392,58 @@ impl Process {
// Jump into the scheduler, never to return. // Jump into the scheduler, never to return.
sched(); sched();
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 { loop {
unreachable!(); // 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());
} }
} }
@ -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
}
}

View File

@ -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 => {

View File

@ -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,