/* * Clone the current process. * * The new thread is given a copy of the caller's file handles if RET * is not null. (If RET is null, what we're creating is a kernel-only * thread and it doesn't need an address space or file handles.) * However, the new thread always inherits its current working * directory from the caller. The new thread is given no address space * (the caller decides that). */ int proc_fork(struct proc **ret) { struct proc *proc; struct filetable *tbl; int result; proc = proc_create(curproc->p_name); if (proc == NULL) { return ENOMEM; } /* VM fields */ /* do not clone address space -- let caller decide on that */ /* VFS fields */ tbl = curproc->p_filetable; if (tbl != NULL) { result = filetable_copy(tbl, &proc->p_filetable); if (result) { as_destroy(proc->p_addrspace); proc->p_addrspace = NULL; proc_destroy(proc); return result; } } spinlock_acquire(&curproc->p_lock); /* we don't need to lock proc->p_lock as we have the only reference */ if (curproc->p_cwd != NULL) { VOP_INCREF(curproc->p_cwd); proc->p_cwd = curproc->p_cwd; } spinlock_release(&curproc->p_lock); *ret = proc; return 0; }
int sys_fork(struct trapframe *tf, pid_t *retval) { int result; char* name; (void) result; (void) tf; (void) retval; struct trapframe *temp_tf = kmalloc(sizeof(*temp_tf)); *temp_tf = *tf; struct proc *newproc = proc_create("forked_process"); // TODO: concurrency issue? as_copy(curproc->p_addrspace, &newproc->p_addrspace); newproc->p_filetable = kmalloc(sizeof(struct filetable)); newproc->p_filetable->filetable_lock = lock_create("filetable_lock"); filetable_copy(newproc->p_filetable); // copied from proc.c init p_cwd spinlock_acquire(&curproc->p_lock); if (curproc->p_cwd != NULL) { VOP_INCREF(curproc->p_cwd); newproc->p_cwd = curproc->p_cwd; } spinlock_release(&curproc->p_lock); newproc->parent_pid = curproc->pid; name = kstrdup(curproc->p_name); *retval = newproc->pid; thread_fork(name, newproc ,run_forked_proc, (void *)temp_tf, 0); return 0; }
int sys_fork(struct trapframe* tf, pid_t* retval) { DEBUG(DB_EXEC,"sys_fork(): entering\n"); KASSERT(curproc != NULL); KASSERT(sizeof(struct trapframe)==(37*4)); char* child_name = kmalloc(sizeof(char)* NAME_MAX); strcpy(child_name, curproc->p_name); strcat(child_name, "_c"); // create PCB for child struct proc* child_proc = NULL; proc_fork(&child_proc); if (child_proc == NULL) { return ENOMEM; } strcpy(child_proc->p_name, child_name); KASSERT(child_proc->p_pid > 0); // copy address space and registers from this process to child struct addrspace* child_as = kmalloc(sizeof(struct addrspace)); if (child_as == NULL) { kfree(child_name); proc_destroy(child_proc); return ENOMEM; } struct trapframe* child_tf = kmalloc(sizeof(struct trapframe)); if (child_tf == NULL) { kfree(child_name); as_destroy(child_as); proc_destroy(child_proc); return ENOMEM; } DEBUG(DB_EXEC,"sys_fork(): copying address space...\n"); // copy the address space just created into the child process's // PCB structure int result = as_copy(curproc->p_addrspace, &child_as); if (result) { kfree(child_name); as_destroy(child_as); proc_destroy(child_proc); return result; } child_proc->p_addrspace = child_as; DEBUG(DB_EXEC,"sys_fork(): copying trapframe space...\n"); // copy this process's trapframe to the child process memcpy(child_tf, tf, sizeof(struct trapframe)); DEBUG(DB_EXEC, "sys_fork(): copying filetable...\n"); filetable_copy(curproc->p_filetable,&child_proc->p_filetable); DEBUG(DB_EXEC,"sys_fork(): assigning child process's parent as this process...\n"); // assign child processes parent as this process child_proc->p_parent = curproc; DEBUG(DB_EXEC,"sys_fork(): adding child to children procarray...\n"); result = procarray_add(&curproc->p_children, child_proc, NULL); if (result) { DEBUG(DB_EXEC, "sys_fork(): failed to add child process to proc_table...\n"); } DEBUG(DB_EXEC,"sys_fork(): allocating data...\n"); void **data = kmalloc(2*sizeof(void*)); data[0] = (void*)child_tf; data[1] = (void*)child_as; result = thread_fork(child_name, child_proc, &enter_forked_process, data, 0); if (result) { kfree(child_name); kfree(child_tf); as_destroy(child_as); proc_destroy(child_proc); return ENOMEM; } *retval = child_proc->p_pid; DEBUG(DB_EXEC, "sys_fork(): thread_fork returned: curproc=%u, child_proc=%u\n",curproc->p_pid,child_proc->p_pid); return 0; }