Linux-0.11内核源码分析系列:内存管理try_to_share()与share_page()函数分析

来源:互联网 发布:淘宝hd降级 编辑:程序博客网 时间:2024/06/05 00:46
/*    *Author  : DavidLin    *Date    : 2014-11-22pm    *Email   : linpeng1577@163.com or linpeng1577@gmail.com    *world   : the city of SZ, in China    *Ver     : 000.000.001    *history :     editor      time            do    *          1)LinPeng       2014-11-22      created this file!    *          2)    */ <pre name="code" class="plain">/* * try_to_share()检查进程P中地址”address"是否存在 * 如果存在且是没有被污染的页面,将该页面与当前进程共享 * * 注意,前提条件是进程p不是当前进程,而且它们共享同样的执行文件 *//* * try_to_share() checks the page at address "address" in the task "p", * to see if it exists, and if it is clean. If so, share it with the current * task. * * NOTE! This assumes we have checked that p != current, and that they * share the same executable. */static int try_to_share(unsigned long address, struct task_struct * p){unsigned long from;         //管理源页表unsigned long to;           //管理目的页表unsigned long from_page;    //管理源页表项unsigned long to_page;      //管理目的页表项unsigned long phys_addr;    //管理源物理地址from_page = to_page = ((address>>20) & 0xffc);  //获取页表地址from_page += ((p->start_code>>20) & 0xffc);     //from_page加上进程P                                                        //的数据段地址                                                        //取得4G空间地址to_page += ((current->start_code>>20) & 0xffc); //to_page加上当前进程                                                        //的数据段地址                                                        //取得4G空间地址        //注意:address指的是进程中0-64M的相对地址,要计算主内存区的数组偏移,        //必须加上任务代码段(数据段)的偏移地址,才可以获取4G空间偏移地址/* is there a page-directory at from? */                from = *(unsigned long *) from_page;    //from是from_page的页目录项                                                //页目录项管理着页表                                                //即页表的值保存在页目录项中if (!(from & 1))    //如果该目录项无效,即源页表也是无效return 0;   //返回0,表示失败from &= 0xfffff000; //取得源页表from_page = from + ((address>>10) & 0xffc);  //此处from_page指向页框                                                     //即页表内偏移地址        phys_addr = *(unsigned long *) from_page;    //取得源物理页地址/* is the page clean and present? */if ((phys_addr & 0x41) != 0x01)    //如果源物理页不干净或者不存在return 0;                  //返回0表示失败phys_addr &= 0xfffff000;if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM)  return 0;    //如果源物理地址不在主内存区,返回0表示失败to = *(unsigned long *) to_page;    //取得目的页目录项if (!(to & 1))                      //如果目的页目录项P位无效if (to = get_free_page())   //申请一块物理页用来保存目的页表*(unsigned long *) to_page = to | 7;//将页表挂到页目录项elseoom();//如果无法申请到空闲物理页,内存溢出报警,dieto &= 0xfffff000;     //取得目的页表to_page = to + ((address>>10) & 0xffc);  //to_page等于目的页表的表内偏移                                                 //即to_page[0--1023]中的索引值        if (1 & *(unsigned long *) to_page)  //如果目的页表项已经存在有效,diepanic("try_to_share: to_page already exists");/* share them: write-protect */*(unsigned long *) from_page &= ~2;  //源页表项设置为只读*(unsigned long *) to_page = *(unsigned long *) from_page;  //共享invalidate();            //刷新交换高速缓存phys_addr -= LOW_MEM;    phys_addr >>= 12;mem_map[phys_addr]++;    //主内存区相应物理页引用加1return 1;                //返回1表示共享成功}/* share_page()函数试图找到一个进程,该进程可以和当前进程共享某个页面 * 参数address是当前进程中数据空间的某页面,即把数据空间的起始地址当做 * 0地址的相对地址 *  * 通过检查当前进程的executable->i_count,因为可执行文件被不同进程引用时会++1, * 所以如果executable->i_count > 1,表示除了当前进程,还有其他进程使用该文件 * 如果上述条件成立,当前进程就试图与其他进程共享该页 *//* * share_page() tries to find a process that could share a page with * the current one. Address is the address of the wanted page relative * to the current data space. * * We first check if it is at all feasible by checking executable->i_count. * It should be >1 if there are other tasks sharing this inode. */static int share_page(unsigned long address){struct task_struct ** p;    //指向进程指针的指针if (!current->executable)   //如果没有对应执行文件,返回return 0;if (current->executable->i_count < 2)    //如果只有当前进程引用该文件return 0;                        //返回for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {    //遍历进程管理数组if (!*p)    //如果进程不存在,继续continue;if (current == *p)    //如果进程等于当前进程continue;     //继续if ((*p)->executable != current->executable)continue;     //如果执行文件不同if (try_to_share(address,*p))    //试图与找到的进程共享该页      return 1;                //返回1表示成功                }return 0;    //如果上述无法找到进程共享页面,返回0表示失败}



0 0
原创粉丝点击