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

View File

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

View File

@ -108,5 +108,3 @@ struct proc {
struct inode *cwd; // Current directory
char name[16]; // Process name (debugging)
};
int allocpid();

View File

@ -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);
@ -234,23 +254,37 @@ impl Process {
if pagetable.is_null() {
return Err(ProcessError::Allocation);
}
// Map the trampoline code (for syscall return)
// 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);
}
Ok(pagetable)
}
/// Free a process's pagetable and free the physical memory it refers to.
@ -288,8 +322,12 @@ 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;
child.lock.unlock();
@ -354,8 +392,58 @@ impl Process {
// Jump into the scheduler, never to return.
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 {
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]
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
}
}

View File

@ -52,7 +52,7 @@ pub unsafe fn scheduler() -> ! {
// Run the process.
swtch(addr_of_mut!(cpu.context), addr_of_mut!(p.context));
// Process is done running for now.
// It should have changed its state before coming back.
cpu.proc = null_mut();

View File

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

View File

@ -3,7 +3,7 @@ use crate::{
println,
proc::{
cpu::Cpu,
process::{exit, Process, ProcessState},
process::{Process, ProcessState},
scheduler::{r#yield, wakeup},
},
sync::mutex::Mutex,