Отдаю менеджер локальной кучи безвозмездно и бескорыстно. Особенности:
-автоматом определяет размерность адреса
-функция l_free имеет защиту от дурака (неправильный указатель).
Работает не очень быстро, но надежно. Проверен необнократно на AVR (16битный адрес) и ARM (32битный адрес). Под z80 компилил при помощи SDCC. Вроде тоже нормально работает.
Текст состоит из двух файлов. heap.h и heap.c.
Вопросы задавать МОЖНО
Лежит здесь
http://www.nedopc.org/nedopc/upload/heap.tar
[SRC] Менеджер памяти
Moderator: Shaos
-
- Doomed
- Posts: 491
- Joined: 16 Apr 2005 22:35
- Location: Томск
-
- Admin
- Posts: 23989
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
-
- Admin
- Posts: 23989
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
Привожу полные исходные тексты
heap.h
heap.h
Code: Select all
//----------------------------------------------------------------------------
// Работа с кучей. Заголовочный файл.
//
// Структура кучи:
// |t_dynamem_descr| memory part |t_dynamem_descr| memory part |...|t_dynamem_descr| memory part |
// где
// t_dynamem_descr - описатель элемента памяти (см. ниже)
// memory part - элемент памяти, который описывается соответствующим описателем
//
// Поле next_dynamem_descr описателя последнего элемента памяти всегда указывает
// на описатель первого элемента (циклическая структура структура).
// Поле prev_dynamem_descr описателя первого элемента памяти указывает
// на первый элемент (сам на себя).
//----------------------------------------------------------------------------
#ifndef heap_h
#define heap_h
//----------------------------------------------------------------------------
// Макрос HEAP_ALIGN задает нужно ли выравнивание.
// Общий вид:
// #define HEAP_ALIGN n /* n=0,2,4,8... */
// Выравнивание производится только по границе 2^n байт
// #define HEAP_ALIGN 0x00 /* нет выравнивания */
// #define HEAP_ALIGN 0x02 /* выравнивание по полуслову (16 бит) */
// #define HEAP_ALIGN 0x04 /* выравнивание по слову (32 бит) */
// #define HEAP_ALIGN 0x08 /* выравнивание по двойному слову (64 бит) */
// Если используется выравнивание, то начало кучи и ее размер так же должны быть
// выровнены !
//----------------------------------------------------------------------------
#ifndef HEAP_ALIGN
#define HEAP_ALIGN sizeof(int)
#else
#if HEAP_ALIGN==0
#undef HEAP_ALIGN
#endif /* 0 */
#endif /* HEAP_ALIGN */
//----------------------------------------------------------------------------
// Флаги (поле flags типа t_dynamem_descr)
#define DM_BUSY 0x00000001 /* Если флаг равен 1, то блок памяти занят */
//----------------------------------------------------------------------------
// Описатель элемента кучи (тип-структура t_heap_el)
//----------------------------------------------------------------------------
typedef struct
{void* next_dynamem_descr; // Указатель на описатель следующего элемента
// Поле next_dynamem_descr последнего элемента
// памяти всегда указывает на
// описатель первого элемента
// (циклическая структура структура).
//
void* prev_dynamem_descr; // Указатель на описатель предыдущего элемента
// Для первого элемента кучи этот указатель указывает
// на первый элемент (сам на себя).
//
void* this_memory_part; // Указатель на элемент памяти. Элемент ВСЕГДА
// расположен сразу за описателем
unsigned int this_memory_size; // Размер элемента памяти (в байтах)
unsigned int flags; // Флаги элемента памяти
}t_heap_el;
//----------------------------------------------------------------------------
// Структура-описатель кучи (тип-структура t_heap)
//----------------------------------------------------------------------------
typedef struct
{// Указатель на текущий элемент кучи
t_heap_el* curel;
// Указатель на начало кучи (на описатель первого элемента)
t_heap_el* firstel;
}t_heap;
//----------------------------------------------------------------------------
// На всякий случай :)
//----------------------------------------------------------------------------
#ifndef NULL
#define NULL 0
#endif
//----------------------------------------------------------------------------
// Резервирует память в куче 'heap', размером 'size' байт.
// Возвращает указатель на зарезервированную память
// Если в куче не достаточно памяти, то возвращает NULL
//----------------------------------------------------------------------------
void* l_malloc(t_heap* heap, unsigned int size);
//----------------------------------------------------------------------------
// Резервирует память в куче 'heap', для размещения массива из 'nmemb' элементов,
// каждый из которых имеет размер 'size'
// Возвращает указатель на зарезервированную память
// Если в куче не достаточно памяти, то возвращает NULL
//----------------------------------------------------------------------------
void* l_calloc(t_heap* heap,int nmemb,int size);
//----------------------------------------------------------------------------
// Освобождает зарезервированную память, на которую указывает 'ptr' в куче 'heap'.
// Если указатель указывает на память, которая не была выделена ранее
// функциями l_malloc() или l_calloc() или указатель 'ptr' равен 0, то ничего не
// происходит
void l_free(t_heap* heap, void* ptr);
//----------------------------------------------------------------------------
// Инициализирует кучу 'heap'.
// heap_begin - адрес начала кучи
// heap_size - размер кучи (включая все описатели)
// Куча занимает в памяти адресное пространство
// от heap_begin до (heap_begin+heap_size-1)
void l_heapinit(t_heap* heap, void* heap_begin, int heap_size);
//----------------------------------------------------------------------------
#endif /* heap_h */
Я тут за главного - если что шлите мыло на me собака shaos точка net
-
- Admin
- Posts: 23989
- Joined: 08 Jan 2003 23:22
- Location: Silicon Valley
heap.c
Code: Select all
//----------------------------------------------------------------------------
// Работа с кучей. Заголовочный файл.
//
// Структура кучи:
// |t_dynamem_descr| memory part |t_dynamem_descr| memory part |...|t_dynamem_descr| memory part |
// где
// t_dynamem_descr - описатель элемента памяти (см. ниже)
// memory part - элемент памяти, который описывается соответствующим описателем
//
// Поле next_dynamem_descr описателя последнего элемента памяти всегда указывает
// на описатель первого элемента (циклическая структура структура).
// Поле prev_dynamem_descr описателя первого элемента памяти указывает
// на первый элемент (сам на себя).
//----------------------------------------------------------------------------
#include <mm/heap.h>
//----------------------------------------------------------------------------
// Для отладки модуля должен быть определен символ :
// #define MALLOC_DEBUG 1
// или в командной строке должен быть задан ключ
// -DMALLOC_DEBUG=1
//----------------------------------------------------------------------------
// Если отладочная версия, то определим макросы запрещения и разрешения
// прерываний (если они не определены ранее)
//----------------------------------------------------------------------------
#ifdef MALLOC_DEBUG
// Марос ATOMIC_BEGIN() - определяет начало фрагмента,
// который не может быть прерван
#ifndef ATOMIC_BEGIN
#define ATOMIC_BEGIN()
#endif /* ATOMIC_BEGIN */
// Марос ATOMIC_END() - определяет конец фрагмента,
// который не может быть прерван
#ifndef ATOMIC_END
#define ATOMIC_END()
#endif /* ATOMIC_END */
//
#else
// Если версяя рабочая, то включаем определения макросы
// запрещения и разрешения прерываний
#include <atomic/atomic.h>
#endif /* MALLOC_DEBUG */
//----------------------------------------------------------------------------
// Определяем функции печати для отладки
//----------------------------------------------------------------------------
#ifdef MALLOC_DEBUG
//--------------------------------------------------------------------------
// Для использования своей функции печати, отличной от dbg_printf()
// Должен быть определен макрос NOSTD_DBG_PRINTF
// Например, для использования функции printf() для отладки, должен быть
// определен макрос
// #define NOSTD_DBG_PRINTF printf
// или в командной строке должен быть задан ключ
// -DNOSTD_DBG_PRINTF=printf
//--------------------------------------------------------------------------
#ifndef NOSTD_DBG_PRINTF
#define NOSTD_DBG_PRINTF dbg_printf
#endif /* PRINTF_HAVING */
// Print memory block
void prmembl(t_heap_el* mblk)
{NOSTD_DBG_PRINTF("void* next_dynamem_descr 0x%x\n",mblk->next_dynamem_descr);
NOSTD_DBG_PRINTF("void* prev_dynamem_descr 0x%x\n",mblk->prev_dynamem_descr);
NOSTD_DBG_PRINTF("void* this_memory_part 0x%x\n",mblk->this_memory_part);
NOSTD_DBG_PRINTF("unsigned int this_memory_size 0x%x\n",mblk->this_memory_size);
NOSTD_DBG_PRINTF("unsigned int flags 0x%x\n",mblk->flags);
}
// Print memory block of pointer
void prmemptr(void* mptr)
{prmembl( (t_heap_el*) ( ((unsigned int)(mptr)) - sizeof(t_heap_el)) );
}
#endif /* MALLOC_DEBUG */
//----------------------------------------------------------------------------
// Инициализирует кучу 'heap'.
// heap_begin - адрес начала кучи
// heap_size - размер кучи (включая все описатели)
// Куча занимает в памяти адресное пространство
// от heap_begin до (heap_begin+heap_size-1)
//----------------------------------------------------------------------------
void l_heapinit(t_heap* heap, void* heap_begin, int heap_size)
{t_heap_el* tdd;
// Первый элемент, текущий элемент
tdd = heap->curel = heap->firstel = heap_begin;
// Циклическая структура
tdd->next_dynamem_descr=tdd;
// Предыдущий за первым элементом - он же (указатель на самого себя)
tdd->prev_dynamem_descr=tdd;
// Указатель на элемент памяти
tdd->this_memory_part = (void*)(((int)(tdd))+sizeof(t_heap_el));
// Размер элемента памяти
tdd->this_memory_size = heap_size - sizeof(t_heap_el);
// Элемент памяти свободен
tdd->flags = 0x00000000;
#ifdef MALLOC_DEBUG
NOSTD_DBG_PRINTF("Memory after init:\n");
prmembl(heap_begin);
NOSTD_DBG_PRINTF("\n");
#endif /* MALLOC_DEBUG */
// После инициализации куча представляет собой список из одного элемента,
// который имеет размер кучи минус размер описателя элемента.
// Т.е. вся куча - это один свобоный элемент памяти
}
//----------------------------------------------------------------------------
// Резервирует память в куче 'heap', для размещения массива из 'nmemb' элементов,
// каждый из которых имеет размер 'size'
// Возвращает указатель на зарезервированную память
// Если в куче не достаточно памяти, то возвращает NULL
//----------------------------------------------------------------------------
void* l_calloc(t_heap* heap,int nmemb,int size){return(l_malloc(heap,nmemb*size));}
//----------------------------------------------------------------------------
// Резервирует память в куче 'heap', размером 'size' байт.
// Возвращает указатель на зарезервированную память
// Если в куче не достаточно памяти, то возвращает NULL
//----------------------------------------------------------------------------
void* l_malloc(t_heap* heap, unsigned int size)
{// Запрещаем прерывания
ATOMIC_BEGIN();
// Временные переменные
t_heap_el* tptr=heap->curel; // Поиск начинается с текущего элемента
t_heap_el* tptrn;
// Возвращаемый указатель
void* retptr;
// Когда exit==1, заканчиваем цикл поиска
int exit=0;
// Выравнивание по заданной границе
#ifdef HEAP_ALIGN
if(size & (HEAP_ALIGN-1))
{size = size + (HEAP_ALIGN - (size & (HEAP_ALIGN-1)));
}
#endif
// Основной цикл поиска
while(!exit)
{// Если найден свободный элемент...
if(!(tptr->flags & DM_BUSY))
{// Проверяем размер
if(tptr->this_memory_size == size)
{// Требуемый и найденный размеры памяти равны
tptr->flags |= DM_BUSY; // Резервируем блок
retptr = tptr->this_memory_part; // Возвращаем указатель на текущий эл-т
heap->curel = tptr->next_dynamem_descr; // Текущий указатель переставляем
// на следующий эл-т
exit=1; // Выходим
}
else if((tptr->this_memory_size) >= (size+sizeof(t_heap_el)) )
{// Найденный размер достаточен для размещения нового эл-та и его описателя
// tptrn - адрес описателя нового эл-та
tptrn=(t_heap_el*)( ((unsigned int)(tptr->this_memory_part)) + size);
// Установим поля описателя нового элемента
tptrn->next_dynamem_descr= tptr->next_dynamem_descr;
tptrn->prev_dynamem_descr= tptr;
tptrn->this_memory_part = (void*)(((unsigned int)(tptrn))+sizeof(t_heap_el));
tptrn->this_memory_size = (tptr->this_memory_size - size - sizeof(t_heap_el));
tptrn->flags = 0x00000000;
// Установим поля найденного элемента
tptr->next_dynamem_descr=tptrn;
//tptr->prev_dynamem_descr
//tptr->this_memory_part
tptr->this_memory_size = size;
tptr->flags |= DM_BUSY;// Block busy
// Если элемент ptr не был последним, то поле следующего за ним эл-та
// должно теперь указывать не на prt, а на ptrn
if((tptrn->next_dynamem_descr)!=heap->firstel)
{((t_heap_el*)(tptrn->next_dynamem_descr))->prev_dynamem_descr=tptrn;
}
//
heap->curel = tptr->next_dynamem_descr; // Текущий указатель переставляем
// на следующий эл-т
retptr = tptr->this_memory_part; // Возвращаем указатель на текущий эл-т
exit=1; // Выходим
}
}
// Переходим к следующему элементу
tptr = tptr->next_dynamem_descr;
// Если не выход
if(!exit)
{// Проверка на полный проход кучи
if(tptr==heap->curel)
{// Элементов заданного размера не найдено,
retptr = NULL; // Возвращаем NULL
exit=1; // Выходим
}
}
}
//
ATOMIC_END(); // Разрешаем прерывания
// Отладочная байда
#ifdef MALLOC_DEBUG
NOSTD_DBG_PRINTF("Allocate :\n");
if(retptr){prmemptr(retptr);NOSTD_DBG_PRINTF("\n");}
else{NOSTD_DBG_PRINTF("Nothing !\n");}
#endif /* MALLOC_DEBUG */
// Выход
return(retptr);
}
//----------------------------------------------------------------------------
// Освобождает зарезервированную память, на которую указывает 'ptr' в куче 'heap'.
// Если указатель указывает на память, которая не была выделена ранее
// функциями l_malloc() или l_calloc() или указатель 'ptr' равен 0, то ничего не
// происходит
//----------------------------------------------------------------------------
void l_free(t_heap* heap, void* ptr)
{// Запрещаем прерывания
ATOMIC_BEGIN();
// Временные переменные
t_heap_el* tptr=heap->curel; // Поиск начинается с текущего элемента
t_heap_el* tptrn;
// Отладочная байда
#ifdef MALLOC_DEBUG
NOSTD_DBG_PRINTF("Free :\n");
if(ptr){prmemptr(ptr);}
else{NOSTD_DBG_PRINTF("Nothing ! (NULL)\n");}
#endif /* MALLOC_DEBUG */
// Основной цикл поиска, пока ptr!=0
while(ptr)
{// Удаляемый эл-т найден ?
if(tptr->this_memory_part==ptr)
{// Найден. Удаляем его на хрен
// Отладочная байда
#ifdef MALLOC_DEBUG
NOSTD_DBG_PRINTF("MBL found\n");
#endif /* MALLOC_DEBUG */
// Устанавливаем признак "блок свободен"
tptr->flags &= ~DM_BUSY;
// Проверяем следующий элемент
tptrn = tptr->next_dynamem_descr; // Указатель на следующий элемент
// Если следующий эл-т свободен и не первый в куче,
// то объединяем его с текущим
if ((!(tptrn->flags & DM_BUSY)) && (tptrn!=heap->firstel))
{// Отладочная байда
#ifdef MALLOC_DEBUG
NOSTD_DBG_PRINTF("Join with next\n");
#endif /* MALLOC_DEBUG */
// Объединяем текущий (tptr) и следующий (tptrn) элементы
tptr->this_memory_size = tptr->this_memory_size + tptrn->this_memory_size + sizeof(t_heap_el);
tptr->next_dynamem_descr=tptrn->next_dynamem_descr;
// Если текущий элемент кучи - уничтожаемый при объедтинении
// элемент tptrn, то изменяем его (чтобы он не указывал куда попало)
if(tptrn==heap->curel){heap->curel=tptr;}
// Если эл-т tptrn не последний, то меняем указатель prev_dynamem_descr
// описателя, следующего за ptrn элемента
if( (tptrn->next_dynamem_descr) != heap->firstel)
{tptrn = tptrn->next_dynamem_descr;
tptrn -> prev_dynamem_descr = tptr;
}
//
}
// Если предыдущий эл-т свободен и не первый в куче,
// то объединяем его с текущим
tptrn = tptr->prev_dynamem_descr; // Указатель на предыдущий элемент
if ((!(tptrn->flags & DM_BUSY)) && (tptr!=heap->firstel))
{// Отладочная байда
#ifdef MALLOC_DEBUG
NOSTD_DBG_PRINTF("Join with prev\n");
#endif /* MALLOC_DEBUG */
// Объединяем текущий (tptr) и предыдущий (tptrn) элементы
tptrn->this_memory_size = tptr->this_memory_size + tptrn->this_memory_size + sizeof(t_heap_el);
tptrn->next_dynamem_descr=tptr->next_dynamem_descr;
// Если текущий элемент кучи - уничтожаемый при объедтинении
// элемент tptr, то изменяем его (чтобы он не указывал куда попало)
if(tptr==heap->curel){heap->curel=tptrn;}
// Если эл-т tptr не последний, то меняем указатель prev_dynamem_descr
// описателя, следующего за ptr элемента
if( (tptr->next_dynamem_descr) != heap->firstel)
{tptr = tptr->next_dynamem_descr;
tptr -> prev_dynamem_descr = tptrn;
}
//
}
//
ptr=NULL; // Выходим
}
// Проверка, всю ли кучу просмотрели
if(ptr)
{tptr = tptr->next_dynamem_descr;
// Всю кучу просмотрели, элемента не нашли
if(tptr==heap->curel)
{ptr=NULL; // Выходим
}
}
}
// Отладочная байда
#ifdef MALLOC_DEBUG
NOSTD_DBG_PRINTF("\n");
#endif /* MALLOC_DEBUG */
//
ATOMIC_END(); // Разрешаем прерывания
//
}
//----------------------------------------------------------------------------
Я тут за главного - если что шлите мыло на me собака shaos точка net