nedoPC.org

Electronics hobbyists community established in 2002
Atom Feed | View unanswered posts | View active topics It is currently 28 Apr 2024 05:13



Reply to topic  [ 4 posts ] 
[SRC] Менеджер памяти 
Author Message
Doomed

Joined: 16 Apr 2005 22:35
Posts: 492
Location: Томск
Reply with quote
Отдаю менеджер локальной кучи безвозмездно и бескорыстно. Особенности:
-автоматом определяет размерность адреса
-функция l_free имеет защиту от дурака (неправильный указатель).
Работает не очень быстро, но надежно. Проверен необнократно на AVR (16битный адрес) и ARM (32битный адрес). Под z80 компилил при помощи SDCC. Вроде тоже нормально работает.

Текст состоит из двух файлов. heap.h и heap.c.
Вопросы задавать МОЖНО

Лежит здесь
http://www.nedopc.org/nedopc/upload/heap.tar


18 Jul 2005 02:32
Profile
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22615
Location: Silicon Valley
Reply with quote
Post 
Перенес топик в MCU так как вроде речь только про мелкоконтроллеры идет ;)

_________________
:dj: https://mastodon.social/@Shaos


15 Aug 2005 18:13
Profile WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22615
Location: Silicon Valley
Reply with quote
Post 
Привожу полные исходные тексты

heap.h
Code:
//----------------------------------------------------------------------------
// Работа с кучей. Заголовочный файл.
//
// Структура кучи:
// |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 */

_________________
:dj: https://mastodon.social/@Shaos


11 Jun 2011 23:21
Profile WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22615
Location: Silicon Valley
Reply with quote
Post 
heap.c
Code:
//----------------------------------------------------------------------------
// Работа с кучей. Заголовочный файл.
//
// Структура кучи:
// |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(); // Разрешаем прерывания
   //
  }
//----------------------------------------------------------------------------

_________________
:dj: https://mastodon.social/@Shaos


11 Jun 2011 23:21
Profile WWW
Display posts from previous:  Sort by  
Reply to topic   [ 4 posts ] 

Who is online

Users browsing this forum: No registered users and 38 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software.