MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
memory.c
Go to the documentation of this file.
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdarg.h>
5 #include "memory.h"
6 #include "endrun.h"
7 
8 #define MAGIC "DEADBEEF"
9 #define ALIGNMENT 4096
10 
11 struct BlockHeader {
12  char magic[8];
14  char * ptr;
15  char * self; /* points to the starting of the header in the allocator; useful in use_malloc mode */
16  size_t size;
17  size_t request_size;
18  char name[127];
19  int dir;
20  char annotation[];
21 } ;
22 
23 int
24 allocator_init(Allocator * alloc, const char * name, const size_t request_size, const int zero, Allocator * parent)
25 {
26  size_t size = (request_size / ALIGNMENT + 1) * ALIGNMENT;
27 
28  char * rawbase;
29  if (parent) {
30  rawbase = (char *) allocator_alloc(parent, name, size + ALIGNMENT, ALLOC_DIR_BOT, "Child");
31  if(rawbase == NULL)
32  return ALLOC_ENOMEMORY;
33  }
34  else
35  if(posix_memalign((void **) &rawbase, ALIGNMENT, size + ALIGNMENT))
36  return ALLOC_ENOMEMORY;
37 
38  alloc->parent = parent;
39  alloc->rawbase = rawbase;
40  alloc->base = rawbase + ALIGNMENT - ((size_t) rawbase % ALIGNMENT);
41  alloc->size = size;
42  alloc->use_malloc = 0;
43  strncpy(alloc->name, name, 11);
44  alloc->refcount = 1;
45  alloc->top = alloc->size;
46  alloc->bottom = 0;
47 
48  allocator_reset(alloc, zero);
49 
50  return 0;
51 }
52 
53 int
54 allocator_malloc_init(Allocator * alloc, const char * name, const size_t request_size, const int zero, Allocator * parent)
55 {
56  /* max support 4096 blocks; ignore request_size */
57  size_t size = ALIGNMENT * 4096;
58 
59  char * rawbase;
60  if (parent) {
61  rawbase = (char *) allocator_alloc(parent, name, size + ALIGNMENT, ALLOC_DIR_BOT, "Child");
62  if (rawbase == NULL) return ALLOC_ENOMEMORY;
63  }
64  else
65  if(posix_memalign((void **) &rawbase, ALIGNMENT, size + ALIGNMENT))
66  return ALLOC_ENOMEMORY;
67 
68 
69  alloc->parent = parent;
70  alloc->use_malloc = 1;
71  alloc->rawbase = rawbase;
72  alloc->base = rawbase;
73  alloc->size = size;
74  strncpy(alloc->name, name, 11);
75  alloc->refcount = 1;
76  alloc->top = alloc->size;
77  alloc->bottom = 0;
78 
79  allocator_reset(alloc, zero);
80 
81  return 0;
82 }
83 
84 int
85 allocator_reset(Allocator * alloc, int zero)
86 {
87  /* Free the memory when using malloc*/
88  if(alloc->use_malloc) {
89  AllocatorIter iter[1];
90  for(allocator_iter_start(iter, alloc); !allocator_iter_ended(iter); allocator_iter_next(iter))
91  {
92  free(iter->ptr - ALIGNMENT);
93  }
94  }
95  alloc->refcount = 1;
96  alloc->top = alloc->size;
97  alloc->bottom = 0;
98 
99  if(zero) {
100  memset(alloc->base, 0, alloc->size);
101  }
102  return 0;
103 }
104 
105 static void *
106 allocator_alloc_va(Allocator * alloc, const char * name, const size_t request_size, const int dir, const char * fmt, va_list va)
107 {
108  size_t size = request_size;
109 
110  if(alloc->use_malloc) {
111  size = 0; /* because we'll get it from malloc */
112  } else {
113  size = ((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
114  }
115  size += ALIGNMENT; /* for the header */
116 
117  char * ptr;
118  if(dir == ALLOC_DIR_BOT) {
119  if(alloc->bottom + size > alloc->top) {
120  allocator_print(alloc);
121  endrun(1, "Not enough memory for %s %td bytes\n", name, size);
122  }
123  ptr = alloc->base + alloc->bottom;
124  alloc->bottom += size;
125  alloc->refcount += 1;
126  } else if (dir == ALLOC_DIR_TOP) {
127  if(alloc->top < alloc->bottom + size) {
128  allocator_print(alloc);
129  endrun(1, "Not enough memory for %s %td bytes\n", name, size);
130  }
131  ptr = alloc->base + alloc->top - size;
132  alloc->refcount += 1;
133  alloc->top -= size;
134  } else {
135  /* wrong dir cannot allocate */
136  return NULL;
137  }
138 
139  struct BlockHeader * header = (struct BlockHeader *) ptr;
140  memcpy(header->magic, MAGIC, 8);
141  header->self = ptr;
142  header->size = size;
143  header->request_size = request_size;
144  header->dir = dir;
145  header->alloc = alloc;
146  strncpy(header->name, name, 126);
147  header->name[126] = '\0';
148 
149  vsprintf(header->annotation, fmt, va);
150 
151  char * cptr;
152  if(alloc->use_malloc) {
153  /* prepend a copy of the header to the malloc block; allocator_free will use it*/
154  if(posix_memalign((void **) &cptr, ALIGNMENT, request_size + ALIGNMENT))
155  endrun(1, "Failed malloc: %lu bytes for %s\n", request_size, header->name);
156  header->ptr = cptr + ALIGNMENT;
157  memcpy(cptr, header, ALIGNMENT);
158  cptr = header->ptr;
159  } else {
160  cptr = ptr + ALIGNMENT;
161  header->ptr = cptr;
162  }
163  return cptr;
164 }
165 void *
166 allocator_alloc(Allocator * alloc, const char * name, const size_t request_size, const int dir, const char * fmt, ...)
167 {
168  va_list va;
169  va_start(va, fmt);
170  void * rt = allocator_alloc_va(alloc, name, request_size, dir, fmt, va);
171  va_end(va);
172  return rt;
173 }
174 
175 int
177 {
178  if(alloc->refcount != 1) {
180  endrun(1, "leaked\n");
181  }
182  if(alloc->parent)
184  else
185  free(alloc->rawbase);
186  return 0;
187 }
188 
189 int
191  AllocatorIter * iter,
192  Allocator * alloc
193  )
194 {
195  iter->alloc = alloc;
196  iter->_bottom = 0;
197  iter->_top = alloc->top;
198  iter->_ended = 0;
199  return allocator_iter_next(iter);
200 }
201 
202 static int
203 is_header(struct BlockHeader * header)
204 {
205  return 0 == memcmp(header->magic, MAGIC, 8);
206 }
207 
208 int
210  AllocatorIter * iter
211  )
212 {
213  struct BlockHeader * header;
214  Allocator * alloc = iter->alloc;
215  if(alloc->bottom != iter->_bottom) {
216  header = (struct BlockHeader *) (iter->_bottom + alloc->base);
217  iter->_bottom += header->size;
218  } else
219  if(iter->_top != alloc->size) {
220  header = (struct BlockHeader *) (iter->_top + alloc->base);
221  iter->_top += header->size;
222  } else {
223  iter->_ended = 1;
224  return 0;
225  }
226  if (! is_header(header)) {
227  /* several corruption that shall not happen */
228  endrun(5, "Ptr %p is not a magic header\n", header);
229  }
230  iter->ptr = header->ptr;
231  iter->name = header->name;
232  iter->annotation = header->annotation;
233  iter->size = header->size;
234  iter->request_size = header->request_size;
235  iter->dir = header->dir;
236  return 1;
237 }
238 
239 int
241 {
242  return iter->_ended;
243 }
244 
245 size_t
247 {
248  /*For malloc, return a fixed 2GB */
249  if(alloc->use_malloc) {
250  return 2L*1024L*1024L*1024L;
251  }
252  return (alloc->top - alloc->bottom);
253 }
254 
255 size_t
257 {
258  /* For malloc sum up the requested memory.
259  * I considered mallinfo, but there may be multiple memory arenas. */
260  if(alloc->use_malloc) {
261  size_t total = 0;
262  AllocatorIter iter[1];
264  allocator_iter_next(iter))
265  {
266  total += iter->request_size;
267  }
268  return total;
269  }
270  if (dir == ALLOC_DIR_TOP) {
271  return (alloc->size - alloc->top);
272  }
273  if (dir == ALLOC_DIR_BOT) {
274  return (alloc->bottom - 0);
275  }
276  if (dir == ALLOC_DIR_BOTH) {
277  return (alloc->size - alloc->top + alloc->bottom - 0);
278  }
279  /* unknown */
280  return 0;
281 }
282 
283 void
285 {
286  message(1, "--------------- Allocator: %-17s %12s-----------------\n",
287  alloc->name,
288  alloc->use_malloc?"(libc managed)":"(self managed)"
289  );
290  message(1, " Total: %010td kbytes\n", alloc->size/1024);
291  message(1, " Free: %010td Used: %010td Top: %010td Bottom: %010td \n",
296  );
297  AllocatorIter iter[1];
298  message(1, " %-20s | %c | %-12s %-12s | %s\n", "Name", 'd', "Requested", "Allocated", "Annotation");
299  message(1, "-------------------------------------------------------\n");
300  for(allocator_iter_start(iter, alloc);
301  !allocator_iter_ended(iter);
302  allocator_iter_next(iter))
303  {
304  message(1, " %-20s | %c | %012td %012td | %s\n",
305  iter->name,
306  "T?B"[iter->dir + 1],
307  iter->request_size/1024, iter->size/1024, iter->annotation);
308  }
309 }
310 
311 void *
312 allocator_realloc_int(Allocator * alloc, void * ptr, const size_t new_size, const char * fmt, ...)
313 {
314  va_list va;
315  va_start(va, fmt);
316 
317  char * cptr = (char *) ptr;
318  struct BlockHeader * header = (struct BlockHeader*) (cptr - ALIGNMENT);
319  struct BlockHeader tmp = * header;
320 
321  if (!is_header(header)) {
322  allocator_print(header->alloc);
323  endrun(1, "Not an allocated address: Header = %08p ptr = %08p\n", header, cptr);
324  }
325 
326  if(alloc->use_malloc) {
327  struct BlockHeader * header2 = (struct BlockHeader *) realloc(header, new_size + ALIGNMENT);
328  header2->ptr = (char*) header2 + ALIGNMENT;
329  header2->request_size = new_size;
330  /* update record */
331  vsprintf(header2->annotation, fmt, va);
332  va_end(va);
333  memcpy(header2->self, header2, sizeof(header2[0]));
334  return header2->ptr;
335  }
336 
337  if(0 != allocator_dealloc(alloc, ptr)) {
338  allocator_print(header->alloc);
339  endrun(1, "Mismatched Free: %s : %s\n", header->name, header->annotation);
340  }
341 
342  /*If we are shrinking memory, move the existing data block up and then write a new header.*/
343  if(tmp.dir == ALLOC_DIR_TOP && new_size < tmp.request_size) {
344  /*Offset for new memory, after header*/
345  size_t size = ((new_size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
346  memmove(alloc->base + alloc->top - size, tmp.ptr, new_size);
347  }
348  void * newptr = allocator_alloc_va(alloc, tmp.name, new_size, tmp.dir, fmt, va);
349  /*If we are extending memory, move the existing data block down after writing a new header below it*/
350  if(tmp.dir == ALLOC_DIR_TOP && new_size > tmp.request_size) {
351  memmove(newptr, tmp.ptr, tmp.size);
352  }
353  va_end(va);
354  return newptr;
355 }
356 
357 void
359 {
360  char * cptr = (char *) ptr;
361  struct BlockHeader * header = (struct BlockHeader*) (cptr - ALIGNMENT);
362 
363  if (!is_header(header)) {
364  allocator_print(header->alloc);
365  endrun(1, "Not an allocated address: Header = %08p ptr = %08p\n", header, cptr);
366  }
367 
368  int rt = allocator_dealloc(header->alloc, ptr);
369  if (rt != 0) {
370  allocator_print(header->alloc);
371  endrun(1, "Mismatched Free: %s : %s\n", header->name, header->annotation);
372  }
373 }
374 
375 int
377 {
378  char * cptr = (char *) ptr;
379  struct BlockHeader * header = (struct BlockHeader*) (cptr - ALIGNMENT);
380 
381  if (!is_header(header)) {
382  return ALLOC_ENOTALLOC;
383  }
384 
385  /* ->self is always the header in the allocator; header maybe a duplicate in use_malloc */
386  ptr = header->self;
387  if(header->dir == ALLOC_DIR_BOT) {
388  if(ptr != alloc->bottom - header->size + alloc->base) {
389  return ALLOC_EMISMATCH;
390  }
391  alloc->bottom -= header->size;
392  } else if(header->dir == ALLOC_DIR_TOP) {
393  if(ptr != alloc->top + alloc->base) {
394  return ALLOC_EMISMATCH;
395  }
396  alloc->top += header->size;
397  } else {
398  return ALLOC_ENOTALLOC;
399  }
400 
401  if(alloc->use_malloc) {
402  free(header);
403  }
404 
405  /* remove the link to the memory. */
406  header = (struct BlockHeader *) ptr; /* modify the true header in the allocator */
407  header->ptr = NULL;
408  header->self = NULL;
409  header->alloc = NULL;
410  alloc->refcount --;
411 
412  return 0;
413 }
const char * name
Definition: densitykernel.c:93
void message(int where, const char *fmt,...)
Definition: endrun.c:175
void endrun(int where, const char *fmt,...)
Definition: endrun.c:147
static int is_header(struct BlockHeader *header)
Definition: memory.c:203
void * allocator_alloc(Allocator *alloc, const char *name, const size_t request_size, const int dir, const char *fmt,...)
Definition: memory.c:166
int allocator_iter_next(AllocatorIter *iter)
Definition: memory.c:209
int allocator_init(Allocator *alloc, const char *name, const size_t request_size, const int zero, Allocator *parent)
Definition: memory.c:24
void allocator_free(void *ptr)
Definition: memory.c:358
#define ALIGNMENT
Definition: memory.c:9
int allocator_malloc_init(Allocator *alloc, const char *name, const size_t request_size, const int zero, Allocator *parent)
Definition: memory.c:54
int allocator_reset(Allocator *alloc, int zero)
Definition: memory.c:85
size_t allocator_get_free_size(Allocator *alloc)
Definition: memory.c:246
static void * allocator_alloc_va(Allocator *alloc, const char *name, const size_t request_size, const int dir, const char *fmt, va_list va)
Definition: memory.c:106
#define MAGIC
Definition: memory.c:8
int allocator_dealloc(Allocator *alloc, void *ptr)
Definition: memory.c:376
void * allocator_realloc_int(Allocator *alloc, void *ptr, const size_t new_size, const char *fmt,...)
Definition: memory.c:312
void allocator_print(Allocator *alloc)
Definition: memory.c:284
int allocator_iter_start(AllocatorIter *iter, Allocator *alloc)
Definition: memory.c:190
int allocator_destroy(Allocator *alloc)
Definition: memory.c:176
size_t allocator_get_used_size(Allocator *alloc, int dir)
Definition: memory.c:256
int allocator_iter_ended(AllocatorIter *iter)
Definition: memory.c:240
#define ALLOC_ENOTALLOC
Definition: memory.h:8
#define ALLOC_DIR_TOP
Definition: memory.h:12
#define ALLOC_EMISMATCH
Definition: memory.h:9
#define ALLOC_ENOMEMORY
Definition: memory.h:10
#define ALLOC_DIR_BOT
Definition: memory.h:13
#define ALLOC_DIR_BOTH
Definition: memory.h:14
size_t _bottom
Definition: memory.h:34
char * ptr
Definition: memory.h:44
Allocator * alloc
Definition: memory.h:33
char * name
Definition: memory.h:41
int _ended
Definition: memory.h:36
size_t _top
Definition: memory.h:35
size_t size
Definition: memory.h:39
char * annotation
Definition: memory.h:43
size_t request_size
Definition: memory.h:40
char name[12]
Definition: memory.h:17
Allocator * parent
Definition: memory.h:18
size_t top
Definition: memory.h:25
int refcount
Definition: memory.h:27
int use_malloc
Definition: memory.h:28
size_t bottom
Definition: memory.h:24
char * rawbase
Definition: memory.h:20
char * base
Definition: memory.h:21
size_t size
Definition: memory.h:22
char annotation[]
Definition: memory.c:20
char * self
Definition: memory.c:15
size_t request_size
Definition: memory.c:17
char * ptr
Definition: memory.c:14
size_t size
Definition: memory.c:16
char magic[8]
Definition: memory.c:12
char name[127]
Definition: memory.c:18
int dir
Definition: memory.c:19
Allocator * alloc
Definition: memory.c:13