Memory Pool
Create a pool of memory blocks
memory_pool.c
Go to the documentation of this file.
1 /*
2  * author: iancain
3  *
4  * additions: armaan roshani
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdbool.h>
10 #include <stdint.h>
11 #include <memory.h>
12 #include "memory_pool.h"
13 
14 
15 
16 bool DEBUG = false;
17 
18 
19 
20 
21 // PRIVATE: declared inside *.c file
23 {
24  uint32_t magic; // NODE_MAGIC = 0xBAADA555. error checking
25  size_t size;
26  bool inuse; // true = currently allocated. Used for error checking
27 
29 
31 
32 
33 
34 struct memory_pool {
35  size_t count; // total elements
36  size_t block_size; // size of each block
37  size_t available; // (total elements) - (elements in use)
38 
39  struct memory_pool_block_header * pool; // looks like a pointer to a linked list
40 
41  void ** shadow; // shadow copy of nodes to free on destroy even if caller/user still has them in acquired state
42 }; // memory_pool_t (typedef in header)
43 
44 
45 
46 //---
47 // MACROS
48 //
49 
50 // HTODB = header to data block
51 // converts header pointer to container data block
52 //
53 // pointer arithmetic:
54 // takes in:
55 // * header pointer as number
56 // * block size as number
57 // outputs:
58 // header memory address - block size
59 //
60 // This seems to imply that:
61 // * pointers point to lowest address of relevant block of memory
62 // * the datablock exists "below" the header in address space
63 //
64 #define MEMORY_POOL_HTODB(_header_, _block_size_) ((void *)_header_ - _block_size_)
65 
66 // DBTOH = data block to header
67 // convert data block pointer to point to embedded header information block
68 //
69 #define MEMORY_POOL_DBTOH(_data_block_, _block_size_) ((memory_pool_block_header_t *)(_data_block_ + _block_size_))
70 
71 // magic value to check for data corruption
72 #define NODE_MAGIC 0xBAADA555
73 
74 
75 
90 memory_pool_t * memory_pool_init(size_t count, size_t block_size)
91 {
92  memory_pool_t *mp = NULL; // pointer to allocate
93  memory_pool_block_header_t * header = NULL; // pointer to header
94  memory_pool_block_header_t * temp; // pointer to header
95  void * block = NULL; // pointer to data block
96  int n = 0;
97 
98  // allocate memory pool struct. give ownership back to caller
99  mp = (memory_pool_t*) malloc (sizeof(memory_pool_t)); // create memory pool object
100  if( mp == NULL ) {
101  printf("ERROR: memory_pool_init: unable to malloc memory_pool_t. OOM\n");
102  return NULL;
103  }
104 
105  // allocate memory pool block and header combos
106  for( n = 0; n < count; ++n ) {
107 
108  if(DEBUG)
109  printf("*** DEBUG:\tinside for loop, count is: %d\t***\n", n);
110 
111  // allocate data block: data block size + header size
112  //
113  size_t total_size = block_size + sizeof(memory_pool_block_header_t);
114  block = (void *) malloc (total_size);
115 
116  // move to end of data block to create header
117  //
118  temp = header;
119  header = MEMORY_POOL_DBTOH(block, block_size);
120 
121  // add to stack (just a simple stack)
122  // implementing as a linked list
123  header->next = temp;
124  header->size = block_size;
125 
126  printf("MEMORY_POOL: i=%d, data=%p, header=%p, block_size=%zu, next=%p\n",
127  n, // int
128  block, // pointer
129  header, // pointer
130  header->size, // size_t
131  header->next); // pointer
132  }
133 
134  // allocate shadow array of pointers
135  mp->shadow = (void **) calloc(count, sizeof(memory_pool_block_header_t *));
136 
137  printf("memory_pool_init: mp=%p, count=%zu, block_size=%zu\n", mp, count, block_size);
138 
139  // populate variables in new memory_pool object
140  mp->count = count; // total elements
141  mp->block_size = block_size; // size of each block
142  mp->available = count;
143 
144  // attach pool
145  mp->pool = header;
146 
147  // error check: if for loop traversed count times, return mp memory address
148  // else, return NULL
149  return n == count ? mp : NULL;
150 }
151 
152 
153 
155 {
156  if(mp == NULL) { // don't want to deference NULL
157  printf("ERROR: memory_pool_destroy: nothing to destroy.\n");
158  return false;
159  }
160 
161  printf("memory_pool_destroy: mp=%p, pool=%p, count=%zu, available=%zu, block_size=%zu\n",
162  mp,
163  mp->pool,
164  mp->count,
165  mp->available,
166  mp->block_size);
167 
168  memory_pool_block_header_t * header = mp->pool;
170 
171  // free all non-aquired data blocks
172  //for(int n = 0; n < mp->count; ++n ) {
173  for(int n = 0; n < mp->available; ++n ) {
174 
175  printf("memory_pool_destroy: freeing non-aquired data block # %d\n", n+1);
176 
177  next = header->next;
178 
179  void * data_block = MEMORY_POOL_HTODB(header, mp->block_size);
180  free(data_block);
181 
183 
184  header = next;
185  }
186 
187  // free all aquired data blocks
188  for(int n = 0; n < (mp->count - mp->available ); ++n ) {
189 
190  printf("memory_pool_destroy: freeing aquired data block # %d\n", n+1);
191 
192  if(mp->shadow[n] != NULL) { //don't want to free(NULL), causing coredump
193 
194  void * data_block = MEMORY_POOL_HTODB(header, mp->block_size);
195  free(data_block);
196  }
197  }
198 
199  // free memory pool itself
200  free(mp);
201 
202  return true;
203 }
204 
205 
206 
215 {
216  if(mp->pool == NULL) { // don't want to deference NULL
217  printf("ERROR: memory_pool_acquire: nothing to aquire.\n");
218  return NULL;
219  }
220 
221  // grab pointer
222  memory_pool_block_header_t * header = mp->pool;
223 
224  // pop stack
225  mp->pool = mp->pool->next;
226 
227  // pool housekeeping
228  --(mp->available);
229 
230  // header housekeeping
231  header->inuse = true;
232  header->next = NULL;
233 
234  // shadow housekeeping
235  int slot = mp->count - mp->available;
236  mp->shadow[slot] == header;
237 
238  // get data block from header
239  void * data = MEMORY_POOL_HTODB(header, mp->block_size);
240 
241  printf("memory_pool_acquire: mp=%p, data=%p\n", mp, data);
242  return data; // return to caller
243 }
244 
245 
253 bool memory_pool_release(memory_pool_t *mp, void * data)
254 {
255  // move to header inside memory block using MEMORY_POOL_DBTOH(data, mp->block_size);
257 
258  printf("memory_pool_release: data=%p, header=%p, block_size=%zu, next=%p\n",
259  data, header, header->size, header->next);
260 
261  // grab pointer
263 
264  // push on stack
265  mp->pool = header;
266  header->next = next;
267 
268  // header housekeeping
269  header->inuse = false;
270 
271  // shadow housekeeping
272  int slot = mp->count - mp->available;
273  mp->shadow[slot] == NULL;
274 
275  // pool housekeeping
276  //
277  // do this after shadow housekeeping to allow (count - available)
278  // to include correct slot
279  ++(mp->available);
280 
281  return true;
282 }
283 
284 
285 
294 {
295  if( mp == NULL ) {
296  printf("ERROR: memory_pool_available: memory pool invalid\n");
297  return 0;
298  }
299  return mp->available;
300 }
301 
302 
303 
311 {
312  if( mp == NULL ) {
313  printf("ERROR: memory_pool_dump: memory pool invalid\n");
314  return;
315  }
316 
317  printf("memory_pool_dump: mp = %p, count=%zu, available=%zu, block_size=%zu\n",
318  mp, // pointer
319  mp->count, // size_t
320  mp->available, // size_t
321  mp->block_size); // size_t
322 
323  // point to initial header
324  memory_pool_block_header_t * header = mp->pool;
325 
326  for(int n = 0; n < mp->available; ++n ) {
327 
328  // use header-to-data-block macro to create pointer
329  void * data_block = MEMORY_POOL_HTODB(header, mp->block_size);
330 
331  printf(" + block: i=%d, data=%p, header=%p, inuse=%s, block_size=%zu, next=%p\n",
332  n, // int
333  data_block, // pointer
334  header, // pointer
335  header->inuse ? "TRUE":"FALSE", // bool
336  header->size, // size_t
337  header->next); // pointer
338 
339  header = header->next;
340  }
341 
342  return;
343 }
bool DEBUG
Definition: memory_pool.c:16
size_t block_size
Definition: memory_pool.c:36
struct memory_pool_block_header * pool
Definition: memory_pool.c:39
size_t memory_pool_available(memory_pool_t *mp)
memory pool availability function
Definition: memory_pool.c:293
void ** shadow
Definition: memory_pool.c:41
bool memory_pool_release(memory_pool_t *mp, void *data)
memory pool push function
Definition: memory_pool.c:253
struct memory_pool_block_header memory_pool_block_header_t
type alias for global namespace
size_t count
Definition: memory_pool.c:35
#define MEMORY_POOL_DBTOH(_data_block_, _block_size_)
Definition: memory_pool.c:69
memory_pool_t * memory_pool_init(size_t count, size_t block_size)
memory pool initializer
Definition: memory_pool.c:90
size_t available
Definition: memory_pool.c:37
void * memory_pool_acquire(memory_pool_t *mp)
memory pool pop function
Definition: memory_pool.c:214
void memory_pool_dump(memory_pool_t *mp)
memory pool dump function
Definition: memory_pool.c:310
#define MEMORY_POOL_HTODB(_header_, _block_size_)
Definition: memory_pool.c:64
bool memory_pool_destroy(memory_pool_t *mp)
Definition: memory_pool.c:154
struct memory_pool_block_header * next
looks like a linked list
Definition: memory_pool.c:28