gitignore *.o *.swp
[firmware_header_edit.git] / heap_reap.c
1 /* experimental tracking of heap allocations for easy reaping no matter what the code path is
2  *
3  * both tasks are in the same function to take advantage of local static variables that are
4  * persistent across calls but invisible to code outside the function.
5  *
6  * @param ptr   NULL: calloc(nmemb, size), NULL-1: reap all, otherwise free(ptr)
7  * @param nmemb number of elements of size to allocate
8  * @param size  size if each element
9  */
10
11 #include "heap_reap.h"
12 #include <stdio.h>
13
14 unsigned int heap_debug = 0;
15
16 struct mem_track {
17   void *ptr;
18   struct mem_track *prev;
19   struct mem_track *next;
20   size_t requested;
21   size_t allocated;
22 };
23
24 void *
25 heap_and_reap(void *ptr, size_t nmemb, size_t size)
26 {
27   static struct mem_track *memalloc = NULL;
28   struct mem_track *tmp;
29   void *result = NULL;
30
31   if (ptr == NULL) { 
32     // allocate requested memory and 'hide' the struct mem_track at the end of it
33     size_t dwords = ((nmemb * size + sizeof(struct mem_track)) / 4) + 1;
34
35     if ((result = calloc(dwords, 4)) != NULL) {
36       tmp = (struct mem_track *) (result + (dwords * 4) - sizeof(struct mem_track)  );
37       tmp->allocated = dwords * 4;
38       tmp->requested = nmemb * size;
39       tmp->ptr = result;
40       tmp->prev = memalloc;
41       tmp->next = NULL;
42       if (memalloc)
43         memalloc->next = tmp;
44       else
45         memalloc = tmp;
46       if (heap_debug)
47         fprintf(stderr, "heap req %08lx alloc %08lx @ %p\n", tmp->requested, tmp->allocated, tmp);
48     }
49   }
50   else { // free allocation
51     struct mem_track *p = memalloc;
52     while (p) {
53       if (ptr == NULL-1 || p->ptr == ptr) { // free all or a specific allocation
54         if (heap_debug)
55           fprintf(stderr, "heap free %08lx @ %p\n", p->allocated, p);
56         tmp = p->next;
57         if (p->prev)
58           p->prev->next = p->next;
59         if (p->next)
60           p->next->prev = p->prev;
61         free(p->ptr);
62         if (memalloc == p)
63           memalloc = tmp;
64         p = tmp;
65         if (ptr != NULL-1) // only freeing a specific allocation
66           break;
67       } else
68         p = p->next;
69     }
70   }
71   return result;
72 }
73