Цитата(sergeeff @ Oct 7 2008, 18:46)
И излишества всякие, нехорошие ...
Думал просто oткомментировать немного и выложить heap manager для FreeRTOS, но получается, что сначала нужно описывать почему он сделан именно так
. Попробую:
1. Хотелось иметь возможность получения списков свободных и занятых блоков памяти во время консольной отладки.
2. Хотелось иметь признак для чего блок памяти используется системой (TCB/Stack, Очередь,...)
3. Хотелось иметь возможность знать какая задача породила тот или иной блок - самое простое, при запросе блока сохранять адрес TCB.
4. Обязательна возможность использовать с менеджером разрозненные блоки памяти в едином списке. И наоборот - использовать несколько независимо управляемых блоков памяти (например, если эти блоки памяти имеют разное назначение/свойства, или для ручной борьбы с дефрагментацией )
5. Особые навороты с для ускорения поиска свободных блоков типа "испанского варианта" не нужны, поскольку
- основная масса блоков памяти под задачи, очереди и прочее выделяется "навсегда" и естественно выделение начинается с них;
- относительно родной реализации FreeRTOS под задачу и очередь у меня выделяется по одному блоку памяти TCB+Stack и QCB+Queue вместо отдельных.
- в результате в реальности занимаются/освобождаются обычно 2-3-5-ну чуть больше блоков и найти подходящий по размеру проще и быстрее простым перебором из свободных.
6. Борьба с дефрагментацией:
- склеивание соседних свободных блоков в один;
- прежде всего поиск свободного блока равного размеру запрашиваемого - на самом деле достаточно не редкий вариант, особенно, если чуть приложить к этому усилия.
Как строим:
1. Один общий связанный список, или отдельные для свободных и занятых. Использую один общий. Решающая причина - простой механизм склейки свободных блоков. При этом недостатки такого подхода нивелирутся тем, что ввиду (п.5) дефрагментация только в хвосте списка и длинна списка для поиска свободного эффективно сокращается использованием всего одного дополнительного указателя на первый свободный блок в общем списке.
2. На MCB выделено достаточно много памяти - 16 байт. Для максимально кастрированного варианта типа родных heap_*.с и с ограничением на размеры выделяемого блока можно было и в 4 байта уложиться, но см. "хотелки". Без особого напряга можно было в 12 байт уложиться, но тем неменее исходя из того, что например, для ARM стека выравнивание на 8 байт надо.... Пусть будет на данный момент 16 байт.
Код
typedef union type_size {
unsigned long size;
struct {
unsigned long xlen:24;
unsigned long type:8;
};
}type_size;
// Memory Control Block (MCB)
typedef struct heap_mcb
{
struct heap_mcb *next; // Указатель на следующий MCB
// mcb.next последнего MCM всегда указывает на
// первый MCB.
struct heap_mcb *prev; // Указатель на предыдущий MCB.
// Для первого MCB этот указатель указывает
// сам на себя.
union type_size ts; // Размер блока памяти и тип блока
void *ow; // ТСВ Владельца блока памяти
// Собственно контролируемый блок памяти расположен сразу за MCB
} heap_mcb;
// Структура-описатель HEAP (тип-структура t_heap)
typedef struct heap_t
{ // Указатель на начало heap (первый MCB)
struct heap_mcb *start;
// Указатель на первый свободный MCB
struct heap_mcb *freem;
// RAW размер HEAP
unsigned long hsize;
} heap_t;
Осталось откомментировать и выложить исходники. Завтра...