brk(addr)直接修改堆的大小。addr指定current->mm->brk的新值,返回值是线性区新的结束地址,这是一个系统调用。当用户态的进程调用brk()系统调用时,内核执行sys_brk(addr)函数。下面分析这个函数的执行流程:
1:检测addr参数是否位于进程代码段所在的线性区,如果是直接返回,因为堆不能与进程代码段所在的线性区重合。
mm=current->mm; down_write(&mm->mmap_sem); if(addr<mm->end_code){ out: up_write(&mm->mmap_sem); return mm->brk; }
newbrk=(addr+0xfff)&0xfffff000; oldbrk=(mm->brk+0xfff)&0xfffff000; if(oldbrk==newbrk) { mm->brk=addr; goto out; }
if(addr<=mm->brk) { if(!do_munmap(mm,newbrk,oldbrk-newbrk)) mm->brk=addr; goto out; }
rlim=current->signal->rlim[RLIMIT_DATA].rlim_cur; if(rlim<RLIM_INFINITY & addr - mm->start_data>rlim) goto out;
if(find_vma_itersection(mm,oldbrk,newbrk+PAGE_SIZE)) goto out;
if(do_brk(oldbrk,newbrk-oldbrk)==oldbrk) mm->brk=addr; goto out;do_brk()函数实际上是仅处理匿名线性区的do_mmap()简化版。可以认为它的调用等价于:
do_mmap(NULL,oldbrk,newbrk-oldbrk,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_FIXED|MAP_PRIVATE,0)
当然do_brk()比do_mmap()稍快,因为前者假定线性区不映射磁盘上的文件,从而避免了检查线性区对象的几个字段。在这里就不介绍do_brk()函数了,因后面会写一篇专门介绍重要的do_munmap。
原文地址:http://blog.csdn.net/getnextwindow/article/details/29796973