/*
* 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.
*/
// 首先,address为逻辑地址。
// share_page用来确定当前进程address地址处的页面是否有可能与某个其他进程的一个
// 页面共享。所谓共享,即让当前进程在寻址address页面时直接寻址到那个共享页面上
// 这种效果是通过修改当前进程页表中address地址处的页表项内容(这个内容就是address
// 地址对应的物理页面地址)为目标共享页面的物理地址来实现的。
static int share_page(unsigned long address)
{
struct task_struct ** p;
// 若当前进程没有可执行文件部分,直接退出。
if (!current->executable)
return 0;
// 若当前进程可执行部分存在,但是其inode引用次数小于2则退出。
// executable->i_count记录当前的进程可执行文件的inode被引用的次数,这个次数为1
// 说明这个可执行文件只被当前进程引用,这样根本就不用查找别的进程就可以知道
// 不可能找到别的进程页面可以用来共享的,所以直接返回。若这个引用计数为2,就说明
// 除当前进程外还有一个进程在引用这个executable文件,这样就共享的前提了。
if (current->executable->i_count < 2)
return 0;
// 执行到这里,说明除当前进程外还有别的进程引用了这个executable,于是遍历task[64]
// 来检测所有进程,来找到这些也引用了executable文件的进程然后try_to_share他们
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
// 若为空项,即task[64]中这个进程槽并未注册进程,直接进行下一个for项目。
if (!*p)
continue;
// 跳过当前进程,因为你总不能和自己try_to_share吧
if (current == *p)
continue;
// 跳过那些executable和当前进程不同的进程。
if ((*p)->executable != current->executable)
continue;
// 最后剩下的就是那些引用了当前进程executable文件的进程了,调用try_to_share
// 来试图和它共享页面。此处注意返回值。若share成功则返回1,若失败则返回0.
if (try_to_share(address,*p))
return 1;
}
// linux0.11的编程风格中有一个明显的特色,那就是return的使用。
// 首先,返回值反映了函数执行成功与否的信息。譬如本函数,成功则返回1,失败便返回0.
// 其次,函数运行逻辑中极少使用if + else来分化逻辑,而是采用if + return来分化:即
// 首先用if把那些不要的情况return掉,最后剩下的即是想要的逻辑分支了。
// 这种构架写起来和读起来都更加清晰,并且有利于函数的模块化封装,值得学习。
return 0;
}
* 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.
*/
// 首先,address为逻辑地址。
// share_page用来确定当前进程address地址处的页面是否有可能与某个其他进程的一个
// 页面共享。所谓共享,即让当前进程在寻址address页面时直接寻址到那个共享页面上
// 这种效果是通过修改当前进程页表中address地址处的页表项内容(这个内容就是address
// 地址对应的物理页面地址)为目标共享页面的物理地址来实现的。
static int share_page(unsigned long address)
{
struct task_struct ** p;
// 若当前进程没有可执行文件部分,直接退出。
if (!current->executable)
return 0;
// 若当前进程可执行部分存在,但是其inode引用次数小于2则退出。
// executable->i_count记录当前的进程可执行文件的inode被引用的次数,这个次数为1
// 说明这个可执行文件只被当前进程引用,这样根本就不用查找别的进程就可以知道
// 不可能找到别的进程页面可以用来共享的,所以直接返回。若这个引用计数为2,就说明
// 除当前进程外还有一个进程在引用这个executable文件,这样就共享的前提了。
if (current->executable->i_count < 2)
return 0;
// 执行到这里,说明除当前进程外还有别的进程引用了这个executable,于是遍历task[64]
// 来检测所有进程,来找到这些也引用了executable文件的进程然后try_to_share他们
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
// 若为空项,即task[64]中这个进程槽并未注册进程,直接进行下一个for项目。
if (!*p)
continue;
// 跳过当前进程,因为你总不能和自己try_to_share吧
if (current == *p)
continue;
// 跳过那些executable和当前进程不同的进程。
if ((*p)->executable != current->executable)
continue;
// 最后剩下的就是那些引用了当前进程executable文件的进程了,调用try_to_share
// 来试图和它共享页面。此处注意返回值。若share成功则返回1,若失败则返回0.
if (try_to_share(address,*p))
return 1;
}
// linux0.11的编程风格中有一个明显的特色,那就是return的使用。
// 首先,返回值反映了函数执行成功与否的信息。譬如本函数,成功则返回1,失败便返回0.
// 其次,函数运行逻辑中极少使用if + else来分化逻辑,而是采用if + return来分化:即
// 首先用if把那些不要的情况return掉,最后剩下的即是想要的逻辑分支了。
// 这种构架写起来和读起来都更加清晰,并且有利于函数的模块化封装,值得学习。
return 0;
}