Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15530577
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: 嵌入式

2009-12-12 18:03:05

浅析lwip中mem_malloc()内存动态申请函数的具体实现

  默认MEM_USE_POOLS为0,所以默认将使用如下mem_init初始化内存管理单元,当然lwip还有快速的类似linux中slab的缓冲块,但是这里mem_init初始化的内存管理单元是最通用的内存管理单元,它可以通过函数mem_malloc()申请任意大小的内存,而slab只能申请固定大小的特定内存块[luther.gliethttp],下面就针对mem_init的具体实现做进一步深入讨论[luther.gliethttp]
浅析lwip_init==>mem_init()默认的内存初始化
/**
 * Adam's mem_malloc() plus solution for bug #17922
 * Allocate a block of memory with a minimum of 'size' bytes.
 *
 * @param size is the minimum size of the requested block in bytes.
 * @return pointer to allocated memory or NULL if no free memory was found.
 *
 * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT).
 */
void *
mem_malloc(mem_size_t size)
{
  mem_size_t ptr, ptr2;
  struct mem *mem, *mem2;
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
  u8_t local_mem_free_count = 0;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
  LWIP_MEM_ALLOC_DECL_PROTECT();

  if (size == 0) {
    return NULL;
  }

  /* Expand the size of the allocated memory region so that we can
     adjust for alignment. */
  size = LWIP_MEM_ALIGN_SIZE(size); // 我设的是4字节对齐

  if(size < MIN_SIZE_ALIGNED) {
    /* every data block must be at least MIN_SIZE_ALIGNED long */
    size = MIN_SIZE_ALIGNED;        // 一次申请最小不能低于MIN_SIZE_ALIGNED,同样我设的为4字节
  }

  if (size > MEM_SIZE_ALIGNED) {
    return NULL;
  }

  /* protect the heap from concurrent access */
  sys_arch_sem_wait(mem_sem, 0);
  LWIP_MEM_ALLOC_PROTECT();
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
  /* run as long as a mem_free disturbed mem_malloc */
  do {
    local_mem_free_count = 0;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */

    /* Scan through the heap searching for a free block that is big enough,
     * beginning with the lowest free block.
     */
    for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
         ptr = ((struct mem *)&ram[ptr])->next) {
      mem = (struct mem *)&ram[ptr];
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
      mem_free_count = 0;
      LWIP_MEM_ALLOC_UNPROTECT();
      /* allow mem_free to run */
      LWIP_MEM_ALLOC_PROTECT();
      if (mem_free_count != 0) {
        local_mem_free_count = mem_free_count;
      }
      mem_free_count = 0;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */

      if ((!mem->used) &&
          (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
        /* mem is not used and at least perfect fit is possible:
         * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */

        if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
          /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
           * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
           * -> split large block, create empty remainder,
           * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
           * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
           * struct mem would fit in but no data between mem2 and mem2->next
           * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
           *       region that couldn't hold data, but when mem->next gets freed,
           *       the 2 regions would be combined, resulting in more free memory
           */
          // 分配出去size大小的内存之后,是否还能剩下一个能够分配的最小内存所需空闲空间[luther.gliethttp]
          // 如果剩下的内存足够,那么为剩下的空闲内存构造mem结构体
          ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
          /* create mem2 struct */
          mem2 = (struct mem *)&ram[ptr2]; // ptr第一次执行为0,所以ptr2递增指向更高空闲内存偏移处,然后为mem2填充结构体数据
          mem2->used = 0;   // 本段内存空闲
          mem2->next = mem->next; // mem2链接被分配出去的mem的next单元,第一次执行的话,mem->next就是MEM_SIZE_ALIGNED
          mem2->prev = ptr; // prev指向mem对应的ptr索引偏移[luther.gliethttp]
          /* and insert it between mem and mem->next */
          mem->next = ptr2; // mem的next指向mem2,这样构成如下链表:mem<->mem2->MEM_SIZE_ALIGNED
          mem->used = 1;    // 本mem被分配出去了,但是仍在链表上[luther.gliethttp]

          if (mem2->next != MEM_SIZE_ALIGNED) { // mem2指向MEM_SIZE_ALIGNED的最后一个空闲内存
            ((struct mem *)&ram[mem2->next])->prev = ptr2; // 因为上面mem被摘下来了,mem->next也被替换,这里为mem->next的prev赋值
          }
          MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
        } else {
          /* (a mem2 struct does no fit into the user data space of mem and mem->next will always
           * be used at this point: if not we have 2 unused structs in a row, plug_holes should have
           * take care of this).
           * -> near fit or excact fit: do not split, no mem2 creation
           * also can't move mem->next directly behind mem, since mem->next
           * will always be used at this point!
           */
        // 本mem不能拆分成更小的内存了,所以将mem全部分配出去[luther.gliethttp]
          mem->used = 1;
          MEM_STATS_INC_USED(used, mem->next - ((u8_t *)mem - ram));
        }

        if (mem == lfree) {
            // 如果分配出去的mem是lfree空闲链表头,那么需要重新计算lfree[luther.gliethttp]
          /* Find next free block after mem and update lowest free pointer */
          while (lfree->used && lfree != ram_end) { // 将第1个used=0的没有被使用的mem作为lfree.
            LWIP_MEM_ALLOC_UNPROTECT();
            /* prevent high interrupt latency... */
            LWIP_MEM_ALLOC_PROTECT();
            lfree = (struct mem *)&ram[lfree->next];
          }
          LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
        }
        LWIP_MEM_ALLOC_UNPROTECT();
        sys_sem_signal(mem_sem);
        LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
         (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
        LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
         ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
        LWIP_ASSERT("mem_malloc: sanity check alignment",
          (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);

        return (u8_t *)mem + SIZEOF_STRUCT_MEM;
      }
    }
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
    /* if we got interrupted by a mem_free, try again */
  } while(local_mem_free_count != 0);
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
  MEM_STATS_INC(err);
  LWIP_MEM_ALLOC_UNPROTECT();
  sys_sem_signal(mem_sem);
  return NULL;
}
阅读(11144) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~