zoukankan      html  css  js  c++  java
  • Kernel 3.0.8 内存管理函数【转】

    转自:http://blog.csdn.net/myarrow/article/details/7208777

    1. 内存分配函数

    相关代码如下:

    #define alloc_pages(gfp_mask, order)   alloc_pages_node(numa_node_id(), gfp_mask, order)
    #define alloc_page_vma(gfp_mask, vma, addr) alloc_pages(gfp_mask, 0)
    #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)

    #define __get_free_page(gfp_mask)   __get_free_pages((gfp_mask),0)
    #define __get_dma_pages(gfp_mask, order)   __get_free_pages((gfp_mask) | GFP_DMA,(order))

     #define pfn_to_page(pfn) (mem_map + ((pfn) - PHYS_PFN_OFFSET))
    #define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PHYS_PFN_OFFSET)
    #define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr))

    #define phys_to_page(phys) (pfn_to_page(phys >> PAGE_SHIFT))
    #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)

    #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
    #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)


    1)__get_free_pages实现代码如下,它返回页的虚拟地址:

    [cpp] view plaincopy
     
    1. unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)  
    2. {  
    3.     struct page *page;  
    4.   
    5.     /* 
    6.      * __get_free_pages() returns a 32-bit address, which cannot represent 
    7.      * a highmem page 
    8.      */  
    9.     VM_BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0);  
    10.   
    11.     page = alloc_pages(gfp_mask, order);  
    12.     if (!page)  
    13.         return 0;  
    14.     return (unsigned long) page_address(page);  
    15. }  
    [cpp] view plaincopy
     
    1. /** 
    2.  * page_address - get the mapped virtual address of a page 
    3.  * @page: &struct page to get the virtual address of 
    4.  * 
    5.  * Returns the page's virtual address. 
    6.  */  
    7. void *page_address(struct page *page)  
    8. {  
    9.     unsigned long flags;  
    10.     void *ret;  
    11.     struct page_address_slot *pas;  
    12.   
    13.     if (!PageHighMem(page))  
    14.         return lowmem_page_address(page);  
    15.   
    16.     pas = page_slot(page);  
    17.     ret = NULL;  
    18.     spin_lock_irqsave(&pas->lock, flags);  
    19.     if (!list_empty(&pas->lh)) {  
    20.         struct page_address_map *pam;  
    21.   
    22.         list_for_each_entry(pam, &pas->lh, list) {  
    23.             if (pam->page == page) {  
    24.                 ret = pam->virtual;  
    25.                 goto done;  
    26.             }  
    27.         }  
    28.     }  
    29. done:  
    30.     spin_unlock_irqrestore(&pas->lock, flags);  
    31.     return ret;  
    32. }  
    [cpp] view plaincopy
     
    1. static __always_inline void *lowmem_page_address(struct page *page)  
    2. {  
    3.     return __va(PFN_PHYS(page_to_pfn(page)));  
    4. }  


    2)alloc_pages_node

    [cpp] view plaincopy
     
    1. static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,  
    2.                         unsigned int order)  
    3. {  
    4.     /* Unknown node is current node */  
    5.     if (nid < 0)  
    6.         nid = numa_node_id();  
    7.   
    8.     return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));  
    9. }  

    参数nid是要分配内存的 NUMA节点 ID,
    参数gfp_mask是 GFP_分配标志,
    参数order是分配内存的大小(2^order个页面).
    返回值是一个指向第一个(可能返回多个页)page结构的指针,失败时返回NULL。
     

    [cpp] view plaincopy
     
    1. static inline struct page *  
    2. __alloc_pages(gfp_t gfp_mask, unsigned int order,  
    3.         struct zonelist *zonelist)  
    4. {  
    5.     return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);  
    6. }  
    [cpp] view plaincopy
     
    1. /* 
    2.  * This is the 'heart' of the zoned buddy allocator. 
    3.  */  
    4. struct page *  
    5. __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,  
    6.             struct zonelist *zonelist, nodemask_t *nodemask)  
    7. {  
    8.     enum zone_type high_zoneidx = gfp_zone(gfp_mask);  
    9.     struct zone *preferred_zone;  
    10.     struct page *page;  
    11.     int migratetype = allocflags_to_migratetype(gfp_mask);  
    12.   
    13.     gfp_mask &= gfp_allowed_mask;  
    14.   
    15.     lockdep_trace_alloc(gfp_mask);  
    16.   
    17.     might_sleep_if(gfp_mask & __GFP_WAIT);  
    18.   
    19.     if (should_fail_alloc_page(gfp_mask, order))  
    20.         return NULL;  
    21.   
    22.     /* 
    23.      * Check the zones suitable for the gfp_mask contain at least one 
    24.      * valid zone. It's possible to have an empty zonelist as a result 
    25.      * of GFP_THISNODE and a memoryless node 
    26.      */  
    27.     if (unlikely(!zonelist->_zonerefs->zone))  
    28.         return NULL;  
    29.   
    30.     get_mems_allowed();  
    31.     /* The preferred zone is used for statistics later */  
    32.     first_zones_zonelist(zonelist, high_zoneidx,  
    33.                 nodemask ? : &cpuset_current_mems_allowed,  
    34.                 &preferred_zone);  
    35.     if (!preferred_zone) {  
    36.         put_mems_allowed();  
    37.         return NULL;  
    38.     }  
    39.   
    40.     /* First allocation attempt */  
    41.     page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,  
    42.             zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET,  
    43.             preferred_zone, migratetype);  
    44.     if (unlikely(!page))  
    45.         page = __alloc_pages_slowpath(gfp_mask, order,  
    46.                 zonelist, high_zoneidx, nodemask,  
    47.                 preferred_zone, migratetype);  
    48.     put_mems_allowed();  
    49.   
    50.     trace_mm_page_alloc(page, order, gfp_mask, migratetype);  
    51.     return page;  
    52. }  

    其接下来的主要调用流程如下:

    get_page_from_freelist->

    buffered_rmqueue

    3) buffered_rmqueue

         从区域zone中获取一块大小为2^order的物理内存块,返回该内存块的首个页框的描述符page。

    [cpp] view plaincopy
     
    1. static inline  
    2. struct page *buffered_rmqueue(struct zone *preferred_zone,  
    3.             struct zone *zone, int order, gfp_t gfp_flags,  
    4.             int migratetype)  
    5. {  
    6.     unsigned long flags;  
    7.     struct page *page;  
    8.     int cold = !!(gfp_flags & __GFP_COLD);  
    9.   
    10. again:  
    11.     if (likely(order == 0)) { //获取一页物理内存(2^0),从当前cpu的高速缓存内存中申请  
    12.         struct per_cpu_pages *pcp;  
    13.         struct list_head *list;  
    14.   
    15.         local_irq_save(flags);  
    16.         pcp = &this_cpu_ptr(zone->pageset)->pcp; //获取zone的当前处理器的高速缓存内存描述结构指针  
    17.         list = &pcp->lists[migratetype];  
    18.         if (list_empty(list)) { //高速缓存内存为空  
    19.             pcp->count += rmqueue_bulk(zone, 0,//调用此函数从伙伴系统中分配batch空闲内存到高速缓存内存中  
    20.                     pcp->batch, list,  
    21.                     migratetype, cold);  
    22.             if (unlikely(list_empty(list)))  
    23.                 goto failed;  
    24.         }  
    25.                    //我们从pcp->list链表开始的第一个lru起,去寻找相应的struct page结构体  
    26.         if (cold)  
    27.             page = list_entry(list->prev, struct page, lru);  
    28.         else  
    29.             page = list_entry(list->next, struct page, lru);  
    30.                   //由于被分配出去了,所以高速缓存内存中不再包含这页内存,所以从链表里删除这一项。  
    31.         list_del(&page->lru);  
    32.         pcp->count--;  //相应的当前页数也要减少  
    33.     } else { //获取一块物理内存(2^order)  
    34.         if (unlikely(gfp_flags & __GFP_NOFAIL)) {  
    35.             /* 
    36.              * __GFP_NOFAIL is not to be used in new code. 
    37.              * 
    38.              * All __GFP_NOFAIL callers should be fixed so that they 
    39.              * properly detect and handle allocation failures. 
    40.              * 
    41.              * We most definitely don't want callers attempting to 
    42.              * allocate greater than order-1 page units with 
    43.              * __GFP_NOFAIL. 
    44.              */  
    45.             WARN_ON_ONCE(order > 1);  
    46.         }  
    47.         spin_lock_irqsave(&zone->lock, flags);  
    48.         page = __rmqueue(zone, order, migratetype); //调用函数申请内存  
    49.         spin_unlock(&zone->lock);  
    50.         if (!page)  
    51.             goto failed;  
    52.         __mod_zone_page_state(zone, NR_FREE_PAGES, -(1 << order));  
    53.     }  
    54.   
    55.     __count_zone_vm_events(PGALLOC, zone, 1 << order);  
    56.     zone_statistics(preferred_zone, zone, gfp_flags);  
    57.     local_irq_restore(flags);  
    58.   
    59.     VM_BUG_ON(bad_range(zone, page));  
    60.     if (prep_new_page(page, order, gfp_flags))  
    61.         goto again;  
    62.     return page; //返回申请到的内存空间的首页内存页的struct page结构指针  
    63.   
    64. failed:  
    65.     local_irq_restore(flags);  
    66.     return NULL;  
    67. }  

    4) rmqueue_bulk

     用于多次(count)内存申请.

    [cpp] view plaincopy
     
    1. /*  
    2.  * Obtain a specified number of elements from the buddy allocator, all under 
    3.  * a single hold of the lock, for efficiency.  Add them to the supplied list. 
    4.  * Returns the number of new pages which were placed at *list. 
    5.  */  
    6. static int rmqueue_bulk(struct zone *zone, unsigned int order,   
    7.             unsigned long count, struct list_head *list,  
    8.             int migratetype, int cold)  
    9. {  
    10.     int i;  
    11.       
    12.     spin_lock(&zone->lock);  
    13.     for (i = 0; i < count; ++i) {  
    14.         struct page *page = __rmqueue(zone, order, migratetype);  
    15.         if (unlikely(page == NULL))  
    16.             break;  
    17.   
    18.         /* 
    19.          * Split buddy pages returned by expand() are received here 
    20.          * in physical page order. The page is added to the callers and 
    21.          * list and the list head then moves forward. From the callers 
    22.          * perspective, the linked list is ordered by page number in 
    23.          * some conditions. This is useful for IO devices that can 
    24.          * merge IO requests if the physical pages are ordered 
    25.          * properly. 
    26.          */  
    27.         if (likely(cold == 0))  
    28.             list_add(&page->lru, list);  
    29.         else  
    30.             list_add_tail(&page->lru, list);  
    31.         set_page_private(page, migratetype);  
    32.         list = &page->lru;  
    33.     }  
    34.     __mod_zone_page_state(zone, NR_FREE_PAGES, -(i << order));  
    35.     spin_unlock(&zone->lock);  
    36.     return i;  
    37. }  

      

    5) __rmqueue

     用于一次内存申请。

    [cpp] view plaincopy
     
    1. /* 
    2.  * Do the hard work of removing an element from the buddy allocator. 
    3.  * Call me with the zone->lock already held. 
    4.  */  
    5. static struct page *__rmqueue(struct zone *zone, unsigned int order,  
    6.                         int migratetype)  
    7. {  
    8.     struct page *page;  
    9.   
    10. retry_reserve:  
    11.     page = __rmqueue_smallest(zone, order, migratetype);  
    12.   
    13.     if (unlikely(!page) && migratetype != MIGRATE_RESERVE) {  
    14.         page = __rmqueue_fallback(zone, order, migratetype);  
    15.   
    16.         /* 
    17.          * Use MIGRATE_RESERVE rather than fail an allocation. goto 
    18.          * is used because __rmqueue_smallest is an inline function 
    19.          * and we want just one call site 
    20.          */  
    21.         if (!page) {  
    22.             migratetype = MIGRATE_RESERVE;  
    23.             goto retry_reserve;  
    24.         }  
    25.     }  
    26.   
    27.     trace_mm_page_alloc_zone_locked(page, order, migratetype);  
    28.     return page;  
    29. }  

    2. 内存释放函数

    相关宏定义如下:

    [cpp] view plaincopy
     
      1. #define __free_page(page) __free_pages((page), 0)  
      2. #define free_page(addr) free_pages((addr),0)  
  • 相关阅读:
    监听用户的访问的链接
    软件开发的流程
    PHP性能优化四(业务逻辑中使用场景)
    php性能优化三(PHP语言本身)
    php性能优化二(PHP配置php.ini)
    poj 1676
    计蒜客 蒜头君下棋
    计蒜客 划分整数
    计蒜客 蒜头君的数轴
    计蒜客 藏宝图
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/4837257.html
Copyright © 2011-2022 走看看