LWIP Revisited ---- memory pool management

This here is connected to a memory pool management section, where if a reader opened memp.c words will feel particularly understand that the original author was doing, but read the original author to understand is how clever use of macros. Ado said before about my analysis is that the macro conditions

Prerequisite
MEMP_STATS = 0
MEMP_OVERFLOW_CHECK = 0

First, go look simple format #include "lwip / priv / memp_std.h" file, you only need to understand this document relies LWIP_MEMPOOL (name, num, size, desc) macro, and the macro clears the end of the file.

Therefore, under the most difficult of the two appear

#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc)
#include "lwip/priv/memp_std.h"

const struct memp_desc *const memp_pools[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name,
#include "lwip/priv/memp_std.h"
};

Let me talk first, continue to chase LWIP_MEMPOOL_DECLARE defined below, watching the ignorant continue in force. . . But one should not panic macro substitution out

#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \
  LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_ ## name ## _base, ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); \
    \
  LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \
    \
  static  struct memp * memp_tab_ ## name; \
    \
  const  struct memp_desc ## memp_ name = {\
    DECLARE_LWIP_MEMPOOL_DESC(desc) \
    LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \
    LWIP_MEM_ALIGN_SIZE(size), \
    (on one), \
    memp_memory_ ## name ## _base, \
    &memp_tab_ ## name \
  };

Inside achieve relevant macro summarized as follows

#ifndef LWIP_DECLARE_MEMORY_ALIGNED
#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)]     
#endif

#define LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(name)      

#define DECLARE_LWIP_MEMPOOL_DESC(desc)

#define LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(name)

#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1U) & ~(MEM_ALIGNMENT-1U))

Finally, there is such a process

#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \
  LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_ ## name ## _base, ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); \
    \
  LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \
    \
  static  struct memp * memp_tab_ ## name; \
    \
  const  struct memp_desc ## memp_ name = {\
    DECLARE_LWIP_MEMPOOL_DESC(desc) \
    LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \
    LWIP_MEM_ALIGN_SIZE(size), \
    (on one), \
    memp_memory_ ## name ## _base, \
    &memp_tab_ ## name \
  };
  
    |
    |
   \|/
   
#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \
   
  memp_memory_RAW_PCB_base[(num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))]; \
  static struct memp *memp_tab_RAW_PCB; \
  const struct memp_desc memp_RAW_PCB = {\
    LWIP_MEM_ALIGN_SIZE(size), \
    (on one), \
    memp_memory_RAW_PCB _base,\
    &memp_tab_ RAW_PCB\ 
  };

Then the macro substitution is like this, not all listed here

#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc)
#include "lwip/priv/memp_std.h"
    |
    |
   \|/
  memp_memory_RAW_PCB_base[(num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))]; \
  static struct memp *memp_tab_RAW_PCB; 
  const struct memp_desc memp_RAW_PCB = {
    “RAW_PCB”
    LWIP_MEM_ALIGN_SIZE(size), 
    (on one), 
    memp_memory_RAW_PCB _base,
    &memp_tab_ RAW_PCB 
  };
  
  memp_memory_UDP_PCB_base[(num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))]; \
  static struct memp *memp_tab_UDP_PCB; 
  const struct memp_desc memp_UDP_PCB = {
    “UDP_PCB”      
    LWIP_MEM_ALIGN_SIZE(size), 
    (on one), 
    memp_memory_UDP_PCB _base,
    &memp_tab_UDP_PCB
  };  
.
.
.

, Similarly understood here to continue following the second macro is the same way the following results

const struct memp_desc *const memp_pools[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name,
#include "lwip/priv/memp_std.h"
};
    |
    |
   \|/

const struct memp_desc *const memp_pools[MEMP_MAX] = {
&memp_RAW_PCB,
&memp_UDP_PCB,
.
.
.
}

Note here that comes out of this MEMP_MAX

typedef enum {
#define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name,
#include "lwip/priv/memp_std.h"
MEMP_MAX
} Memp_t;
|
|
\|/
typedef enum {
MEMP_RAW_PCB,
MEMP_UDP_PCB,
.
.
.
MEMP_MAX
} Memp_t;

Then there is also a need for a definition of the following structure,

struct memp_desc {
#if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY
  /** Textual description */
  const char *desc;
#endif /* LWIP_DEBUG || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY */
  /** Element size */
  u16_t size;

#if !MEMP_MEM_MALLOC
  /** Number of elements */
  u16_t num;

  /** Base address */
  u8_t *base;

  /** First free element of each pool. Elements form a linked list. */
  struct memp **tab;
#endif /* MEMP_MEM_MALLOC */
};

Such memp_pools will mempool entire string to a memory array structure. Pay attention to this point memp_desc structure in each memp_pools in memp_tab_UDP_PCB just a pointer to a pointer, it did not have specific practical significance. Then memp_init will carry out this work, remove the macro does not compile part
memp_init follows

void memp_init(void)
{
  u16_t i;
  /* for every pool: */
  for (i = 0; i < LWIP_ARRAYSIZE(memp_pools); i++) {
    memp_init_pool (memp_pools [i]);
  }
}

Is circulating calling memp_init_pool, then look memp_init_pool after removing the macros to simplify

void
memp_init_pool(const struct memp_desc *desc)
{
  int i;
  struct memp * memp;

  *desc->tab = NULL;
  memp = (struct memp *)LWIP_MEM_ALIGN(desc->base);

  /* create a linked list of memp elements */
  for (i = 0; i < desc->num; ++i) {
    memp->next = *desc->tab;
    *desc->tab = memp;
    memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size
  }
}

As defined herein and all of the memory pool initialization has been completed a borrowing FIG wildfires, pool after initialization following structure

Each type of cell from the last, tab free pool all the string together to form a singly linked list memory pool. The hardest to understand this part is done, the next memory pool allocation and release is a very simple content.

Memory Application

void * memp_malloc (memp_t type) {
   void * MEMP;
   // get the corresponding memory pool control block 
  MEMP = do_memp_malloc_pool (memp_pools [type]);
   return MEMP;
}
// This internal function is actually called after do_memp_malloc_pool simplified as follows,
static void * do_memp_malloc_pool(const struct memp_desc *desc)
{
  struct memp * memp;
  SYS_ARCH_DECL_PROTECT(old_level);
  SYS_ARCH_PROTECT(old_level);
  memp = *desc->tab;

  if (memp != NULL) {

    *desc->tab = memp->next;

    SYS_ARCH_UNPROTECT(old_level);
    /* cast through u8_t* to get rid of alignment warnings */
    return ((u8_t *)memp + MEMP_SIZE);
  } else {
    SYS_ARCH_UNPROTECT(old_level);
  }
  return NULL;
}

Because the tab is idle pool of the head, so the memory is returned directly to the application tab pointing pool on it. At the same time release the memory is to pool re-insertion of the one-way linked list. Specifically the following simplified code

Memory release

void memp_free(memp_t type, void *mem)
{
  if (mem == NULL) {
    return;
  }
  do_memp_free_pool(memp_pools[type], mem);

}
// Call do_memp_free_pool
static void do_memp_free_pool(const struct memp_desc *desc, void *mem)
{
  struct memp * memp;
  SYS_ARCH_DECL_PROTECT(old_level);

  /* cast through void* to get rid of alignment warnings */
  memp = (struct memp *)(void *)((u8_t *)mem - MEMP_SIZE);
  SYS_ARCH_PROTECT(old_level);
  memp->next = *desc->tab;
  *desc->tab = memp;

  SYS_ARCH_UNPROTECT(old_level);

}

Now LWIP implementation of two types of memory strategies, have been understanding, and overflow detection section in which memory pool did not say, but it has helped us use LWIP, the authors have designed two types of memory strategies is his original intention of the design, read #include "lwip / priv / memp_std.h" file will know, there is the memory pool for the special fixed-length data structure design, he assigned quick release is also, and it is given there will be no memory fragmentation but it is also a space for time approach, because the application pool memory function, support if the current size of the pool runs out, you can allocate a larger pool. Heap memory allocation is used to respond to situations of varying sizes when people support the use of heap implementation LWIP pool also support the achievement of the heap with a pool, and also supports a pool of users, these features are available through a simple configuration macro as follows

MEM_LIBC_MALLOC C library

MEMP_MEM_MALLOC replace the pool liner heap memory usage.

MEM_USE_POOLS replace the use of memory heap memory pool

MEMP_USE_CUSTOM_POOLS user-defined memory pool, this implementation requires the user to provide a file lwippools.h, press defined in the form of bytes of memory pool, the pool size of the memory required to gradually increase.

LWIP_MALLOC_MEMPOOL_START

LWIP_MALLOC_MEMPOOL(20, 256)

LWIP_MALLOC_MEMPOOL(10, 512)

LWIP_MALLOC_MEMPOOL(5, 1512)

LWIP_MALLOC_MEMPOOL_END

Well, this memory management part of LWIP be simple to learn a bit, and memory management completed.

2019-06-16 17:58:42

 

Guess you like

Origin www.cnblogs.com/w-smile/p/11032337.html