gwenhywfar  4.99.15beta
memory.c
Go to the documentation of this file.
1 /***************************************************************************
2  begin : Sat Jun 28 2003
3  copyright : (C) 2003 by Martin Preuss
4  email : martin@libchipcard.de
5 
6  ***************************************************************************
7  * *
8  * This library is free software; you can redistribute it and/or *
9  * modify it under the terms of the GNU Lesser General Public *
10  * License as published by the Free Software Foundation; either *
11  * version 2.1 of the License, or (at your option) any later version. *
12  * *
13  * This library is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16  * Lesser General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU Lesser General Public *
19  * License along with this library; if not, write to the Free Software *
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21  * MA 02111-1307 USA *
22  * *
23  ***************************************************************************/
24 
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 
29 /*#define ENABLE_MY_SMALL_BLOCK_ALLOC*/
30 
31 
32 
33 #include "memory_p.h"
34 #include <gwenhywfar/gwenhywfarapi.h>
35 #include <gwenhywfar/types.h>
36 #include <gwenhywfar/stringlist.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #ifdef HAVE_STRINGS_H
41 # include <strings.h>
42 #endif
43 #include <assert.h>
44 
45 #ifdef HAVE_UNISTD_H
46 # include <unistd.h>
47 #endif
48 
49 
50 static GWEN_MEMORY_TABLE *gwen_memory__first_table=0;
51 static int gwen_memory__debug=0;
52 static int gwen_memory__nofree=0;
53 static int gwen_memory__verbous=0;
57 
58 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
59 static size_t gwen_memory__released_since_collect=0;
60 #endif
61 
62 
63 
65 {
66  const char *s;
67 
68  s=getenv(GWEN_MEMORY_ENV_DEBUG);
69  if (s) {
70  fprintf(stderr, "Memory debugging is enabled\n");
72  gwen_memory__nofree=(getenv(GWEN_MEMORY_ENV_NO_FREE)!=0);
73  gwen_memory__verbous=(getenv(GWEN_MEMORY_ENV_VERBOUS)!=0);
74  }
75  return 0;
76 }
77 
78 
79 
81 {
82  GWEN_MEMORY_TABLE *mt;
83 
85  while (mt) {
86  GWEN_MEMORY_TABLE *next;
87 
88  next=mt->next;
90  mt=next;
91  }
92 
94  size_t avg=0;
95  size_t bytes;
96  const char *suffix;
97 
100 
101  if (gwen_memory__allocated_bytes>(1024*1024)) {
102  bytes=gwen_memory__allocated_bytes/(1024*1024);
103  suffix="mb";
104  }
105  else if (gwen_memory__allocated_bytes>1024) {
106  bytes=gwen_memory__allocated_bytes/1024;
107  suffix="kb";
108  }
109  else {
111  suffix="bytes";
112  }
113 
114  fprintf(stderr,
115  "GWEN info: %zu %s allocated in %zu calls "
116  "(%zu times reused, average %zu bytes)\n",
117  bytes, suffix,
120  avg);
121  }
122 
123  return 0;
124 }
125 
126 
127 
129 {
130  return;
131 }
132 
133 
134 
135 
136 
137 GWEN_MEMORY_TABLE *GWEN_Memory_Table_new(void)
138 {
139  GWEN_MEMORY_TABLE *mt;
140  unsigned char *p;
141  unsigned short dsize;
142 
144  fprintf(stderr, "GWEN info: allocating memory table\n");
145  mt=(GWEN_MEMORY_TABLE *)malloc(sizeof(GWEN_MEMORY_TABLE));
146  assert(mt);
147  memset(mt, 0, sizeof(GWEN_MEMORY_TABLE));
148  dsize=GWEN_MEMORY_MAXBLOCK;
149  p=mt->data;
150  GWEN_MEMORY_WRITESIZE(p, dsize);
151 
152  return mt;
153 }
154 
155 
156 
157 void GWEN_Memory_Table_free(GWEN_MEMORY_TABLE *mt)
158 {
159  if (mt) {
160  if (gwen_memory__debug) {
161  unsigned char *p;
162  unsigned char *end;
163 
164  p=mt->data;
165  end=p+GWEN_MEMORY_TABLE_LEN;
166  while (p<end) {
167  unsigned short bsize;
168  unsigned short rsize;
169 
170  bsize=GWEN_MEMORY_READSIZE(p);
171  rsize=bsize & GWEN_MEMORY_MASK_LEN;
172  if (bsize & GWEN_MEMORY_MASK_MALLOCED) {
173  fprintf(stderr,
174  "GWEN warning: Block %p still allocated (%d bytes)\n",
175  GWEN_MEMORY_GETDATA(p),
176  rsize);
177  }
178  p+=rsize+GWEN_MEMORY_SIZELEN;
179  }
180  }
181  free(mt);
182  }
183 }
184 
185 
186 
187 void GWEN_Memory_Table_Append(GWEN_MEMORY_TABLE *head, GWEN_MEMORY_TABLE *mt)
188 {
189  GWEN_MEMORY_TABLE *last;
190 
191  assert(head);
192  assert(mt);
193 
194  last=head;
195  while (last->next)
196  last=last->next;
197  last->next=mt;
198 }
199 
200 
201 
202 void GWEN_Memory_Table_Insert(GWEN_MEMORY_TABLE *mt)
203 {
204  mt->next=gwen_memory__first_table;
206 }
207 
208 
209 
210 unsigned char *GWEN_Memory_Table__FindFreeBlock(GWEN_MEMORY_TABLE *mt,
211  unsigned short dsize)
212 {
213  unsigned char *end;
214  unsigned char *p;
215 
216  end=mt->data+GWEN_MEMORY_TABLE_LEN;
217  p=mt->data;
218  while (p<end) {
219  unsigned short bsize;
220  unsigned short rsize;
221 
222  bsize=GWEN_MEMORY_READSIZE(p);
223  rsize=bsize & GWEN_MEMORY_MASK_LEN;
224  /*fprintf(stderr, "GWEN debug: at %u: found block with %u bytes (%s)\n",
225  p-mt->data,
226  rsize,
227  (bsize & GWEN_MEMORY_MASK_INUSE)?"used":"free");*/
228  if (rsize && !(bsize & GWEN_MEMORY_MASK_INUSE)) {
229  /* unused block */
230  if (rsize==dsize ||
231  rsize>=(dsize+GWEN_MEMORY_SIZELEN+GWEN_MEMORY_MINREMAIN)) {
232  return p;
233  }
234  }
235  p+=rsize+GWEN_MEMORY_SIZELEN;
236  }
237 
238  return 0;
239 }
240 
241 
242 
243 void GWEN_Memory_Table__CollectAt(GWEN_MEMORY_TABLE *mt,
244  unsigned char *p)
245 {
246  unsigned char *end;
247  unsigned short nsize=0;
248  unsigned char *np;
249  int cnt=0;
250 
251  np=p;
252  end=mt->data+GWEN_MEMORY_TABLE_LEN;
253 
254  while (np<end) {
255  unsigned short bsize;
256  unsigned short rsize;
257 
258  bsize=GWEN_MEMORY_READSIZE(np);
259  rsize=bsize & GWEN_MEMORY_MASK_LEN;
260  if (rsize && !(bsize & GWEN_MEMORY_MASK_INUSE)) {
261  nsize+=rsize;
262  if (cnt)
263  nsize+=GWEN_MEMORY_SIZELEN;
264  cnt++;
265  }
266  else
267  break;
268 
269  np+=rsize+GWEN_MEMORY_SIZELEN;
270  }
271 
272  if (cnt>1) {
273  fprintf(stderr, "GWEN info: collected %u bytes\n", nsize);
274  GWEN_MEMORY_WRITESIZE(p, nsize);
275  }
276 
277 
278 }
279 
280 
281 
282 void GWEN_Memory_Table__Collect(GWEN_MEMORY_TABLE *mt)
283 {
284  unsigned char *p;
285  unsigned char *end;
286 
287  end=mt->data+GWEN_MEMORY_TABLE_LEN;
288  p=mt->data;
289  while (p<end) {
290  unsigned short bsize;
291  unsigned short rsize;
292 
294  bsize=GWEN_MEMORY_READSIZE(p);
295  rsize=bsize & GWEN_MEMORY_MASK_LEN;
296  p+=rsize+GWEN_MEMORY_SIZELEN;
297  }
298 }
299 
300 
301 
302 void GWEN_Memory_Table__Dump(GWEN_MEMORY_TABLE *mt)
303 {
304  unsigned char *p;
305  unsigned char *end;
306 
307  p=mt->data;
308  end=p+GWEN_MEMORY_TABLE_LEN;
309  while (p<end) {
310  unsigned short bsize;
311  unsigned short rsize;
312 
313  bsize=GWEN_MEMORY_READSIZE(p);
314  rsize=bsize & GWEN_MEMORY_MASK_LEN;
315  fprintf(stderr,
316  "GWEN debug: at %5zu: found block with %5u bytes [%p] (%s)\n",
317  p-mt->data,
318  rsize,
319  p,
320  (bsize & GWEN_MEMORY_MASK_INUSE)?"used":"free");
321  p+=rsize+GWEN_MEMORY_SIZELEN;
322  }
323 }
324 
325 
326 
327 unsigned char *GWEN_Memory__FindFreeBlock(unsigned short dsize)
328 {
329  GWEN_MEMORY_TABLE *mt;
330  unsigned char *p=0;
331 
332  if (dsize>GWEN_MEMORY_MAXBLOCK) {
333  fprintf(stderr, "GWEN error: Memory block too big (%d>%d)\n",
334  dsize, GWEN_MEMORY_MAXBLOCK);
335  abort();
336  }
339 
341  assert(mt);
342 
343  while (mt) {
345  if (p)
346  return p;
347  mt=mt->next;
348  }
349 
351  //GWEN_Memory_Table_Append(gwen_memory__first_table, mt);
354  assert(p);
355 
356  return p;
357 }
358 
359 
360 
361 void *GWEN_Memory__Malloc(unsigned short dsize)
362 {
363  unsigned char *p;
364  unsigned short bsize;
365  unsigned short rsize;
366 
368  assert(p);
369 
370  bsize=GWEN_MEMORY_READSIZE(p);
371  rsize=bsize & GWEN_MEMORY_MASK_LEN;
372 
373  if (rsize>dsize) {
374  unsigned char *np;
375  unsigned short nsize;
376 
377  /* write header for next block */
378  nsize=rsize-dsize-GWEN_MEMORY_SIZELEN;
379  np=p+GWEN_MEMORY_SIZELEN+dsize;
380  /*fprintf(stderr,
381  "Splitting block from %u to %u/%u (relpos %u)\n",
382  rsize, dsize, nsize, np-p); */
383  GWEN_MEMORY_WRITESIZE(np, (nsize & GWEN_MEMORY_MASK_LEN));
384  }
385  else
387 
388  GWEN_MEMORY_WRITESIZE(p, (dsize |
389  GWEN_MEMORY_MASK_INUSE |
390  GWEN_MEMORY_MASK_MALLOCED));
391  /* fprintf(stderr, "GWEN debug: allocated block internally (%p).\n", p); */
392 
393  return (void *)GWEN_MEMORY_GETDATA(p);
394 }
395 
396 
397 
398 void *GWEN_Memory_malloc(size_t wsize)
399 {
400  void *p;
401 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
402  size_t dsize;
403 #endif
404 
405  if (GWEN_UNLIKELY(wsize==0)) {
406  fprintf(stderr,
407  "GWEN error: allocating 0 bytes, maybe a program error\n");
408  abort();
409  }
410 
411 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
412  dsize=(wsize+GWEN_MEMORY_GRANULARITY-1) & ~(GWEN_MEMORY_GRANULARITY-1);
413 
414  if (dsize<GWEN_MEMORY_MAXBLOCK) {
415  /* allocate a small block */
416  /*if (gwen_memory__verbous)
417  fprintf(stderr, "GWEN info: Allocating %u bytes internally\n",
418  dsize);*/
419  p=GWEN_Memory__Malloc(dsize & GWEN_MEMORY_MASK_LEN);
420  }
421  else {
422  unsigned char *pc;
423 
424  /* allocate big block via system */
426  fprintf(stderr, "GWEN info: Allocating %u bytes externally\n",
427  dsize);
428  pc=(unsigned char *)malloc(dsize+GWEN_MEMORY_SIZELEN);
429  assert(pc);
430  GWEN_MEMORY_WRITESIZE(pc, GWEN_MEMORY_EXTERNAL);
431  p=GWEN_MEMORY_GETDATA(pc);
432  }
433 
436  /*fprintf(stderr, "GWEN debug: allocated block (%p).\n", p);*/
437  return p;
438 #else
439  p=malloc(wsize);
440  assert(p);
441  return p;
442 #endif
443 }
444 
445 
446 
447 void *GWEN_Memory_realloc(void *oldp, size_t nsize)
448 {
449 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
450  void *p;
451  unsigned char *pc;
452  unsigned short dsize;
453  unsigned short rsize;
454 #endif
455 
456  assert(oldp);
457  assert(nsize);
458 
459 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
460  pc=GWEN_MEMORY_GETSTART(oldp);
461  dsize=GWEN_MEMORY_READSIZE(pc);
462  rsize=dsize & GWEN_MEMORY_MASK_LEN;
463 
464  if (!(dsize & GWEN_MEMORY_MASK_MALLOCED)) {
465  fprintf(stderr, "GWEN error: Block %p already free'd\n", oldp);
466  abort();
467  }
468 
469  if (!(dsize & GWEN_MEMORY_MASK_INUSE)) {
470  fprintf(stderr, "GWEN error: Block %p not in use\n", oldp);
471  abort();
472  }
473 
474  p=GWEN_Memory_malloc(nsize);
475  if (rsize>nsize)
476  rsize=nsize;
477  memmove(p, oldp, rsize);
478  GWEN_Memory_dealloc(oldp);
479  return p;
480 #else
481  return realloc(oldp, nsize);
482 #endif
483 }
484 
485 
486 
487 void GWEN_Memory_dealloc(void *p)
488 {
489 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
490  if (p) {
491  unsigned char *pc;
492  unsigned short dsize;
493 
494  pc=GWEN_MEMORY_GETSTART(p);
495  dsize=GWEN_MEMORY_READSIZE(pc);
496 
497  if (!(dsize & GWEN_MEMORY_MASK_MALLOCED)) {
498  fprintf(stderr, "GWEN error: Block %p already free'd\n", p);
499  abort();
500  }
501 
502  if (!(dsize & GWEN_MEMORY_MASK_INUSE)) {
503  fprintf(stderr, "GWEN error: Block %p not in use\n", p);
504  abort();
505  }
506 
507  if (gwen_memory__nofree==0) {
508  GWEN_MEMORY_WRITESIZE(pc,
509  (dsize &
510  ~GWEN_MEMORY_MASK_MALLOCED &
511  ~GWEN_MEMORY_MASK_INUSE));
512  }
513  else {
514  GWEN_MEMORY_WRITESIZE(pc,
515  (dsize &
516  ~GWEN_MEMORY_MASK_MALLOCED));
517  }
518 
519  if (dsize==GWEN_MEMORY_EXTERNAL) {
520  /*fprintf(stderr,
521  "GWEN debug: deallocating block at %p externally\n", p); */
522 
523  if (gwen_memory__nofree==0)
524  free((void *)pc);
525  }
526  else {
527  /*fprintf(stderr,
528  "GWEN debug: deallocating %u bytes at %p internally\n",
529  (dsize & GWEN_MEMORY_MASK_LEN), p); */
530  //gwen_memory__released_since_collect+=dsize;
531  if (gwen_memory__released_since_collect>GWEN_MEMORY_COLLECT_AFTER) {
532  fprintf(stderr, "GWEN info: collecting free blocks\n");
534  gwen_memory__released_since_collect=0;
535  }
536  }
537  }
538 #else
540  free(p);
541 #endif
542 }
543 
544 
545 
546 char *GWEN_Memory_strdup(const char *s)
547 {
548 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
549  unsigned int dsize;
550  char *p;
551 #endif
552 
553  assert(s);
554 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
555  dsize=strlen(s);
556 
557  p=(char *)GWEN_Memory_malloc(dsize+1);
558  assert(p);
559  memmove(p, s, dsize+1);
560  return p;
561 #else
562  return strdup(s);
563 #endif
564 }
565 
566 
567 
569 {
570  GWEN_MEMORY_TABLE *mt;
571 
573  while (mt) {
575  mt=mt->next;
576  }
577 }
578 
579 
580 
582 {
583  GWEN_MEMORY_TABLE *mt;
584 
586  while (mt) {
588  mt=mt->next;
589  }
590 }
591 
592 
593 
void GWEN_Memory_Table__Dump(GWEN_MEMORY_TABLE *mt)
Definition: memory.c:302
void GWEN_Memory_Collect(void)
Definition: memory.c:581
char * GWEN_Memory_strdup(const char *s)
Definition: memory.c:546
unsigned char * GWEN_Memory_Table__FindFreeBlock(GWEN_MEMORY_TABLE *mt, unsigned short dsize)
Definition: memory.c:210
GWEN_MEMORY_TABLE * GWEN_Memory_Table_new(void)
Definition: memory.c:137
void GWEN_Memory_dealloc(void *p)
Definition: memory.c:487
void GWEN_Memory_Report(void)
Definition: memory.c:128
static GWEN_MEMORY_TABLE * gwen_memory__first_table
Definition: memory.c:50
void GWEN_Memory_Dump(void)
Definition: memory.c:568
void GWEN_Memory_Table_Append(GWEN_MEMORY_TABLE *head, GWEN_MEMORY_TABLE *mt)
Definition: memory.c:187
void * GWEN_Memory_malloc(size_t wsize)
Definition: memory.c:398
int GWEN_Memory_ModuleInit(void)
Definition: memory.c:64
static size_t gwen_memory__allocated_reused
Definition: memory.c:56
void GWEN_Memory_Table__Collect(GWEN_MEMORY_TABLE *mt)
Definition: memory.c:282
unsigned char * GWEN_Memory__FindFreeBlock(unsigned short dsize)
Definition: memory.c:327
void GWEN_Memory_Table_free(GWEN_MEMORY_TABLE *mt)
Definition: memory.c:157
void GWEN_Memory_Table__CollectAt(GWEN_MEMORY_TABLE *mt, unsigned char *p)
Definition: memory.c:243
static int gwen_memory__verbous
Definition: memory.c:53
static size_t gwen_memory__allocated_bytes
Definition: memory.c:54
#define GWEN_LIKELY(cond)
void * GWEN_Memory_realloc(void *oldp, size_t nsize)
Definition: memory.c:447
static int gwen_memory__debug
Definition: memory.c:51
static int gwen_memory__nofree
Definition: memory.c:52
#define GWEN_UNLIKELY(cond)
void GWEN_Memory_Table_Insert(GWEN_MEMORY_TABLE *mt)
Definition: memory.c:202
int GWEN_Memory_ModuleFini(void)
Definition: memory.c:80
static size_t gwen_memory__allocated_calls
Definition: memory.c:55
void * GWEN_Memory__Malloc(unsigned short dsize)
Definition: memory.c:361