fork()
This commit is contained in:
parent
6342f66cd3
commit
badd35b3f9
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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<i32, ProcessError> {
|
||||
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
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user