/* 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 * @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 2012011346 /* * 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_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 * wakeup_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 proc = alloc_proc(); proc->pid = get_pid(); cprintf("fork pid = %d\n", proc->pid); // 2. call setup_kstack to allocate a kernel stack for child process setup_kstack(proc); // 3. call copy_thread to setup tf & context in proc_struct copy_thread(proc, stack, tf); // 4. insert proc_struct into proc_list list_add_before(&proc_list, &proc->list_link); // 5. call wakeup_proc to make the new child process RUNNABLE wakeup_proc(proc); // 7. set ret vaule using child proc's pid nr_process++; ret = proc->pid; // 8. set parent proc->parent = current; 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_wait - wait one OR any children with PROC_ZOMBIE state, and free memory space of kernel stack // - proc struct of this child. // NOTE: only after do_wait function, all resources of the child proces are free. int do_wait(int pid, int *code_store) { struct proc_struct *proc; bool intr_flag, haskid; repeat: cprintf("do_wait: begin\n"); haskid = 0; list_entry_t *list = &proc_list, *le = list; while ((le = list_next(le)) != list) { proc = le2proc(le, list_link); if (proc != NULL) { haskid = 1; if (proc->state == PROC_ZOMBIE) { goto found; } } } if (haskid) { cprintf("do_wait: has kid begin\n"); cprintf("proc_wait:: pid: %d, name: %s from PROC_RUNABLE to PROC_SLEEPING\n",current->pid, current->name); current->state = PROC_SLEEPING; current->wait_state = WT_CHILD; schedule(); goto repeat; } return -E_BAD_PROC; found: cprintf("do_wait: has kid find child pid%d\n",proc->pid); cprintf("proc_exit:: pid: %d, name: %s from PROC_ZOMBIE to exit\n",proc->pid, proc->name); if (proc == idleproc ) { panic("wait idleproc \n"); } local_intr_save(intr_flag); { remove_links(proc); } local_intr_restore(intr_flag); put_kstack(proc); kfree(proc); return 0; }
// 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; }
int do_linux_waitpid(int pid, int *code_store) { struct mm_struct *mm = current->mm; if (code_store != NULL) { if (!user_mem_check(mm, (uintptr_t)code_store, sizeof(int), 1)) { return -E_INVAL; } } struct proc_struct *proc, *cproc; bool intr_flag, haskid; repeat: cproc = current; haskid = 0; if (pid > 0) { proc = find_proc(pid); if (proc != NULL) { do { if (proc->parent == cproc) { haskid = 1; if (proc->state == PROC_ZOMBIE) { goto found; } break; } cproc = next_thread(cproc); } while (cproc != current); } } /* we do NOT have group id, so..*/ else if(pid==0 || pid==-1){ /* pid == 0 */ do { proc = cproc->cptr; for (; proc != NULL; proc = proc->optr) { haskid = 1; if (proc->state == PROC_ZOMBIE) { goto found; } } cproc = next_thread(cproc); } while (cproc != current); }else{ //pid<-1 //TODO return -E_INVAL; } if (haskid) { current->state = PROC_SLEEPING; current->wait_state = WT_CHILD; schedule(); may_killed(); goto repeat; } return -E_BAD_PROC; found: if (proc == idleproc || proc == initproc) { panic("wait idleproc or initproc.\n"); } int exit_code = proc->exit_code; int return_pid = proc->pid; local_intr_save(intr_flag); { unhash_proc(proc); remove_links(proc); } local_intr_restore(intr_flag); put_kstack(proc); kfree(proc); int ret = 0; if (code_store != NULL) { lock_mm(mm); { int status = exit_code << 8; if (!copy_to_user(mm, code_store, &status, sizeof(int))) { ret = -E_INVAL; } } unlock_mm(mm); } return (ret == 0) ? return_pid : ret; }
// do_wait - wait one OR any children with PROC_ZOMBIE state, and free memory space of kernel stack // - proc struct of this child. // NOTE: only after do_wait function, all resources of the child proces are free. int do_wait(int pid, int *code_store) { struct mm_struct *mm = current->mm; if (code_store != NULL) { if (!user_mem_check(mm, (uintptr_t) code_store, sizeof(int), 1)) { return -E_INVAL; } } struct proc_struct *proc, *cproc; bool intr_flag, haskid; repeat: cproc = current; haskid = 0; if (pid != 0) { proc = find_proc(pid); if (proc != NULL) { do { if (proc->parent == cproc) { haskid = 1; if (proc->state == PROC_ZOMBIE) { goto found; } break; } cproc = next_thread(cproc); } while (cproc != current); } } else { do { proc = cproc->cptr; for (; proc != NULL; proc = proc->optr) { haskid = 1; if (proc->state == PROC_ZOMBIE) { goto found; } } cproc = next_thread(cproc); } while (cproc != current); } if (haskid) { current->state = PROC_SLEEPING; current->wait_state = WT_CHILD; schedule(); may_killed(); goto repeat; } return -E_BAD_PROC; found: if (proc == idleproc || proc == initproc) { panic("wait idleproc or initproc.\n"); } int exit_code = proc->exit_code; spin_lock_irqsave(&proc_lock, intr_flag); { unhash_proc(proc); remove_links(proc); } spin_unlock_irqrestore(&proc_lock, intr_flag); put_kstack(proc); kfree(proc); int ret = 0; if (code_store != NULL) { lock_mm(mm); { if (!copy_to_user (mm, code_store, &exit_code, sizeof(int))) { ret = -E_INVAL; } } unlock_mm(mm); } return ret; }