memp_std.h

Все регионы , которые мы будет создавать будут размещены в одном массиве : memp_memory . Вот он объявлен в memp.c :

static u8_t memp_memory [ MEM_ALIGNMENT - 1
#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
#include "lwip/memp_std.h" // - это интересный способ
// указать размер массива
];

#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)

MEMP_SIZE - это размер структуры memp, которая будет добавляться к началу каждого блока памяти в регионе и используется для служебных целей. По сути memp указывает на следующий блок памяти (next). Таким образом строятся связанные цепочки блоков.

struct memp
{
	struct memp *next;
#if MEMP_OVERFLOW_CHECK
	const char *file;
	int line;
#endif /* MEMP_OVERFLOW_CHECK */
};

В коде используется такой подход : переопределяется #define LWIP_MEMPOOL много раз и потом делается #include "lwip/memp_std.h" . Это делается просто для того ,чтобы один раз прописать создание нового региона и автоматически появятся записи в нужных массивах.

В массиве memp_sizes будут собраны размеры блока памяти для каждого региона.

#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
static
#endif
const u16_t memp_sizes [ MEMP_MAX ] = {
#define LWIP_MEMPOOL(name,num,size,desc)  LWIP_MEM_ALIGN_SIZE(size),
#include "lwip/memp_std.h"
		};

В массиве memp_num будут собраны размеры блоков для каждого региона.

#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */

/** This array holds the number of elements in each pool. */
static const u16_t memp_num [ MEMP_MAX ] = {
#define LWIP_MEMPOOL(name,num,size,desc)  (num),
#include "lwip/memp_std.h"
		};

Для постоянного хранения первого свободного блока в каждом регионе используется массив memp_tab .

static struct memp *memp_tab [ MEMP_MAX ];
фотка 1

Обратите внимание , что это картинка с китайского сайта. Это почему-то единственная картинка в интернете по запросу memp lwip , другой не найти. Если вы перейдете по ней в гугле , то можно перевести на русский.

Особенность выделения блоков (обратите внимание) - в обратном направлении , в сторону уменьшения адреса.

Все указатели next каждого региона всегда сначала инициализируются в функции memp_init . next указывает на адрес следующего блока (по адресам в обратном направлении получается). memp_tab [ i ] после инициализации будет указывать на самый первый свободный блок (региона i). В процессе создания и удаления блоков первый свободный может быть и в начале и в конце (где угодно).

Далее память выделяется память через функцию memp_malloc_fn . Она крайне проста . Берется указатель на первый свободный блок , на это указывает переменная memp_tab[i], это и будет адрес нашего нового блока:
memp = memp_tab [ type ];
next этого блока указывает на следующий свободный блок и переменная memp_tab [ i ] просто переставляется на следующий свободный блок.

Когда происходит удаление любого блока (например в середине цепочки) , (это в функции memp_free происходит ), то просто у удаляемого блока next переставляется на текущий свободный (блок удаленный перед этим блоком), а переменой memp_tab [ i ] присваивается указатель на удаляемым блок.

То есть мы всегда будем сохранять цепочку свободных блоков . Мы можем удалить любой блок и это не нарушит цепочку оставшихся свободных блоков. Если мы попробуем удалить уже удаленный блок ничего страшного не произойдет.

Но за логическими связями (за цепочками связанных логически блоков) мы должны следить сами где-то в другом месте.

Каждый блок дополняется в начале пространством равным MEMP_SANITY_REGION_BEFORE [16] и в конце MEMP_SANITY_REGION_AFTER [16] для контроля затирания блока случайно из кода программы. Это довольно большое увеличение расхода памяти.

фотка 2

Файл memp_std.h определяет порядок выделения регионов памяти. Например :


LWIP_MEMPOOL(TCP_PCB,        MEMP_NUM_TCP_PCB,         sizeof(struct tcp_pcb),        "TCP_PCB")
LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN,  sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN")
LWIP_MEMPOOL(TCP_SEG,        MEMP_NUM_TCP_SEG,         sizeof(struct tcp_seg),        "TCP_SEG")

Это все макросы для того чтобы просто одной строкой выделить еще один регион памяти под какие-то конкретные свои нужды. За макросами прячется интересный результат.

Например объявляем мы регион TCP_SEG:

LWIP_MEMPOOL(TCP_SEG,        MEMP_NUM_TCP_SEG,         sizeof(struct tcp_seg),        "TCP_SEG")

В результате появляются переменные MEMP_TCP_SEG.

По параметру sizeof(struct tcp_seg) понятно , что мы в этот регион будем помещать - сегменты TCP (входящие и исходящие).

PBUF_POOL_SIZE

В LWIP мы используем PBUF_POOL_SIZE . Это максимальное количество стандартных буферов для обслуживания каждого из пришедших пакетов, чтобы никого не потерять. Буферы создаются по цепочке.


Окончательно мы также получаем байтовый массив memp_memory[] размером под все регионы памяти.

Мы по условиям программы обязаны оставить функционал arp, ,ip ,udp , tcp , icmp, dhcp сервер. Все остальное придется убрать для экономии памяти.


Allocating common symbols (файл map) - полезен для информации , что жрет память.