/* *Author : DavidLin *Date : 2014-11-22pm *Email : [email protected] or [email protected] *world : the city of SZ, in China *Ver : 000.000.001 *history : editor time do * 1)LinPeng 2014-11-22 created this file! * 2) */ /* * 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;//將頁表掛到頁目錄項 else oom();//如果無法申請到空閒物理頁,內存溢出報警,die to &= 0xfffff000; //取得目的頁表 to_page = to + ((address>>10) & 0xffc); //to_page等於目的頁表的表內偏移 //即to_page[0--1023]中的索引值 if (1 & *(unsigned long *) to_page) //如果目的頁表項已經存在有效,die panic("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]++; //主內存區相應物理頁引用加1 return 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表示失敗 }
Linux-0.11內核源碼分析系列:內存管理try_to_share()與share_page()函數分析
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.