Linux操作系统内存管理的源码实现
看到其中调用了两个函数,find_empty_process and copy_process,这两个函数在fork.c文件里实现 的。find_empty_process是为将要创建的新进程找一个pid,保存在last_pid里,然后调用copy_process ,这是sys_fork真正的主程序,其中有如此句: 77 p = (struct task_struct *) get_free_page(); 先为新进程分配一张物理页面,用来存放进程的PCB结构,即task_struct结构。光给新进程一张物理 页面来存放它的task_struct,显然是不能满足它的。我们知道,在创建之初,新进程是和其父进程共享 代码和数据的。这是人为定的,不过这样的好处不言而喻。因此在创建的时候就没有必要将其代码和数据 全部copy到新内存地址里,而只为新进程创建页目录项和页表就可以了。代码如下: 115 if (copy_mem(nr,p)) { /*copy_mem调用memory.c里的copy_page_tables*/ 116 task[nr] = NULL; 117 free_page((long) p); 118 return -EAGAIN; 119 } copy_mem为新进程分配页表空间,并把父进程的页表内容copy到新进程的页表空间里,这样新进程的 页表的每一项指向的物理页面和其父进程页表的相应每一项指向的物理页面是一样的。少说了一些,不能 只copy页表就完事了。32位线性地址转换为物理地址的时候,最先要找到32位线性地址对应的页目录项, 再用页目录项找到页表地址。新进程有了自己的页表,并且页表也都指向了物理地址,现在少的就是页目 录项了。新进程在创建的时候,在4G线性空间里给其分配了64M的线性空间,是通过设置LDT来完成的: 130 set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt)); 这64M的线性地址是从nr*64M的地址处开始的,这个地址正好可以被映射到页目录里的一项,这项的地 址是:((nr*64M)>>20)&0xffc。只要从这里开始,在页目录里建一些页目录项,指向新创建的 进程的页表地址(copy_mem调用copy_page_tables()来做的)。到这里,copy_mem的工作可以说是完成了, 不过一定不能少了这一句: 177 this_page &= ~2; (memory.c) 由于新进程和其父进程共享物理内存页面,因此把这些物理页面重新都设成只读是必要的。上面这句 是放在copy_page_tables函数里面的循环中的。copy_mem主要是靠调用这个程序来完成工作的。分析到这 里,我终于可以小舒一口气了。不如回顾一下:系统初始化的时候在内存起始处建一张页目录(page_dir) ,以后所有的进程都使用这张页目录。并为系统建了4张页表。以后每有新进程产生,便为之分配空间存 放PCB(即struct task_struct),然后为之通过复制父进程的页表来创建自己的页表,并创建相应的页目 录项。 (编辑:应用网_丽江站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |