From badd35b3f9029fa157bd285451b4cc7cfbb6c446 Mon Sep 17 00:00:00 2001 From: Garen Tyler Date: Fri, 3 Nov 2023 20:14:57 -0600 Subject: [PATCH] fork() --- kernel/defs.h | 1 - kernel/proc.c | 51 ---------------------- kernel/rustkernel/src/fs/mod.rs | 2 +- kernel/rustkernel/src/proc/process.rs | 57 +++++++++++++++++++++---- kernel/rustkernel/src/proc/trapframe.rs | 2 +- kernel/rustkernel/src/syscall.rs | 2 +- 6 files changed, 52 insertions(+), 63 deletions(-) diff --git a/kernel/defs.h b/kernel/defs.h index 6cae3f6..87f84e4 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -80,7 +80,6 @@ void printint(int n); // proc.c void exit(int); -int fork(void); void proc_mapstacks(pagetable_t); pagetable_t proc_pagetable(struct proc *); void proc_freepagetable(pagetable_t, uint64); diff --git a/kernel/proc.c b/kernel/proc.c index 5b3db32..0809d0c 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -105,57 +105,6 @@ userinit(void) release(&p->lock); } -// Create a new process, copying the parent. -// Sets up child kernel stack to return as if from fork() system call. -int -fork(void) -{ - int i, pid; - struct proc *np; - struct proc *p = myproc(); - - // Allocate process. - if((np = allocproc()) == 0){ - return -1; - } - - // Copy user memory from parent to child. - if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){ - freeproc(np); - release(&np->lock); - return -1; - } - np->sz = p->sz; - - // copy saved user registers. - *(np->trapframe) = *(p->trapframe); - - // Cause fork to return 0 in the child. - np->trapframe->a0 = 0; - - // increment reference counts on open file descriptors. - for(i = 0; i < NOFILE; i++) - if(p->ofile[i]) - np->ofile[i] = filedup(p->ofile[i]); - np->cwd = idup(p->cwd); - - safestrcpy(np->name, p->name, sizeof(p->name)); - - pid = np->pid; - - release(&np->lock); - - acquire(&wait_lock); - np->parent = p; - release(&wait_lock); - - acquire(&np->lock); - np->state = RUNNABLE; - release(&np->lock); - - return pid; -} - // Pass p's abandoned children to init. // Caller must hold wait_lock. void reparent(struct proc *p); diff --git a/kernel/rustkernel/src/fs/mod.rs b/kernel/rustkernel/src/fs/mod.rs index 91b6ff5..dde2296 100644 --- a/kernel/rustkernel/src/fs/mod.rs +++ b/kernel/rustkernel/src/fs/mod.rs @@ -91,7 +91,7 @@ extern "C" { pub fn iinit(); pub fn ialloc(dev: u32, kind: i16) -> *mut DiskInode; pub fn iupdate(ip: *mut DiskInode); - pub fn idup(ip: *mut DiskInode) -> *mut DiskInode; + pub fn idup(ip: *mut Inode) -> *mut Inode; pub fn ilock(ip: *mut Inode); pub fn iunlock(ip: *mut Inode); pub fn iput(ip: *mut Inode); diff --git a/kernel/rustkernel/src/proc/process.rs b/kernel/rustkernel/src/proc/process.rs index a854ff5..d5633f9 100644 --- a/kernel/rustkernel/src/proc/process.rs +++ b/kernel/rustkernel/src/proc/process.rs @@ -3,13 +3,14 @@ use super::{context::Context, cpu::Cpu, scheduler::wakeup, trapframe::Trapframe}; use crate::{ arch::riscv::{Pagetable, PTE_W, PTE_R, PTE_X, PGSIZE, memlayout::{TRAMPOLINE, TRAPFRAME}}, - fs::file::{File, Inode}, + fs::{file::{File, Inode, filedup}, idup}, mem::{ kalloc::{kfree, kalloc}, memset, - virtual_memory::{uvmcreate, uvmfree, uvmunmap, mappages}, + virtual_memory::{uvmcreate, uvmfree, uvmunmap, mappages, uvmalloc, uvmdealloc, uvmcopy}, }, sync::spinlock::Spinlock, + string::safestrcpy, }; use core::{ ffi::{c_char, c_void}, @@ -33,16 +34,11 @@ extern "C" { pub fn procinit(); pub fn userinit(); pub fn forkret(); - pub fn fork() -> i32; + // pub fn fork() -> i32; pub fn exit(status: i32) -> !; pub fn wait(addr: u64) -> i32; pub fn procdump(); pub fn proc_mapstacks(kpgtbl: Pagetable); - // pub fn proc_pagetable(p: *mut Process) -> Pagetable; - // pub fn proc_freepagetable(pagetable: Pagetable, sz: u64); - // pub fn allocproc() -> *mut Process; - pub fn uvmalloc(pagetable: Pagetable, oldsz: u64, newsz: u64, xperm: i32) -> u64; - pub fn uvmdealloc(pagetable: Pagetable, oldsz: u64, newsz: u64) -> u64; } pub static NEXT_PID: AtomicI32 = AtomicI32::new(1); @@ -258,6 +254,51 @@ impl Process { uvmfree(pagetable, size as u64) } + /// Create a new process, copying the parent. + /// Sets up child kernel stack to return as if from fork() syscall. + pub unsafe fn fork() -> Result { + let parent = Process::current().unwrap(); + let child = Process::alloc()?; + + // Copy user memory from parent to child. + if uvmcopy(parent.pagetable, child.pagetable, parent.sz) < 0 { + child.free(); + child.lock.unlock(); + return Err(ProcessError::Allocation); + } + child.sz = parent.sz; + + // Copy saved user registers. + *child.trapframe = *parent.trapframe; + + // Cause fork to return 0 in the child. + (*child.trapframe).a0 = 0; + + // Increment reference counts on open file descriptors. + for (i, file) in parent.ofile.iter().enumerate() { + if !file.is_null() { + child.ofile[i] = filedup(parent.ofile[i]); + } + } + 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); + + let pid = child.pid; + + child.lock.unlock(); + { + let _guard = wait_lock.lock(); + child.parent = addr_of!(*parent).cast_mut(); + } + { + let _guard = child.lock.lock(); + child.state = ProcessState::Runnable; + } + + Ok(pid) + } + /// Kill the process with the given pid. /// Returns true if the process was killed. /// The victim won't exit until it tries to return diff --git a/kernel/rustkernel/src/proc/trapframe.rs b/kernel/rustkernel/src/proc/trapframe.rs index 2f835a7..0df0cd6 100644 --- a/kernel/rustkernel/src/proc/trapframe.rs +++ b/kernel/rustkernel/src/proc/trapframe.rs @@ -12,7 +12,7 @@ /// return-to-user path via usertrapret() doesn't return through /// the entire kernel call stack. #[repr(C)] -#[derive(Default)] +#[derive(Copy, Clone, Default)] pub struct Trapframe { /// Kernel page table. pub kernel_satp: u64, diff --git a/kernel/rustkernel/src/syscall.rs b/kernel/rustkernel/src/syscall.rs index c770335..beecd6f 100644 --- a/kernel/rustkernel/src/syscall.rs +++ b/kernel/rustkernel/src/syscall.rs @@ -57,7 +57,7 @@ pub enum Syscall { impl Syscall { pub unsafe fn call(&self) -> u64 { match self { - Syscall::Fork => process::fork() as u64, + Syscall::Fork => Process::fork().unwrap_or(-1) as i64 as u64, Syscall::Exit => { let mut n = 0i32; argint(0, addr_of_mut!(n));