linux/mm/memory.c/try_to_share()

/*
 * 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.
 */
// try_to_share函数可以让当前进程尝试去共享p进程address处的一个物理页面内容。
// 首先,这里的“共享”指的是能操作、实际就是让当前进程address处寻址最终也
// 指向p进程的address处物理页面。
// 其次,要理解这个函数的实现,一定要搞清楚address不是线性地址,而是逻辑地址。
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;


// 这里address不是线性地址了,而是逻辑地址、即虚拟地址。这个地址是以当前进程
// 64MB从零开始的地址空间计算得来的偏移地址。p->start_code为p进程的start_code
// 线性地址。因为linux0.11中进程都是代码段在前的所以start_code都是0.这个就决定了
// 一个事实,(p->start_code)>>20就得到了这个进程页表在页目录表中最多16个表项中
// 的第一个表项地址指针。然后address又是段内偏移地址,所以address>>20又能得到
// address所属页表在最多16个页表中的序数,于是乎这里两个+=就计算出了address处
// 页表在两个进程中的页表项地址了。
from_page = to_page = ((address>>20) & 0xffc);
from_page += ((p->start_code>>20) & 0xffc);
to_page += ((current->start_code>>20) & 0xffc);
/* is there a page-directory at from? */
from = *(unsigned long *) from_page;
if (!(from & 1))
return 0;
from &= 0xfffff000;
// 得到address在p进程中对应的页表基地址
from_page = from + ((address>>10) & 0xffc);
// 从页表项中取出address在p进程中对应物理页面的基地址
phys_addr = *(unsigned long *) from_page;
/* is the page clean and present? */
if ((phys_addr & 0x41) != 0x01)
return 0;
phys_addr &= 0xfffff000;
if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM)
return 0;
to = *(unsigned long *) to_page;
// 若当前进程address地址处对应的页表还未建立,则为当前进程注册一页物理内存
// 并且更新页目录项使其指向新申请的物理内存。即确保当前进程address处可以在
// 页目录表中找到对应表项
if (!(to & 1))
if (to = get_free_page())
*(unsigned long *) to_page = to | 7;
else
oom();
to &= 0xfffff000;
// 得到address在当前进程对应的页表项,把寻址推进到页表级
to_page = to + ((address>>10) & 0xffc);
// *(unsigned long *)to_page用来取出to_page处页表表项内容,这个内容
// 包括物理页面基地址和一些属性bit
if (1 & *(unsigned long *) to_page)
panic("try_to_share: to_page already exists");
/* share them: write-protect */
*(unsigned long *) from_page &= ~2;
// 若to_page处页面不存在,则满足share条件,开始设置share
// 把address在p进程中物理页面设为只读,然后将address在current process
// 的页表项内容设置为和p进程中一致。这样相当于address在当前进程和p进程
// 内都指向同一个物理页面了(这个页面就是p进程之前address处的物理页面)
*(unsigned long *) to_page = *(unsigned long *) from_page;
invalidate();
// 最后如果整个share顺利的话,p进程的address处物理页面必然多了当前进程
// 的一个引用,因此给他在mem_map中的引用计数+1
phys_addr -= LOW_MEM;
phys_addr >>= 12;
mem_map[phys_addr]++;
return 1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朱有鹏老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值