* @brief Allocate a block of memory with a minimum of 'size' bytes. * * @param m the small memory management object. * * @param size is the minimum size of the requested block in bytes. * * @return the pointer to allocated memory or NULL if no free memory was found. */
| 269 | * @return the pointer to allocated memory or NULL if no free memory was found. |
| 270 | */ |
| 271 | void *rt_smem_alloc(rt_smem_t m, rt_size_t size) |
| 272 | { |
| 273 | rt_size_t ptr, ptr2; |
| 274 | struct rt_small_mem_item *mem, *mem2; |
| 275 | struct rt_small_mem *small_mem; |
| 276 | |
| 277 | if (size == 0) |
| 278 | return RT_NULL; |
| 279 | |
| 280 | RT_ASSERT(m != RT_NULL); |
| 281 | RT_ASSERT(rt_object_get_type(&m->parent) == RT_Object_Class_Memory); |
| 282 | RT_ASSERT(rt_object_is_systemobject(&m->parent)); |
| 283 | |
| 284 | small_mem = (struct rt_small_mem *)m; |
| 285 | /* alignment size */ |
| 286 | size = RT_ALIGN(size, RT_ALIGN_SIZE); |
| 287 | |
| 288 | /* every data block must be at least MIN_SIZE_ALIGNED long */ |
| 289 | if (size < MIN_SIZE_ALIGNED) |
| 290 | size = MIN_SIZE_ALIGNED; |
| 291 | |
| 292 | if (size > small_mem->mem_size_aligned) |
| 293 | { |
| 294 | LOG_D("no memory"); |
| 295 | |
| 296 | return RT_NULL; |
| 297 | } |
| 298 | |
| 299 | for (ptr = (rt_uint8_t *)small_mem->lfree - small_mem->heap_ptr; |
| 300 | ptr <= small_mem->mem_size_aligned - size; |
| 301 | ptr = ((struct rt_small_mem_item *)&small_mem->heap_ptr[ptr])->next) |
| 302 | { |
| 303 | mem = (struct rt_small_mem_item *)&small_mem->heap_ptr[ptr]; |
| 304 | |
| 305 | if ((!MEM_ISUSED(mem)) && (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) |
| 306 | { |
| 307 | /* mem is not used and at least perfect fit is possible: |
| 308 | * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ |
| 309 | |
| 310 | if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= |
| 311 | (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) |
| 312 | { |
| 313 | /* (in addition to the above, we test if another struct rt_small_mem_item (SIZEOF_STRUCT_MEM) containing |
| 314 | * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') |
| 315 | * -> split large block, create empty remainder, |
| 316 | * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if |
| 317 | * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, |
| 318 | * struct rt_small_mem_item would fit in but no data between mem2 and mem2->next |
| 319 | * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty |
| 320 | * region that couldn't hold data, but when mem->next gets freed, |
| 321 | * the 2 regions would be combined, resulting in more free memory |
| 322 | */ |
| 323 | ptr2 = ptr + SIZEOF_STRUCT_MEM + size; |
| 324 | |
| 325 | /* create mem2 struct */ |
| 326 | mem2 = (struct rt_small_mem_item *)&small_mem->heap_ptr[ptr2]; |
| 327 | mem2->pool_ptr = MEM_FREED(small_mem); |
| 328 | mem2->next = mem->next; |
no test coverage detected