Embedded Artistry libmemory
Memory library for embedded systems (malloc and friends)
malloc_freelist.c File Reference
#include <linkedlist/ll.h>
#include <malloc.h>
#include <memory.h>
#include <stdint.h>
Include dependency graph for malloc_freelist.c:

Go to the source code of this file.

Classes

struct  alloc_node_t
 

Macros

#define align_up(num, align)   (((num) + ((align)-1)) & ~((align)-1))
 
#define ALLOC_HEADER_SZ   offsetof(alloc_node_t, block)
 
#define MIN_ALLOC_SZ   ALLOC_HEADER_SZ + 32
 

Functions

static void defrag_free_list (void)
 
static LIST_INIT (free_list)
 
 __attribute__ ((weak))
 
void * malloc (size_t size)
 
void free (void *ptr)
 
void malloc_addblock (void *addr, size_t size)
 Assign blocks of memory for use by malloc(). More...
 

Class Documentation

◆ alloc_node_t

struct alloc_node_t

Definition at line 26 of file malloc_freelist.c.

Collaboration diagram for alloc_node_t:
Collaboration graph
Class Members
char * block
ll_t node
size_t size

Macro Definition Documentation

◆ align_up

#define align_up (   num,
  align 
)    (((num) + ((align)-1)) & ~((align)-1))

Simple macro for making sure memory addresses are aligned to the nearest power of two

Definition at line 18 of file malloc_freelist.c.

◆ ALLOC_HEADER_SZ

#define ALLOC_HEADER_SZ   offsetof(alloc_node_t, block)

We vend a memory address to the user. This lets us translate back and forth between the vended pointer and the container we use for managing the data.

Definition at line 37 of file malloc_freelist.c.

◆ MIN_ALLOC_SZ

#define MIN_ALLOC_SZ   ALLOC_HEADER_SZ + 32

Definition at line 40 of file malloc_freelist.c.

Function Documentation

◆ __attribute__()

__attribute__ ( (weak)  )

Definition at line 81 of file malloc_freelist.c.

82 {
83  // Unused here, override to specify your own init functin
84  // Which includes malloc_addblock calls
85 }

◆ defrag_free_list()

void defrag_free_list ( void  )
static

When we free, we can take our node and check to see if any memory blocks can be combined into larger blocks. This will help us fight against memory fragmentation in a simple way.

Definition at line 58 of file malloc_freelist.c.

59 {
60  alloc_node_t* b;
61  alloc_node_t* lb = NULL;
62  alloc_node_t* t;
63 
64  list_for_each_entry_safe(b, t, &free_list, node)
65  {
66  if(lb)
67  {
68  if((((uintptr_t)&lb->block) + lb->size) == (uintptr_t)b)
69  {
70  lb->size += sizeof(*b) + b->size;
71  list_del(&b->node);
72  continue;
73  }
74  }
75  lb = b;
76  }
77 }

References alloc_node_t::block, and alloc_node_t::size.

Referenced by free().

◆ free()

void free ( void *  ptr)

Definition at line 128 of file malloc_freelist.c.

129 {
130  alloc_node_t* free_blk;
131  alloc_node_t* blk;
132 
133  // Don't free a NULL pointer..
134  if(ptr)
135  {
136  // we take the pointer and use container_of to get the corresponding alloc block
137  blk = container_of(ptr, alloc_node_t, block);
138 
139  // Let's put it back in the proper spot
140  list_for_each_entry(free_blk, &free_list, node)
141  {
142  if(free_blk > blk)
143  {
144  list_insert(&blk->node, free_blk->node.prev, &free_blk->node);
145  goto blockadded;
146  }
147  }
148  list_add_tail(&blk->node, &free_list);
149 
150  blockadded:
151  // Let's see if we can combine any memory
153  }
154 }
static void defrag_free_list(void)

References defrag_free_list(), and alloc_node_t::node.

◆ LIST_INIT()

static LIST_INIT ( free_list  )
static

◆ malloc()

void* malloc ( size_t  size)

Definition at line 87 of file malloc_freelist.c.

88 {
89  void* ptr = NULL;
90  alloc_node_t* blk = NULL;
91 
92  if(size > 0)
93  {
94  // Align the pointer
95  size = align_up(size, sizeof(void*));
96 
97  // try to find a big enough block to alloc
98  list_for_each_entry(blk, &free_list, node)
99  {
100  if(blk->size >= size)
101  {
102  ptr = &blk->block;
103  break;
104  }
105  }
106 
107  // we found something
108  if(ptr)
109  {
110  // Can we split the block?
111  if((blk->size - size) >= MIN_ALLOC_SZ)
112  {
113  alloc_node_t* new_blk;
114  new_blk = (alloc_node_t*)((uintptr_t)(&blk->block) + size);
115  new_blk->size = blk->size - size - ALLOC_HEADER_SZ;
116  blk->size = size;
117  list_insert(&new_blk->node, &blk->node, blk->node.next);
118  }
119 
120  list_del(&blk->node);
121  }
122 
123  } // else NULL
124 
125  return ptr;
126 }
#define align_up(num, align)
#define MIN_ALLOC_SZ
#define ALLOC_HEADER_SZ

References align_up, ALLOC_HEADER_SZ, alloc_node_t::block, MIN_ALLOC_SZ, alloc_node_t::node, and alloc_node_t::size.

◆ malloc_addblock()

void malloc_addblock ( void *  addr,
size_t  size 
)

Assign blocks of memory for use by malloc().

Initializes the malloc() backend with a memory address and memory pool size. This memory is assumed to be owned by malloc() and is vended out when memory is requested. Multiple blocks can be added.

NOTE: This API must be called before malloc() can be used. If you call malloc() before allocating memory, malloc() will return NULL because there is no available memory to provide to the user.

Parameters
addrPointer to the memory block address that you are providing to malloc()
sizeSize of the memory block that you are providing to malloc()

Definition at line 156 of file malloc_freelist.c.

157 {
158  alloc_node_t* blk;
159 
160  // let's align the start address of our block to the next pointer aligned number
161  blk = (void*)align_up((uintptr_t)addr, sizeof(void*));
162 
163  // calculate actual size - remove our alignment and our header space from the availability
164  blk->size = (uintptr_t)addr + size - (uintptr_t)blk - ALLOC_HEADER_SZ;
165 
166  // and now our giant block of memory is added to the list!
167  list_add(&blk->node, &free_list);
168 }
#define align_up(num, align)
#define ALLOC_HEADER_SZ

References align_up, ALLOC_HEADER_SZ, alloc_node_t::node, and alloc_node_t::size.