Linux0.12内核之内存管理(3)

本系列的第三篇文章主要来介绍与共享物理页面相关的两个函数。

//在发生缺页异常的时,首先看看能否与运行同一个文件的其他进程进行页面共享处理。该函数首先判断系统中是否有另外进程也在运行与当前进程一样的执行文件。若有,则在系统当前任务中找寻这样的任务。若找到了这样的任务就尝试与其共享指定地址处的页面。判断系统中是否有另一个进程也在执行同一个可执行文件的方法是利用进程任务数据结构中的executable字段。该字段执行进程正在执行程序的内存中的i节点,根据该i节点的引用次数i_count我们就可以判断。
static int share_page(struct m_inode *inode,unsigned long address)
{
	struct task_struct **p;
	if(inode->i_count<2 || !inode)
		return 0;
	
	for(p=&LAST_TASK;p>&FIRST_TASK;--p)
	{
		if(!*p)
			continue;
		if(current==*p)
			continue;
		if(address<LIBRARY_OFFSET)
			if(inode!=(*p)->executable)
				continue;
		else{
			if(inode!=(*p)->library)
				continue;
			}
		if(try_to_share(address,*p))
			return 1;
	}
	return 0;
}

//在任务p中检查位于线性地址"address"处的页面,看页面是否存在,是否干净。如果p进程address处的页面存在并且没有被修改过的话,就让当前进程与p进程共享之。同时还需要验证置顶的地址处是否已经申请了页面,若是则出错。
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;
	
	//首先分别求指定进程p中和当前进程中逻辑地址address对应的页目录项。为了计算方便,先计算出address处“逻辑"页目录项号,即以进程空间0-64MB算出的页目录项号。该"逻辑"页目录项号加上进程p在cpu 4G线性空间中起始地址对应的页目录项即得p中的地址address处页面所对应的4G线性空间中的实际页目录项from_page
	
	from_page=to_page=((address>>20) & 0xffc);
	from_page+=((p->start_code) & 0xffc);
	to_page+=((current->start_code) & 0xffc);
	
	//在得到p和当前进程address对应的页目录项后,下面分别对进程p和当前进程进行处理。首先对p进程的表项进程操作。目标是取得p进程中address对应的物理内存页面地址,并且该物理页面存在并且干净(没被修改)。方法是首先取目录项内容,如果该目录项无效(P=0),表示目录项对应的二级页表不存在,于是返回。否则取该目录项对应的页表地址from,从而计算出逻辑地址address对应的页表项指针,并取出该页表项内容临时保存在phys_addr中。
	from=*(unsigned long*)from_page;
	if(!(from & 1))
		return 0;
	from &=0xfffff000;
	from_page=from+((address+10) &0xffc;
	phys_addr=*(unsigned long*)from_page;
	
	//接着看看页表映射的物理页面是否存在并干净。0x41对应页面中的D和P标志。如果页面不干净或者无效则返回。然后我们从该表象中取出物理地址保存在phys_addr中,最后我们检查这个物理页面地址的有效性。
	if(phys_addr & 0x41)!=0x01)
		return 0;
	phys_addr &=0xfffff000;
	if(phys_addr>=HIGH_MEMORY || phys_addr<LOW_MEM)
		return 0;
	
	//下面对当前进程的表项进程操作。目标是取得当前进程中address对应的页表项地址,并且该页表项还没有映射物理页面,即其P=0.首先取得当前进程页目录项内容->to。如果该目录项无效P=0,即目录项对应的二级页表不存在,则首先申请空闲物理页来存放页表,并更新目录象to_page内容,让其指向该内容页面。
	to=*(unsigned long*)to_page;
	if(!(to & 1))
	{
		if(to=get_free_page())
			*(unsigned long*)to_page=to|7;
		else
			com();
	}
	to&=0xfffff000;
	to_page=to+((address>>10) &0xffc);
	if(1 & *(unsigned long*)to_page)
		panic("try_to_share:to_page already exists");
	
	//共享处理:首先对p进程的页表项进行修改,设置其写保护标志,然后让当前进程复制p进程这个页表项。此时当前进程逻辑地址address处页面就被映射到p进程逻辑地址address处映射的物理页面上。
	*(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]++;
	return 1;
}

使用一个图来总结share_page的工作:


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于《Linux内核完全剖析基于0.12内核.pdf》,如果想要给其添加目录索引书签,可以通过以下步骤实现。 1. 打开Adobe Acrobat Reader:首先,确保你已经安装了Adobe Acrobat Reader这个PDF阅读器软件,如果没有,可以通过官方网站进行下载和安装。 2. 打开PDF文件:在Adobe Acrobat Reader中,选择“文件”菜单,然后选择“打开”,找到并选择《Linux内核完全剖析基于0.12内核.pdf》文件,点击“打开”。 3. 找到文档结构:在Adobe Acrobat Reader的右侧,你会看到一个名为“文档结构”的窗口。如果未打开,可以在菜单中选择“视图”并启用“文档结构”选项。 4. 添加目录:在“文档结构”窗口中,你可以看到文档中的各个章节和标题。选择某个章节或标题,然后在“文档结构”窗口上的小工具栏中,点击“添加新目录项”。 5. 编辑目录:在弹出的对话框中,输入适当的标题和页码。如果需要,可以使用缩进来建立层次结构。点击“确定”后,你会发现目录已经成功添加到“文档结构”窗口中,并且相应的页面会自动链接到目录项。 6. 保存文件:在完成所有目录的添加后,你可以选择“文件”菜单中的“保存”,保存带有目录索引书签的PDF文档。以后每次打开该文档时,都可以通过点击目录中的条目快速导航到相应的页面。 通过以上步骤,你可以为《Linux内核完全剖析基于0.12内核.pdf》添加目录索引书签,使阅读更加方便和高效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值