Embedded Artistry libmemory
Memory library for embedded systems (malloc and friends)
malloc_freelist.c
Go to the documentation of this file.
1 /*
2  * Copyright © 2017 Embedded Artistry LLC.
3  * License: MIT. See LICENSE file for details.
4  */
5 
6 #include <linkedlist/ll.h>
7 #include <malloc.h>
8 #include <memory.h>
9 #include <stdint.h>
10 
11 #pragma mark - Definitions -
12 
17 #ifndef align_up
18 #define align_up(num, align) (((num) + ((align)-1)) & ~((align)-1))
19 #endif
20 
21 /*
22  * This is the container for our free-list.
23  * Node the usage of the linked list here: the library uses offsetof
24  * and container_of to manage the list and get back to the parent struct.
25  */
26 typedef struct
27 {
28  ll_t node;
29  size_t size;
30  char* block;
31 } alloc_node_t;
32 
37 #define ALLOC_HEADER_SZ offsetof(alloc_node_t, block)
38 
39 // We are enforcing a minimum allocation size of 32B.
40 #define MIN_ALLOC_SZ ALLOC_HEADER_SZ + 32
41 
42 #pragma mark - Prototypes -
43 
44 static void defrag_free_list(void);
45 
46 #pragma mark - Declarations -
47 
48 // This macro simply declares and initializes our linked list
49 static LIST_INIT(free_list);
50 
51 #pragma mark - Private Functions -
52 
58 void defrag_free_list(void)
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 }
78 
79 #pragma mark - APIs -
80 
81 __attribute__((weak)) void malloc_init(void)
82 {
83  // Unused here, override to specify your own init functin
84  // Which includes malloc_addblock calls
85 }
86 
87 void* malloc(size_t size)
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 }
127 
128 void free(void* ptr)
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 }
155 
156 void malloc_addblock(void* addr, size_t size)
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 }
static LIST_INIT(free_list)
static void defrag_free_list(void)
void malloc_addblock(void *addr, size_t size)
Assign blocks of memory for use by malloc().
#define align_up(num, align)
void free(void *ptr)
__attribute__((weak))
#define MIN_ALLOC_SZ
void * malloc(size_t size)
void malloc_init(void)
Initialize Malloc.
#define ALLOC_HEADER_SZ