fork()
This commit is contained in:
parent
6342f66cd3
commit
badd35b3f9
@ -80,7 +80,6 @@ void printint(int n);
|
|||||||
|
|
||||||
// proc.c
|
// proc.c
|
||||||
void exit(int);
|
void exit(int);
|
||||||
int fork(void);
|
|
||||||
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);
|
||||||
|
@ -105,57 +105,6 @@ userinit(void)
|
|||||||
release(&p->lock);
|
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.
|
// Pass p's abandoned children to init.
|
||||||
// Caller must hold wait_lock.
|
// Caller must hold wait_lock.
|
||||||
void reparent(struct proc *p);
|
void reparent(struct proc *p);
|
||||||
|
@ -91,7 +91,7 @@ extern "C" {
|
|||||||
pub fn iinit();
|
pub fn iinit();
|
||||||
pub fn ialloc(dev: u32, kind: i16) -> *mut DiskInode;
|
pub fn ialloc(dev: u32, kind: i16) -> *mut DiskInode;
|
||||||
pub fn iupdate(ip: *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 ilock(ip: *mut Inode);
|
||||||
pub fn iunlock(ip: *mut Inode);
|
pub fn iunlock(ip: *mut Inode);
|
||||||
pub fn iput(ip: *mut Inode);
|
pub fn iput(ip: *mut Inode);
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
use super::{context::Context, cpu::Cpu, scheduler::wakeup, trapframe::Trapframe};
|
use super::{context::Context, cpu::Cpu, scheduler::wakeup, trapframe::Trapframe};
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::riscv::{Pagetable, PTE_W, PTE_R, PTE_X, PGSIZE, memlayout::{TRAMPOLINE, TRAPFRAME}},
|
arch::riscv::{Pagetable, PTE_W, PTE_R, PTE_X, PGSIZE, memlayout::{TRAMPOLINE, TRAPFRAME}},
|
||||||
fs::file::{File, Inode},
|
fs::{file::{File, Inode, filedup}, idup},
|
||||||
mem::{
|
mem::{
|
||||||
kalloc::{kfree, kalloc},
|
kalloc::{kfree, kalloc},
|
||||||
memset,
|
memset,
|
||||||
virtual_memory::{uvmcreate, uvmfree, uvmunmap, mappages},
|
virtual_memory::{uvmcreate, uvmfree, uvmunmap, mappages, uvmalloc, uvmdealloc, uvmcopy},
|
||||||
},
|
},
|
||||||
sync::spinlock::Spinlock,
|
sync::spinlock::Spinlock,
|
||||||
|
string::safestrcpy,
|
||||||
};
|
};
|
||||||
use core::{
|
use core::{
|
||||||
ffi::{c_char, c_void},
|
ffi::{c_char, c_void},
|
||||||
@ -33,16 +34,11 @@ extern "C" {
|
|||||||
pub fn procinit();
|
pub fn procinit();
|
||||||
pub fn userinit();
|
pub fn userinit();
|
||||||
pub fn forkret();
|
pub fn forkret();
|
||||||
pub fn fork() -> i32;
|
// pub fn fork() -> i32;
|
||||||
pub fn exit(status: i32) -> !;
|
pub fn exit(status: i32) -> !;
|
||||||
pub fn wait(addr: u64) -> i32;
|
pub fn wait(addr: u64) -> i32;
|
||||||
pub fn procdump();
|
pub fn procdump();
|
||||||
pub fn proc_mapstacks(kpgtbl: Pagetable);
|
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);
|
pub static NEXT_PID: AtomicI32 = AtomicI32::new(1);
|
||||||
@ -258,6 +254,51 @@ impl Process {
|
|||||||
uvmfree(pagetable, size as u64)
|
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.
|
/// Kill the process with the given pid.
|
||||||
/// Returns true if the process was killed.
|
/// Returns true if the process was killed.
|
||||||
/// The victim won't exit until it tries to return
|
/// The victim won't exit until it tries to return
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
/// return-to-user path via usertrapret() doesn't return through
|
/// return-to-user path via usertrapret() doesn't return through
|
||||||
/// the entire kernel call stack.
|
/// the entire kernel call stack.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Default)]
|
#[derive(Copy, Clone, Default)]
|
||||||
pub struct Trapframe {
|
pub struct Trapframe {
|
||||||
/// Kernel page table.
|
/// Kernel page table.
|
||||||
pub kernel_satp: u64,
|
pub kernel_satp: u64,
|
||||||
|
@ -57,7 +57,7 @@ pub enum Syscall {
|
|||||||
impl Syscall {
|
impl Syscall {
|
||||||
pub unsafe fn call(&self) -> u64 {
|
pub unsafe fn call(&self) -> u64 {
|
||||||
match self {
|
match self {
|
||||||
Syscall::Fork => process::fork() as u64,
|
Syscall::Fork => Process::fork().unwrap_or(-1) as i64 as u64,
|
||||||
Syscall::Exit => {
|
Syscall::Exit => {
|
||||||
let mut n = 0i32;
|
let mut n = 0i32;
|
||||||
argint(0, addr_of_mut!(n));
|
argint(0, addr_of_mut!(n));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user