#include <types.h>
#include <lib.h>
#include <copyinout.h>
#include <proc.h>
#include <thread.h>
#include <current.h>
#include <filedesc.h>
#include <addrspace.h>
#include <kern/errno.h>
#include <machine/trapframe.h>
#include <synch.h>
#include <syscall.h>
struct child_fork_args {
struct addrspace *as_source;
struct proc *td_proc;
struct trapframe *tf;
};
static
void
fork_child_return( void *v_args, unsigned long not_used ) {
struct child_fork_args *args = NULL;
struct trapframe tf;
(void)not_used;
args = v_args;
args->tf->tf_v0 = 0;
args->tf->tf_a3 = 0;
args->tf->tf_epc += 4;
curthread->td_proc = args->td_proc;
KASSERT( curthread->t_addrspace == NULL );
curthread->t_addrspace = args->as_source;
as_activate( curthread->t_addrspace );
memcpy( &tf, args->tf, sizeof( struct trapframe ) );
kfree( args->tf );
kfree( args );
mips_usermode( &tf );
}
static
int
trapframe_clone( struct trapframe *tf, struct trapframe **newtf ) {
*newtf = kmalloc( sizeof( struct trapframe ) );
if( *newtf == NULL )
return ENOMEM;
memcpy( *newtf, tf, sizeof( struct trapframe ) );
return 0;
}
int
sys_fork( struct trapframe *tf, int *retval ) {
struct proc *p_new = NULL;
struct trapframe *tf_new = NULL;
int err;
struct child_fork_args *args;
pid_t pid;
KASSERT( curthread != NULL );
KASSERT( curthread->td_proc != NULL );
KASSERT( tf != NULL );
err = proc_clone( curthread->td_proc, &p_new );
if( err )
return err;
pid = p_new->p_pid;
p_new->p_proc = curthread->td_proc;
err = trapframe_clone( tf, &tf_new );
if( err ) {
file_close_all( p_new );
proc_destroy( p_new );
return err;
}
args = kmalloc( sizeof( struct child_fork_args ) );
if( args == NULL ) {
kfree( tf_new );
file_close_all( p_new );
proc_destroy( p_new );
return ENOMEM;
}
args->tf = tf_new;
args->td_proc = p_new;
err = as_copy( curthread->t_addrspace, &args->as_source );
if( err ) {
kfree( args->tf );
kfree( args );
file_close_all( p_new );
proc_destroy( p_new );
return err;
}
err = thread_fork(
curthread->t_name,
fork_child_return,
args,
0,
NULL
);
if( err ) {
as_destroy( args->as_source );
kfree( args->tf );
kfree( args );
file_close_all( p_new );
proc_destroy( p_new );
return err;
}
*retval = pid;
return 0;
}