//拷贝父进程本身所占资源给子进程 static int32_t copy_process(struct task_struct* child_thread,struct task_struct* parent_thread){ //内核缓冲区,作为父进程用户空间的数据复制到子进程用户空间的中转 void* buf_page = get_kernel_pages(1); if(buf_page == NULL){ return -1; } //a 复制父进程的pcb、虚拟地址位图、内核栈到子进程 if(copy_pcb_vaddrbitmap_stack0(child_thread,parent_thread) == -1){ return -1; } //b 为子进程创建页表,此页表仅包括内核空间 child_thread->pgdir = create_page_dir(); if(child_thread->pgdir == NULL){ return -1; } //c 复制父进程进程体及用户栈给子进程 copy_body_stack3(child_thread,parent_thread,buf_page); //d 构建子进程thread_stack和修改返回值pid build_child_stack(child_thread); //e 更新文件inode的打开数 update_inode_open_cnts(child_thread); mfree_page(PF_KERNEL,buf_page,1); return 0; }
//fork子进程,内核线程不可直接调用 pid_t sys_fork(void){ struct task_struct* parent_thread = running_thread(); struct task_struct* child_thread = get_kernel_pages(1); //为子进程创建pcb(task_struct结构) if(child_thread == NULL){ return -1; } ASSERT(INTR_OFF == intr_get_status() && parent_thread->pgdir != NULL); if(copy_process(child_thread,parent_thread) == -1){ return -1; } //添加到就绪线程队列和所有线程队列,子进程由调度器安排运行 ASSERT(!elem_find(&thread_ready_list,&child_thread->general_tag)); list_append(&thread_ready_list,&child_thread->general_tag); ASSERT(!elem_find(&thread_all_list,&child_thread->all_list_tag)); list_append(&thread_all_list,&child_thread->all_list_tag); return child_thread->pid; }
/* * get_kernel_page() - pin a kernel page in memory * @start: starting kernel address * @write: pinning for read/write, currently ignored * @pages: array that receives pointer to the page pinned. * Must be at least nr_segs long. * * Returns 1 if page is pinned. If the page was not pinned, returns * -errno. The page returned must be released with a put_page() call * when it is finished with. */ int get_kernel_page(unsigned long start, int write, struct page **pages) { const struct kvec kiov = { .iov_base = (void *)start, .iov_len = PAGE_SIZE }; return get_kernel_pages(&kiov, 1, write, pages); } EXPORT_SYMBOL_GPL(get_kernel_page); static void pagevec_lru_move_fn(struct pagevec *pvec, void (*move_fn)(struct page *page, struct lruvec *lruvec, void *arg), void *arg) { int i; struct zone *zone = NULL; struct lruvec *lruvec; unsigned long flags = 0; for (i = 0; i < pagevec_count(pvec); i++) { struct page *page = pvec->pages[i]; struct zone *pagezone = page_zone(page); if (pagezone != zone) { if (zone) spin_unlock_irqrestore(&zone->lru_lock, flags); zone = pagezone; spin_lock_irqsave(&zone->lru_lock, flags); } lruvec = mem_cgroup_page_lruvec(page, zone); (*move_fn)(page, lruvec, arg); } if (zone) spin_unlock_irqrestore(&zone->lru_lock, flags); release_pages(pvec->pages, pvec->nr, pvec->cold); pagevec_reinit(pvec); }
//将父进程的pcb、虚拟地址位图拷贝给子进程 static int32_t copy_pcb_vaddrbitmap_stack0(struct task_struct* child_thread,struct task_struct* parent_thread){ //a 复制pcb所在的整个页,里面包含了进程pcb信息及特权0级栈,里面包含了返回地址,然后再单独修改个别部分 memcpy(child_thread,parent_thread,PG_SIZE); child_thread->pid = fork_pid(); child_thread->elapsed_ticks = 0; child_thread->status = TASK_READY; child_thread->ticks = child_thread->priority; //为新进程把时间片充满 child_thread->parent_pid = parent_thread->pid; child_thread->general_tag.prev = child_thread->general_tag.next = NULL; child_thread->all_list_tag.prev = child_thread->all_list_tag.next = NULL; block_desc_init(child_thread->u_block_desc); //b 复制父进程的虚拟地址池的位图 uint32_t bitmap_pg_cnt = DIV_ROUND_UP((0xc0000000 - USER_VADDR_START) / PG_SIZE / 8,PG_SIZE); void* vaddr_btmp = get_kernel_pages(bitmap_pg_cnt); if(vaddr_btmp == NULL) return -1; //此时child_thread->userprog_vaddr.vaddr_bitmap.bits还是指向父进程虚拟地址的位图地址 //下面将child_thread->userprog_vaddr.vaddr_bitmap.bits指向自己的位图vaddr_btmp memcpy(vaddr_btmp,child_thread->userprog_vaddr.vaddr_bitmap.bits,bitmap_pg_cnt * PG_SIZE); child_thread->userprog_vaddr.vaddr_bitmap.bits = vaddr_btmp; //调试用 ASSERT(strlen(child_thread->name) < 11); //pcb.name的长度是16,为了避免下面strcat越界 strcat(child_thread->name,"_fork"); return 0; }