Golem  v0.1.1
Generic Operating system Libraries for Embedded Multitasking
 All Data Structures Files Functions Variables Pages
/home/ruud/Engineering/software/projects/golem-project-code/trunk/glm_heap.c
1 
11 /* INCLUDES *******************************************************************/
12 #include "glm_heap.h"
13 #include <stdlib.h>
14 #include <string.h>
15 
16 
17 /* TYPES **********************************************************************/
18 typedef struct
19 {
20  heap_id_t id; // heap-ID of creator
21  size_t size; // size of allocated space (without chunk-header)
22 } chunk_header_t;
23 
24 
25 /* PRIVATE VARIABLES **********************************************************/
26 static heap_stats_t m_totals = { 0, 0 };
27 static heap_stats_t *m_stats = NULL;
28 static uint_base_t m_nr_of_hid = 0;
29 
30 
31 /* PRIVATE FUNCTION DECLARATIONS **********************************************/
32 // Checks if given heap ID exists
33 static bool heap_id_valid(heap_id_t a_id);
34 
35 // Updates the heap-usage statistics for the given heap ID either by adding an
36 // a_size bytes using a_dec=FALSE, or by subtracting it using a_dec=TRUE
37 static void heap_stats_update(heap_id_t a_id, size_t a_size, bool a_dec);
38 
39 // Returns a pointer to the base of a chunk (heap-object) where the header is
40 // located.
41 static chunk_header_t * heap_chunk_base_ptr(void *a_ptr);
42 
43 // Returns a pointer to the chunk (heap-object) offset, relative to the chunk's
44 // header.
45 static void * heap_chunk_offset_ptr(chunk_header_t * a_hdr);
46 
47 
48 /* PUBLIC FUNCTIONS ***********************************************************/
49 
50 void
51 heap_reset()
52 {
53  // Free all registered heap-ID's and their statistics
54  free(m_stats);
55 
56  m_totals.current = 0;
57  m_totals.max = 0;
58  m_nr_of_hid = 0;
59 }
60 
61 bool
62 heap_create_hid(char * a_name, heap_id_t *a_heap_id)
63 {
64  bool is_created = false;
65  void *addr = NULL;
66 
67  if(m_nr_of_hid > 0)
68  {
69  addr = realloc(m_stats, (m_nr_of_hid + 1) * sizeof(heap_stats_t) );
70  }
71  else
72  {
73  addr = malloc(sizeof(heap_stats_t));
74  }
75 
76  if(NULL != addr)
77  {
78  m_stats = addr;
79  m_nr_of_hid++;
80 
81  // Update values
82  *a_heap_id = m_nr_of_hid;
83  m_stats[m_nr_of_hid-1].name = a_name;
84  m_stats[m_nr_of_hid-1].current = 0;
85  m_stats[m_nr_of_hid-1].max = 0;
86  is_created = true;
87  }
88 
89  return is_created;
90 }
91 
92 
93 bool
94 heap_stats(heap_id_t a_heap_id, heap_stats_t * a_heap_stats)
95 {
96  bool is_found = false;
97 
98  if(heap_id_valid(a_heap_id))
99  {
100  // Copy data so that original data is never overwritten
101  *a_heap_stats = m_stats[a_heap_id-1];
102  is_found = true;
103  }
104 
105  return is_found;
106 }
107 
108 
109 void
110 heap_totals(heap_stats_t *a_heap_totals)
111 {
112  // Copy heap totals so that original data is never overwritten
113  *a_heap_totals = m_totals;
114 }
115 
116 
117 void *
118 heap_malloc(heap_id_t a_id, size_t a_size )
119 {
120  chunk_header_t *header = NULL;
121  void *addr_base = NULL;
122  void *addr = NULL;
123  size_t alloc_size = sizeof(chunk_header_t) + a_size;
124 
125  if( (a_size > 0) &&
126  heap_id_valid(a_id) )
127  {
128  addr_base = malloc(alloc_size);
129 
130  // Update stats upon successful allocation
131  if(NULL != addr_base)
132  {
133  // Access header and fill its fields
134  header = (chunk_header_t*) addr_base;
135  header->size = a_size;
136  header->id = a_id;
137 
138  // User object is at offset right behind header
139  addr = heap_chunk_offset_ptr(addr_base);
140 
141  // Update heap user's statistics
142  heap_stats_update(a_id, alloc_size, false);
143  }
144  }
145 
146  // Return user's object-pointer
147  return addr;
148 }
149 
150 void *
151 heap_calloc(heap_id_t a_id, size_t a_nr_elements, size_t a_size)
152 {
153  size_t size = a_nr_elements * a_size;
154  size_t alloc_size = size + sizeof(chunk_header_t);
155  void *addr = NULL;
156 
157  if(heap_id_valid(a_id))
158  {
159  // Use normal alloc for this, since we need to use chunk_header_t
160  addr = heap_malloc(a_id, size);
161 
162  // Update stats upon successful allocation
163  if(NULL != addr)
164  {
165  heap_stats_update(a_id, alloc_size, false);
166 
167  // The real calloc() would initialize all allocated memory to 0, so
168  // mimic that.
169  memset(addr, 0, size);
170  }
171  }
172 
173  return addr;
174 }
175 
176 void *
177 heap_realloc(void *a_ptr, size_t a_size)
178 {
179  void *realloc_base = NULL;
180  void *addr = NULL;
181  chunk_header_t *header = NULL;
182  size_t realloc_size = sizeof(chunk_header_t) + a_size;
183  size_t diff_size = 0;
184 
185  // Allow reallocation only if not a NULL-pointer. We can't use malloc() when
186  // a_ptr == NULL since we need a heap-ID for our heap-administration...
187  if(NULL != a_ptr)
188  {
189  if(0 == a_size)
190  {
191  // User requests to free the memory
192  heap_free(a_ptr);
193  }
194  else
195  {
196  // Get to base address for checking if a size increase is requested
197  // and for reallocation.
198  header = heap_chunk_base_ptr(a_ptr);
199 
200  // Calculate requested size increment
201  diff_size = realloc_size - header->size;
202  if(diff_size > 0)
203  {
204  // Actualy reallocate requested size plus header size
205  realloc_base = realloc(header, realloc_size);
206 
207  // Update stats upon successful allocation
208  if(NULL != realloc_base)
209  {
210  // Get address of the chunk
211  addr = heap_chunk_offset_ptr(realloc_base);
212 
213  // Update user's heap statistics
214  header = heap_chunk_base_ptr(addr);
215  heap_stats_update(header->id, diff_size,false);
216 
217  // Update header size to new size
218  header->size = realloc_size;
219  }
220  }
221  }
222  }
223 
224  return addr;
225 }
226 
227 void
228 heap_free(void * a_ptr)
229 {
230  chunk_header_t *header = NULL;
231  void *addr_base = NULL;
232 
233  if(NULL != a_ptr)
234  {
235  // Access heap container
236  addr_base = header = heap_chunk_base_ptr(a_ptr);
237 
238  // Update heap user's statistics
239  heap_stats_update(header->id, header->size, true);
240 
241  // Free and reset heap-container
242  free(addr_base);
243  a_ptr = NULL;
244  }
245 }
246 
247 
248 size_t
249 heap_sizeof(void * a_ptr)
250 {
251  chunk_header_t *header = NULL;
252 
253  header = heap_chunk_base_ptr(a_ptr);
254 
255  return (size_t) header->size - sizeof(chunk_header_t);
256 }
257 
258 
259 heap_id_t
260 heap_get_id(void * a_ptr)
261 {
262  chunk_header_t * header;
263 
264  header = heap_chunk_base_ptr(a_ptr);
265 
266  return header->id;
267 }
268 
269 
270 void
271 heap_transfer_owner(void * a_ptr, heap_id_t a_id)
272 {
273  chunk_header_t *header;
274  size_t alloc_size;
275 
276  header = heap_chunk_base_ptr(a_ptr);
277  alloc_size = header->size + sizeof(chunk_header_t);
278 
279  if(heap_id_valid(a_id))
280  {
281  // Update current object and new owner heap stats
282  heap_stats_update(header->id, alloc_size, true);
283  heap_stats_update(a_id, alloc_size, false);
284 
285  // Transfer ownership
286  header->id = a_id;
287  }
288 }
289 
290 
291 /* PRIVATE FUNCTIONS *************************************************/
292 
293 bool
294 heap_id_valid(heap_id_t a_heap_id)
295 {
296  return (a_heap_id > 0) &&
297  (a_heap_id <= m_nr_of_hid);
298 }
299 
300 
301 void
302 heap_stats_update(heap_id_t a_id, size_t a_size, bool a_dec)
303 {
304  // Note: size_t is unsigned, therefore use seperate flag [a_dec] to subtract
305  // a_size from statistics in case of memory freed.
306  if(heap_id_valid(a_id))
307  {
308  // Update stats for given id, either by subtracting or adding the given
309  // a_size
310  if(a_dec)
311  {
312  m_stats[a_id-1].current -= a_size;
313  }
314  else
315  {
316  m_stats[a_id-1].current += a_size;
317 
318  if( m_stats[a_id-1].current > m_stats[a_id-1].max )
319  {
320  m_stats[a_id-1].max = m_stats[a_id-1].current;
321  }
322  }
323 
324  // Update total stats as well
325  if(a_dec)
326  {
327  m_totals.current -= a_size;
328  }
329  else
330  {
331  m_totals.current += a_size;
332  if( m_totals.current > m_totals.max )
333  {
334  m_totals.max = m_totals.current;
335  }
336  }
337  }
338 }
339 
340 chunk_header_t *
341 heap_chunk_base_ptr(void *a_ptr)
342 {
343  void * addr_base = NULL;
344 
345  addr_base = (char*) a_ptr - sizeof(chunk_header_t);
346  return (chunk_header_t*) addr_base;
347 }
348 
349 void *
350 heap_chunk_offset_ptr(chunk_header_t * a_hdr)
351 {
352  return (char*) a_hdr + sizeof(chunk_header_t);
353 }