Esempio n. 1
0
File: fork.c Progetto: YMChenLiye/os
//拷贝父进程本身所占资源给子进程
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;
}
Esempio n. 2
0
File: fork.c Progetto: YMChenLiye/os
//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;
}
Esempio n. 3
0
/*
 * 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);
}
Esempio n. 4
0
File: fork.c Progetto: YMChenLiye/os
//将父进程的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;
}