關於do_brk()分析

do_brk()源碼剖析

unsigned long do_brk(unsigned long addr, unsigned long len){...}
do_brk函數目的是爲了將addr位置向後繼續申請len字節長度,用做於擴展堆內存的長度
  1. 首先會對於len這個長度進行頁面對齊,而且去判斷頁面對齊以後是否超出了邊界函數

    len = PAGE_ALIGN(len);
       if (!len)
           return addr;
       if ((addr + len) > TASK_SIZE || (addr + len) < addr)
           return -EINVAL;
  2. 判斷一下當前的物理內存是否處於鎖定狀態(防止被交換出去),保持和原來狀態的一致性code

    if (mm->def_flags & VM_LOCKED) {
           unsigned long locked, lock_limit;
           locked = mm->locked_vm << PAGE_SHIFT;
           lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
           locked += len;
           if (locked > lock_limit && !capable(CAP_IPC_LOCK))
               return -EAGAIN;
       }
  3. 尋找當前addr位置對應的vma,看看是否是已經存在的vma將addr已經覆蓋了,須要調用munmap將覆蓋部分清除,保證addr到addr+len這一段內存是空白的沒有被任何的vma所覆蓋。內存

    vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);
       if (vma && vma->vm_start < addr + len) {
           if (do_munmap(mm, addr, len))
               return -ENOMEM;
           goto munmap_back;
       }
  4. 對於當前上一個的vma進行擴展,擴展至addr加上len的位置,若是成功那麼OK,進行mm_struct的維護而後返回。源碼

    if (vma_merge(mm, prev, addr, addr + len, flags,
                   NULL, NULL, pgoff, NULL))
       goto out;
  5. 不然須要來建立一個新的vma來對當前的內存進行映射,將變量設置後放入vma的紅黑樹鏈表中。it

    vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
       if (!vma) {
           vm_unacct_memory(len >> PAGE_SHIFT);
           return -ENOMEM;
       }
       memset(vma, 0, sizeof(*vma));
    
       vma->vm_mm = mm;
       vma->vm_start = addr;
       vma->vm_end = addr + len;
       vma->vm_pgoff = pgoff;
       vma->vm_flags = flags;
       vma->vm_page_prot = protection_map[flags & 0x0f];
       vma_link(mm, vma, prev, rb_link, rb_parent);
相關文章
相關標籤/搜索