进程地址空间之查找一个空闲的地址空间

进程地址空间中关于查找一个空闲的地址空间的算法get_unmapped_area(),这个函数的具体实现代码不必深究,因为它的主要实现部分都交给函数arch_get_unmapped_area()函数来实现。该函数的等价于下面的代码片段:

if (len > TASK_SIZE)
return -ENOMEM;
addr = (addr + 0xfff) & 0xfffff000;
if (addr && addr + len <= TASK_SIZE) {//TASK_SIZE是内核空间和用户空间的分界线,一般等于PAGE_OFFSET
vma = find_vma(current->mm, addr);
if (!vma || addr + len <= vma->vm_start)
return addr;
}
start_addr = addr = mm->free_area_cache;
for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
if (addr + len > TASK_SIZE) {
if (start_addr == (TASK_SIZE/3+0xfff)&0xfffff000)
return -ENOMEM;
start_addr = addr = (TASK_SIZE/3+0xfff)&0xfffff000;
vma = find_vma(current->mm, addr);
}
if (!vma || addr + len <= vma->vm_start) {
mm->free_area_cache = addr + len;
return addr;
}
addr = vma->vm_end;
}

对于代码段中的几个语句进行解释:

addr = (addr + 0xfff) & 0xfffff000;
将地址参数对齐为4KB的整数倍
vma = find_vma(current->mm, addr);
if (!vma || addr + len <= vma->vm_start)
          return addr;

特别注意这里的find_vma()函数的作用:它用于查找线性区的vm_end字段大于addr的第一个线性区的位置。我们所要找的是空闲线性区间,该函数是在已存在的线性区中寻找。所以,如果出现以下两种情况中的任意一种,则查找成功:

(1)find_vma()函数查找不成功,即vma为空,说明在已存在的线性区(memory region)中,不存在哪个线性区的vm_end>addr。也就是说在addr地址之后就没有已分配的线性区了,并且之前已经判断addr + len > TASK_SIZE,找到的这个空闲地址空间不会超过用户地址空间。这样当然就成功查找到一个满足条件的空闲地址空间。


(2)如果find_vma()函数查找成功,即存在一个线性区的vma_end>addr(通过查看find_vma()函数可知,成功返回的线性区的vm_start并不一定要比addr小)。但是,addr + len <= vma->vm_start,换句话说,找到了一个空闲的地址空间,排在find_vma()函数找到的线性区的前面,但是两个地址空间又不交叉;如果这个地址空间之前还有线性区的话,也肯定不会交叉。这样也找到了一个满足条件的空闲地址空间。


如果给定的地址addr为空,或者addr+len>TASK_SIZE,即超出了用户地址空间,那么函数就会扫描用户态线性地址空间以查找一个可以包含新区的足够大的线性地址范围,但任何已有的线性区都不包含这个地址范围。注意内存描述符中的字段:free_area_cache表示的是内核从这个地址开始搜索进程地址空间中线性地址的空闲区间,刚开始被初始化为用户态线性地址空间的三分之一(通常为1GB),在以后创建新线性区时会对其进行更新。

为了提高搜索速度,让搜索从最近被分配的线性区后面的线性地址(即 mm->free_area_cache)开始。

start_addr = addr = mm->free_area_cache;

之后进行的搜索就分为两步:

(1)如果找不到一个合适的线性地址范围,即所请求的区间大于正待扫描的线性地址空间部分(addr + len > TASK_SIZE),函数就从用户态地址空间的三分之一处重新开始搜索,如果已经完成第二次搜索,就返回-ENOMEM(没有足够的线性地址空间来满足这个请求)。

(2)刚刚扫描的线性区后面没有足够的大小(vma!=NULL && addr + len > vma->vm_start)。此时,继续考虑下一个线性区。

(3)如果以上两种情况都没发生,则找到一个足够大的空闲去,此时,函数返回addr。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值