/* do_fork - parent process for a new child process * @clone_flags: used to guide how to clone the child process * @stack: the parent's user stack pointer. if stack==0, It means to fork a kernel thread. * @tf: the trapframe info, which will be copied to child process's proc->tf */ int do_fork(uint32_t clone_flags, uintptr_t stack, struct trapframe *tf) { int ret = -E_NO_FREE_PROC; struct proc_struct *proc; if (nr_process >= MAX_PROCESS) { goto fork_out; } ret = -E_NO_MEM; //LAB4:EXERCISE2 2013011303 /* * Some Useful MACROs, Functions and DEFINEs, you can use them in below implementation. * MACROs or Functions: * alloc_proc: create a proc struct and init fields (lab4:exercise1) * setup_kstack: alloc pages with size KSTACKPAGE as process kernel stack * copy_mm: process "proc" duplicate OR share process "current"'s mm according clone_flags * if clone_flags & CLONE_VM, then "share" ; else "duplicate" * copy_thread: setup the trapframe on the process's kernel stack top and * setup the kernel entry point and stack of process * hash_proc: add proc into proc hash_list * get_pid: alloc a unique pid for process * wakup_proc: set proc->state = PROC_RUNNABLE * VARIABLES: * proc_list: the process set's list * nr_process: the number of process set */ // 1. call alloc_proc to allocate a proc_struct // 2. call setup_kstack to allocate a kernel stack for child process // 3. call copy_mm to dup OR share mm according clone_flag // 4. call copy_thread to setup tf & context in proc_struct // 5. insert proc_struct into hash_list && proc_list // 6. call wakup_proc to make the new child process RUNNABLE // 7. set ret vaule using child proc's pid if ((proc = alloc_proc()) == NULL) { goto fork_out; } proc->pid = get_pid(); proc->parent = current; nr_process++; if (setup_kstack(proc)) { goto bad_fork_cleanup_proc; } if (copy_mm(clone_flags, proc)) { goto bad_fork_cleanup_kstack; } copy_thread(proc, stack, tf); hash_proc(proc); list_add(&proc_list, &(proc->list_link)); wakeup_proc(proc); ret = proc->pid; fork_out: return ret; bad_fork_cleanup_kstack: put_kstack(proc); bad_fork_cleanup_proc: kfree(proc); goto fork_out; }
// do_fork - parent process for a new child process // 1. call alloc_proc to allocate a proc_struct // 2. call setup_kstack to allocate a kernel stack for child process // 3. call copy_mm to dup OR share mm according clone_flag // 4. call wakup_proc to make the new child process RUNNABLE int do_fork(uint32_t clone_flags, uintptr_t stack, struct trapframe *tf) { int ret = -E_NO_FREE_PROC; struct proc_struct *proc; if (nr_process >= MAX_PROCESS) { goto fork_out; } ret = -E_NO_MEM; if ((proc = alloc_proc()) == NULL) { goto fork_out; } proc->parent = current; if (setup_kstack(proc) != 0) { goto bad_fork_cleanup_proc; } if (copy_mm(clone_flags, proc) != 0) { goto bad_fork_cleanup_kstack; } copy_thread(proc, stack, tf); unsigned long intr_flag; local_irq_save(intr_flag); { proc->pid = get_pid(); hash_proc(proc); list_add(&proc_list, &(proc->list_link)); nr_process ++; } local_irq_restore(intr_flag); wakeup_proc(proc); ret = proc->pid; fork_out: return ret; bad_fork_cleanup_kstack: put_kstack(proc); bad_fork_cleanup_proc: kfree(proc); goto fork_out; }
// do_fork - parent process for a new child process // 1. call alloc_proc to allocate a proc_struct // 2. call setup_kstack to allocate a kernel stack for child process // 3. call copy_mm to dup OR share mm according clone_flag // 4. call wakup_proc to make the new child process RUNNABLE int do_fork(uint32_t clone_flags, uintptr_t stack, struct trapframe *tf) { int ret = -E_NO_FREE_PROC; struct proc_struct *proc; if (nr_process >= MAX_PROCESS) { goto fork_out; } ret = -E_NO_MEM; if ((proc = alloc_proc()) == NULL) { goto fork_out; } proc->parent = current; list_init(&(proc->thread_group)); assert(current->wait_state == 0); assert(current->time_slice >= 0); proc->time_slice = current->time_slice / 2; current->time_slice -= proc->time_slice; if (setup_kstack(proc) != 0) { goto bad_fork_cleanup_proc; } if (copy_sem(clone_flags, proc) != 0) { goto bad_fork_cleanup_kstack; } if (copy_fs(clone_flags, proc) != 0) { goto bad_fork_cleanup_sem; } if ( copy_signal(clone_flags, proc) != 0 ) { goto bad_fork_cleanup_fs; } if ( copy_sighand(clone_flags, proc) != 0 ) { goto bad_fork_cleanup_signal; } if (copy_mm(clone_flags, proc) != 0) { goto bad_fork_cleanup_sighand; } if (copy_thread(clone_flags, proc, stack, tf) != 0) { goto bad_fork_cleanup_sighand; } bool intr_flag; local_intr_save(intr_flag); { proc->pid = get_pid(); proc->tid = proc->pid; hash_proc(proc); set_links(proc); if (clone_flags & CLONE_THREAD) { list_add_before(&(current->thread_group), &(proc->thread_group)); proc->gid = current->gid; }else{ proc->gid = proc->pid; } } local_intr_restore(intr_flag); wakeup_proc(proc); ret = proc->pid; fork_out: return ret; bad_fork_cleanup_sighand: put_sighand(proc); bad_fork_cleanup_signal: put_signal(proc); bad_fork_cleanup_fs: put_fs(proc); bad_fork_cleanup_sem: put_sem_queue(proc); bad_fork_cleanup_kstack: put_kstack(proc); bad_fork_cleanup_proc: kfree(proc); goto fork_out; }