From 8dc10d24f019c60050e74bf20383d0ac836d59cf Mon Sep 17 00:00:00 2001 From: Garen Tyler Date: Fri, 3 Nov 2023 21:05:01 -0600 Subject: [PATCH] wait --- kernel/defs.h | 2 - kernel/proc.c | 56 -------- kernel/proc.h | 2 - kernel/rustkernel/src/proc/process.rs | 172 +++++++++++++++--------- kernel/rustkernel/src/proc/scheduler.rs | 2 +- kernel/rustkernel/src/syscall.rs | 5 +- kernel/rustkernel/src/trap.rs | 2 +- 7 files changed, 111 insertions(+), 130 deletions(-) diff --git a/kernel/defs.h b/kernel/defs.h index 5eda245..b9ea516 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -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); diff --git a/kernel/proc.c b/kernel/proc.c index 2ba8fe3..b93b14b 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -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. diff --git a/kernel/proc.h b/kernel/proc.h index 910f4c2..b34dde0 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -108,5 +108,3 @@ struct proc { struct inode *cwd; // Current directory char name[16]; // Process name (debugging) }; - -int allocpid(); diff --git a/kernel/rustkernel/src/proc/process.rs b/kernel/rustkernel/src/proc/process.rs index 58c3bd1..6f40cad 100644 --- a/kernel/rustkernel/src/proc/process.rs +++ b/kernel/rustkernel/src/proc/process.rs @@ -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::() as u32); + memset( + addr_of_mut!(p.context).cast(), + 0, + core::mem::size_of::() 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 { + 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::() 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 - } -} diff --git a/kernel/rustkernel/src/proc/scheduler.rs b/kernel/rustkernel/src/proc/scheduler.rs index 1deb8cb..45f0cbc 100644 --- a/kernel/rustkernel/src/proc/scheduler.rs +++ b/kernel/rustkernel/src/proc/scheduler.rs @@ -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(); diff --git a/kernel/rustkernel/src/syscall.rs b/kernel/rustkernel/src/syscall.rs index 22f3e36..7305a9e 100644 --- a/kernel/rustkernel/src/syscall.rs +++ b/kernel/rustkernel/src/syscall.rs @@ -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 => { diff --git a/kernel/rustkernel/src/trap.rs b/kernel/rustkernel/src/trap.rs index 6c64e11..f3aece7 100644 --- a/kernel/rustkernel/src/trap.rs +++ b/kernel/rustkernel/src/trap.rs @@ -3,7 +3,7 @@ use crate::{ println, proc::{ cpu::Cpu, - process::{exit, Process, ProcessState}, + process::{Process, ProcessState}, scheduler::{r#yield, wakeup}, }, sync::mutex::Mutex,