POK
/home/jaouen/pok_official/pok/trunk/libpok/core/allocator.c
00001 /*
00002  *                               POK header
00003  * 
00004  * The following file is a part of the POK project. Any modification should
00005  * made according to the POK licence. You CANNOT use this file or a part of
00006  * this file is this part of a file for your own project
00007  *
00008  * For more information on the POK licence, please see our LICENCE FILE
00009  *
00010  * Please follow the coding guidelines described in doc/CODING_GUIDELINES
00011  *
00012  *                                      Copyright (c) 2007-2009 POK team 
00013  *
00014  * Created by julien on Thu Jul 30 15:49:30 2009 
00015  */
00016 
00017 #include <core/dependencies.h>
00018 #include <core/allocator.h>
00019 
00020 /*
00021  * This is the allocator of POK. It remains in partition. You can configure it
00022  * with POK_CONFIG_ALLOCATOR_MEMORY_SIZE (total amount of memory that can be allocated
00023  * and with POK_CONFIG_ALLOCATOR_NB_SPACES (total amount of memory spaces that can be
00024  * allocated (number of successive calls to malloc() or calloc() for example.
00025  */
00026 
00027 #ifdef POK_NEEDS_ALLOCATOR
00028 
00029 #ifndef POK_CONFIG_ALLOCATOR_MEMORY_SIZE
00030 #define POK_CONFIG_ALLOCATOR_MEMORY_SIZE 16384
00031 #endif
00032 
00033 #ifndef POK_CONFIG_ALLOCATOR_NB_SPACES
00034 #define POK_CONFIG_ALLOCATOR_NB_SPACES 100
00035 #endif
00036 
00037 #define POK_ALLOCATOR_CHECK_INIT  \
00038                   if (pok_allocator_initialized == 0)\
00039                   { \
00040                      uint32_t toto; \
00041                      for (toto = 0 ; toto < POK_CONFIG_ALLOCATOR_NB_SPACES ; toto++) \
00042                      { \
00043                         pok_allocator_spaces[toto].start = 0; \
00044                         pok_allocator_spaces[toto].size  = 0; \
00045                         pok_allocator_spaces[toto].allocated  = 0; \
00046                      } \
00047                      pok_allocator_used_spaces = 1; \
00048                      pok_allocator_spaces[0].start = 0; /* Initialize the first space */ \
00049                      pok_allocator_spaces[0].allocated = 0; \
00050                      pok_allocator_spaces[0].size = POK_CONFIG_ALLOCATOR_MEMORY_SIZE;\
00051                      pok_allocator_initialized = 1; \
00052                   }
00053 
00054 /* POK_ALLOCATOR_CHECK_INIT is a macro that performs initialization functions
00055  * for memory allocator. It is called each time alloc or free functions are called
00056  * but initialized the memory allocator only one time.
00057  */
00058 
00059 
00060 typedef struct
00061 {
00062    size_t   start;
00063    size_t   size;
00064    bool_t   allocated;
00065 } pok_allocator_space_t;
00066 
00067 
00068 uint8_t                 pok_allocator_memspace[POK_CONFIG_ALLOCATOR_MEMORY_SIZE];
00069 pok_allocator_space_t   pok_allocator_spaces[POK_CONFIG_ALLOCATOR_NB_SPACES];
00070 uint32_t                pok_allocator_used_spaces = 0;
00071 bool_t                  pok_allocator_initialized = 0;
00072 
00073 #ifdef POK_NEEDS_DEBUG
00074 void pok_allocator_print_spaces ()
00075 {
00076    uint32_t space;
00077    printf ("[LIBPOK] [ALLOCATOR] Used spaces = %d\n", pok_allocator_used_spaces);
00078    for (space = 0 ; space < pok_allocator_used_spaces ; space++)
00079    {
00080       printf ("[LIBPOK] [ALLOCATOR] Space %d start=%d size=%d allocated=%d\n", space, pok_allocator_spaces[space].start, pok_allocator_spaces[space].size, pok_allocator_spaces[space].allocated);
00081    }
00082 }
00083 #endif
00084 
00085 void* pok_allocator_allocate (size_t needed_size)
00086 {
00087    POK_ALLOCATOR_CHECK_INIT
00088    uint32_t space;
00089    uint32_t new_space;
00090 
00091    if (pok_allocator_used_spaces >= (POK_CONFIG_ALLOCATOR_NB_SPACES - 1))
00092    {
00093 #ifdef POK_NEEDS_DEBUG
00094       printf ("[LIBPOK] [ALLOCATOR] Not enough space\n");
00095 #endif
00096       return NULL;
00097    }
00098 
00099 #ifdef POK_NEEDS_DEBUG
00100    printf("Try to take a new memory chunk, required space=%d\n", needed_size);
00101 #endif
00102 
00103    for (space = 0 ; space < pok_allocator_used_spaces ; space++)
00104    {
00105 #ifdef POK_NEEDS_DEBUG
00106       printf ("[LIBPOK] [ALLOCATOR] Look space %d, size %d, allocated=%d\n", space, pok_allocator_spaces[space].size, pok_allocator_spaces[space].allocated);
00107 #endif
00108       if ((pok_allocator_spaces[space].allocated == 0) && (pok_allocator_spaces[space].size >= needed_size))
00109       {
00110          if (pok_allocator_spaces[space].size == needed_size)
00111          {
00112             /*
00113              * The space corresponds exactly to the requested memory space
00114              */
00115             pok_allocator_spaces[space].allocated = 1;
00116 
00117 #ifdef POK_NEEDS_DEBUG
00118             printf ("[LIBPOK] [ALLOCATOR] Allocate directly space %d\n", space);
00119             pok_allocator_print_spaces ();
00120 #endif
00121             return (&pok_allocator_memspace[pok_allocator_spaces[space].start]);
00122          }
00123          else
00124          {
00125             /*
00126              * We need to split the block in two new blocks !
00127              */
00128             new_space = pok_allocator_used_spaces;
00129             pok_allocator_used_spaces = pok_allocator_used_spaces + 1;
00130 
00131             pok_allocator_spaces[space].allocated        = 1;
00132             pok_allocator_spaces[new_space].allocated    = 0;
00133 
00134             pok_allocator_spaces[new_space].size         = pok_allocator_spaces[space].size - needed_size;
00135             pok_allocator_spaces[space].size             = needed_size;
00136 
00137             pok_allocator_spaces[new_space].start        = pok_allocator_spaces[space].start + needed_size;
00138 
00139 #ifdef POK_NEEDS_DEBUG
00140             printf("[LIBPOK] [ALLOCATOR] Allocate space %d, CREATE NEW SPACE %d (size=%d)\n", space, new_space, pok_allocator_spaces[new_space].size);
00141             pok_allocator_print_spaces ();
00142 #endif
00143 
00144             return (&pok_allocator_memspace[pok_allocator_spaces[space].start]);
00145          }
00146       }
00147    }
00148 
00149 #ifdef POK_NEEDS_DEBUG
00150       printf ("[LIBPOK] [ALLOCATOR] Didn't find any space for that amount of memory (%d)\n", needed_size);
00151 #endif
00152    return NULL;
00153 }
00154 
00155 /*
00156  * Delete a space
00157  */
00158 void pok_allocator_delete_space (uint32_t space)
00159 {
00160    uint32_t tmp;
00161 
00162 #ifdef POK_NEEDS_DEBUG
00163             printf("[LIBPOK] [ALLOCATOR] Delete space %d\n", space);
00164 #endif
00165 
00166    for (tmp = space ; tmp < POK_CONFIG_ALLOCATOR_NB_SPACES ; tmp++)
00167    {
00168       pok_allocator_spaces[tmp].allocated = pok_allocator_spaces[tmp+1].allocated;
00169       pok_allocator_spaces[tmp].size      = pok_allocator_spaces[tmp+1].size;
00170       pok_allocator_spaces[tmp].start     = pok_allocator_spaces[tmp+1].start;
00171    }
00172 
00173    pok_allocator_used_spaces = pok_allocator_used_spaces - 1;
00174 }
00175 
00176 void pok_allocator_merge_space (uint32_t space)
00177 {
00178    uint32_t space2;
00179 
00180    if (pok_allocator_used_spaces == 1)
00181    {
00182       return;
00183    }
00184 
00185    for (space2 = 0 ; space2 < pok_allocator_used_spaces ; space2++)
00186    {
00187       if ((space2 == space) || (pok_allocator_spaces[space2].allocated == 1))
00188       {
00189          continue;
00190       }
00191 
00192       /*
00193        * In that case, space is a the end of space2. We can merge space in space2
00194        */
00195       if (pok_allocator_spaces[space].start == (pok_allocator_spaces[space2].start + pok_allocator_spaces[space2].size))
00196       {
00197 #ifdef POK_NEEDS_DEBUG
00198 //         printf("[LIBPOK] [ALLOCATOR] Merge space %d, with %d\n", space, space2);
00199 #endif
00200          pok_allocator_spaces[space2].size = pok_allocator_spaces[space2].size + pok_allocator_spaces[space].size;
00201          pok_allocator_delete_space (space);
00202          pok_allocator_merge_space (space2);
00203          return;
00204       }
00205 
00206       /*
00207        * In that case, space2 is located at the end of space. We can merge space2 in space
00208        */
00209       if (pok_allocator_spaces[space2].start == (pok_allocator_spaces[space].start + pok_allocator_spaces[space].size))
00210       {
00211 #ifdef POK_NEEDS_DEBUG
00212 //         printf("[LIBPOK] [ALLOCATOR] Merge space %d, with %d\n", space, space2);
00213 #endif
00214          pok_allocator_spaces[space].size = pok_allocator_spaces[space].size + pok_allocator_spaces[space2].size;
00215          pok_allocator_delete_space (space2);
00216          pok_allocator_merge_space (space2);
00217          return;
00218       }
00219    }
00220 }
00221 
00222 
00223 void pok_allocator_free (void* ptr)
00224 {
00225    POK_ALLOCATOR_CHECK_INIT
00226 
00227    uint32_t space;
00228 
00229    for (space = 0 ; space < pok_allocator_used_spaces ; space++)
00230    {
00231       if (ptr == &pok_allocator_memspace[pok_allocator_spaces[space].start])
00232       {
00233          /* Here, we find the space to free */
00234          pok_allocator_spaces[space].allocated = 0;
00235          pok_allocator_merge_space (space);
00236 #ifdef POK_NEEDS_DEBUG
00237          pok_allocator_print_spaces ();
00238 #endif
00239          return;
00240       }
00241    }
00242 
00243 #ifdef POK_NEEDS_DEBUG
00244    printf("[LIBPOK] [ALLOCATOR] free() didn't find the space to free\n");
00245    pok_allocator_print_spaces ();
00246 #endif
00247    return;
00248 }
00249 
00250 #endif
00251