gwenhywfar  4.3.3
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  const char *s;
66 
67  s=getenv(GWEN_MEMORY_ENV_DEBUG);
68  if (s) {
69  fprintf(stderr, "Memory debugging is enabled\n");
71  gwen_memory__nofree=(getenv(GWEN_MEMORY_ENV_NO_FREE)!=0);
72  gwen_memory__verbous=(getenv(GWEN_MEMORY_ENV_VERBOUS)!=0);
73  }
74  return 0;
75 }
76 
77 
78 
80  GWEN_MEMORY_TABLE *mt;
81 
83  while(mt) {
84  GWEN_MEMORY_TABLE *next;
85 
86  next=mt->next;
88  mt=next;
89  }
90 
92  size_t avg=0;
93  size_t bytes;
94  const char *suffix;
95 
98 
99  if (gwen_memory__allocated_bytes>(1024*1024)) {
100  bytes=gwen_memory__allocated_bytes/(1024*1024);
101  suffix="mb";
102  }
103  else if (gwen_memory__allocated_bytes>1024) {
104  bytes=gwen_memory__allocated_bytes/1024;
105  suffix="kb";
106  }
107  else {
109  suffix="bytes";
110  }
111 
112  fprintf(stderr,
113  "GWEN info: %zu %s allocated in %zu calls "
114  "(%zu times reused, average %zu bytes)\n",
115  bytes, suffix,
118  avg);
119  }
120 
121  return 0;
122 }
123 
124 
125 
127  return;
128 }
129 
130 
131 
132 
133 
134 GWEN_MEMORY_TABLE *GWEN_Memory_Table_new(void) {
135  GWEN_MEMORY_TABLE *mt;
136  unsigned char *p;
137  unsigned short dsize;
138 
140  fprintf(stderr, "GWEN info: allocating memory table\n");
141  mt=(GWEN_MEMORY_TABLE*)malloc(sizeof(GWEN_MEMORY_TABLE));
142  assert(mt);
143  memset(mt, 0, sizeof(GWEN_MEMORY_TABLE));
144  dsize=GWEN_MEMORY_MAXBLOCK;
145  p=mt->data;
146  GWEN_MEMORY_WRITESIZE(p, dsize);
147 
148  return mt;
149 }
150 
151 
152 
153 void GWEN_Memory_Table_free(GWEN_MEMORY_TABLE *mt) {
154  if (mt) {
155  if (gwen_memory__debug) {
156  unsigned char *p;
157  unsigned char *end;
158 
159  p=mt->data;
160  end=p+GWEN_MEMORY_TABLE_LEN;
161  while(p<end) {
162  unsigned short bsize;
163  unsigned short rsize;
164 
165  bsize=GWEN_MEMORY_READSIZE(p);
166  rsize=bsize & GWEN_MEMORY_MASK_LEN;
167  if (bsize & GWEN_MEMORY_MASK_MALLOCED) {
168  fprintf(stderr,
169  "GWEN warning: Block %p still allocated (%d bytes)\n",
170  GWEN_MEMORY_GETDATA(p),
171  rsize);
172  }
173  p+=rsize+GWEN_MEMORY_SIZELEN;
174  }
175  }
176  free(mt);
177  }
178 }
179 
180 
181 
182 void GWEN_Memory_Table_Append(GWEN_MEMORY_TABLE *head, GWEN_MEMORY_TABLE *mt){
183  GWEN_MEMORY_TABLE *last;
184 
185  assert(head);
186  assert(mt);
187 
188  last=head;
189  while(last->next)
190  last=last->next;
191  last->next=mt;
192 }
193 
194 
195 
196 void GWEN_Memory_Table_Insert(GWEN_MEMORY_TABLE *mt){
197  mt->next=gwen_memory__first_table;
199 }
200 
201 
202 
203 unsigned char *GWEN_Memory_Table__FindFreeBlock(GWEN_MEMORY_TABLE *mt,
204  unsigned short dsize) {
205  unsigned char *end;
206  unsigned char *p;
207 
208  end=mt->data+GWEN_MEMORY_TABLE_LEN;
209  p=mt->data;
210  while(p<end) {
211  unsigned short bsize;
212  unsigned short rsize;
213 
214  bsize=GWEN_MEMORY_READSIZE(p);
215  rsize=bsize & GWEN_MEMORY_MASK_LEN;
216  /*fprintf(stderr, "GWEN debug: at %u: found block with %u bytes (%s)\n",
217  p-mt->data,
218  rsize,
219  (bsize & GWEN_MEMORY_MASK_INUSE)?"used":"free");*/
220  if (rsize && !(bsize & GWEN_MEMORY_MASK_INUSE)) {
221  /* unused block */
222  if (rsize==dsize ||
223  rsize>=(dsize+GWEN_MEMORY_SIZELEN+GWEN_MEMORY_MINREMAIN)) {
224  return p;
225  }
226  }
227  p+=rsize+GWEN_MEMORY_SIZELEN;
228  }
229 
230  return 0;
231 }
232 
233 
234 
235 void GWEN_Memory_Table__CollectAt(GWEN_MEMORY_TABLE *mt,
236  unsigned char *p) {
237  unsigned char *end;
238  unsigned short nsize=0;
239  unsigned char *np;
240  int cnt=0;
241 
242  np=p;
243  end=mt->data+GWEN_MEMORY_TABLE_LEN;
244 
245  while(np<end) {
246  unsigned short bsize;
247  unsigned short rsize;
248 
249  bsize=GWEN_MEMORY_READSIZE(np);
250  rsize=bsize & GWEN_MEMORY_MASK_LEN;
251  if (rsize && !(bsize & GWEN_MEMORY_MASK_INUSE)) {
252  nsize+=rsize;
253  if (cnt)
254  nsize+=GWEN_MEMORY_SIZELEN;
255  cnt++;
256  }
257  else
258  break;
259 
260  np+=rsize+GWEN_MEMORY_SIZELEN;
261  }
262 
263  if (cnt>1) {
264  fprintf(stderr, "GWEN info: collected %u bytes\n", nsize);
265  GWEN_MEMORY_WRITESIZE(p, nsize);
266  }
267 
268 
269 }
270 
271 
272 
273 void GWEN_Memory_Table__Collect(GWEN_MEMORY_TABLE *mt) {
274  unsigned char *p;
275  unsigned char *end;
276 
277  end=mt->data+GWEN_MEMORY_TABLE_LEN;
278  p=mt->data;
279  while(p<end) {
280  unsigned short bsize;
281  unsigned short rsize;
282 
284  bsize=GWEN_MEMORY_READSIZE(p);
285  rsize=bsize & GWEN_MEMORY_MASK_LEN;
286  p+=rsize+GWEN_MEMORY_SIZELEN;
287  }
288 }
289 
290 
291 
292 void GWEN_Memory_Table__Dump(GWEN_MEMORY_TABLE *mt) {
293  unsigned char *p;
294  unsigned char *end;
295 
296  p=mt->data;
297  end=p+GWEN_MEMORY_TABLE_LEN;
298  while(p<end) {
299  unsigned short bsize;
300  unsigned short rsize;
301 
302  bsize=GWEN_MEMORY_READSIZE(p);
303  rsize=bsize & GWEN_MEMORY_MASK_LEN;
304  fprintf(stderr,
305  "GWEN debug: at %5zu: found block with %5u bytes [%p] (%s)\n",
306  p-mt->data,
307  rsize,
308  p,
309  (bsize & GWEN_MEMORY_MASK_INUSE)?"used":"free");
310  p+=rsize+GWEN_MEMORY_SIZELEN;
311  }
312 }
313 
314 
315 
316 unsigned char *GWEN_Memory__FindFreeBlock(unsigned short dsize) {
317  GWEN_MEMORY_TABLE *mt;
318  unsigned char *p=0;
319 
320  if (dsize>GWEN_MEMORY_MAXBLOCK) {
321  fprintf(stderr, "GWEN error: Memory block too big (%d>%d)\n",
322  dsize, GWEN_MEMORY_MAXBLOCK);
323  abort();
324  }
327 
329  assert(mt);
330 
331  while(mt) {
333  if (p)
334  return p;
335  mt=mt->next;
336  }
337 
339  //GWEN_Memory_Table_Append(gwen_memory__first_table, mt);
342  assert(p);
343 
344  return p;
345 }
346 
347 
348 
349 void *GWEN_Memory__Malloc(unsigned short dsize) {
350  unsigned char *p;
351  unsigned short bsize;
352  unsigned short rsize;
353 
355  assert(p);
356 
357  bsize=GWEN_MEMORY_READSIZE(p);
358  rsize=bsize & GWEN_MEMORY_MASK_LEN;
359 
360  if (rsize>dsize) {
361  unsigned char *np;
362  unsigned short nsize;
363 
364  /* write header for next block */
365  nsize=rsize-dsize-GWEN_MEMORY_SIZELEN;
366  np=p+GWEN_MEMORY_SIZELEN+dsize;
367  /*fprintf(stderr,
368  "Splitting block from %u to %u/%u (relpos %u)\n",
369  rsize, dsize, nsize, np-p); */
370  GWEN_MEMORY_WRITESIZE(np, (nsize & GWEN_MEMORY_MASK_LEN));
371  }
372  else
374 
375  GWEN_MEMORY_WRITESIZE(p, (dsize |
376  GWEN_MEMORY_MASK_INUSE |
377  GWEN_MEMORY_MASK_MALLOCED));
378  /* fprintf(stderr, "GWEN debug: allocated block internally (%p).\n", p); */
379 
380  return (void*)GWEN_MEMORY_GETDATA(p);
381 }
382 
383 
384 
385 void *GWEN_Memory_malloc(size_t wsize) {
386 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
387  void *p;
388  size_t dsize;
389 #endif
390 
391  if (GWEN_UNLIKELY(wsize==0)) {
392  fprintf(stderr,
393  "GWEN error: allocating 0 bytes, maybe a program error\n");
394  abort();
395  }
396 
397 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
398  dsize=(wsize+GWEN_MEMORY_GRANULARITY-1) & ~(GWEN_MEMORY_GRANULARITY-1);
399 
400  if (dsize<GWEN_MEMORY_MAXBLOCK) {
401  /* allocate a small block */
402  /*if (gwen_memory__verbous)
403  fprintf(stderr, "GWEN info: Allocating %u bytes internally\n",
404  dsize);*/
405  p=GWEN_Memory__Malloc(dsize & GWEN_MEMORY_MASK_LEN);
406  }
407  else {
408  unsigned char *pc;
409 
410  /* allocate big block via system */
412  fprintf(stderr, "GWEN info: Allocating %u bytes externally\n",
413  dsize);
414  pc=(unsigned char*)malloc(dsize+GWEN_MEMORY_SIZELEN);
415  assert(pc);
416  GWEN_MEMORY_WRITESIZE(pc, GWEN_MEMORY_EXTERNAL);
417  p=GWEN_MEMORY_GETDATA(pc);
418  }
419 
422  /*fprintf(stderr, "GWEN debug: allocated block (%p).\n", p);*/
423  return p;
424 #else
425  return malloc(wsize);
426 #endif
427 }
428 
429 
430 
431 void *GWEN_Memory_realloc(void *oldp, size_t nsize) {
432 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
433  void *p;
434  unsigned char *pc;
435  unsigned short dsize;
436  unsigned short rsize;
437 #endif
438 
439  assert(oldp);
440  assert(nsize);
441 
442 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
443  pc=GWEN_MEMORY_GETSTART(oldp);
444  dsize=GWEN_MEMORY_READSIZE(pc);
445  rsize=dsize & GWEN_MEMORY_MASK_LEN;
446 
447  if (!(dsize & GWEN_MEMORY_MASK_MALLOCED)) {
448  fprintf(stderr, "GWEN error: Block %p already free'd\n", oldp);
449  abort();
450  }
451 
452  if (!(dsize & GWEN_MEMORY_MASK_INUSE)) {
453  fprintf(stderr, "GWEN error: Block %p not in use\n", oldp);
454  abort();
455  }
456 
457  p=GWEN_Memory_malloc(nsize);
458  memmove(p, oldp, rsize);
459  GWEN_Memory_dealloc(oldp);
460  return p;
461 #else
462  return realloc(oldp, nsize);
463 #endif
464 }
465 
466 
467 
468 void GWEN_Memory_dealloc(void *p) {
469 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
470  if (p) {
471  unsigned char *pc;
472  unsigned short dsize;
473 
474  pc=GWEN_MEMORY_GETSTART(p);
475  dsize=GWEN_MEMORY_READSIZE(pc);
476 
477  if (!(dsize & GWEN_MEMORY_MASK_MALLOCED)) {
478  fprintf(stderr, "GWEN error: Block %p already free'd\n", p);
479  abort();
480  }
481 
482  if (!(dsize & GWEN_MEMORY_MASK_INUSE)) {
483  fprintf(stderr, "GWEN error: Block %p not in use\n", p);
484  abort();
485  }
486 
487  if (gwen_memory__nofree==0) {
488  GWEN_MEMORY_WRITESIZE(pc,
489  (dsize &
490  ~GWEN_MEMORY_MASK_MALLOCED &
491  ~GWEN_MEMORY_MASK_INUSE));
492  }
493  else {
494  GWEN_MEMORY_WRITESIZE(pc,
495  (dsize &
496  ~GWEN_MEMORY_MASK_MALLOCED));
497  }
498 
499  if (dsize==GWEN_MEMORY_EXTERNAL) {
500  /*fprintf(stderr,
501  "GWEN debug: deallocating block at %p externally\n", p); */
502 
503  if (gwen_memory__nofree==0)
504  free((void*)pc);
505  }
506  else {
507  /*fprintf(stderr,
508  "GWEN debug: deallocating %u bytes at %p internally\n",
509  (dsize & GWEN_MEMORY_MASK_LEN), p); */
510  //gwen_memory__released_since_collect+=dsize;
511  if (gwen_memory__released_since_collect>GWEN_MEMORY_COLLECT_AFTER){
512  fprintf(stderr, "GWEN info: collecting free blocks\n");
514  gwen_memory__released_since_collect=0;
515  }
516  }
517  }
518 #else
520  free(p);
521 #endif
522 }
523 
524 
525 
526 char *GWEN_Memory_strdup(const char *s) {
527 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
528  unsigned int dsize;
529  char *p;
530 #endif
531 
532  assert(s);
533 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
534  dsize=strlen(s);
535 
536  p=(char*)GWEN_Memory_malloc(dsize+1);
537  assert(p);
538  memmove(p, s, dsize+1);
539  return p;
540 #else
541  return strdup(s);
542 #endif
543 }
544 
545 
546 
547 void GWEN_Memory_Dump(void) {
548  GWEN_MEMORY_TABLE *mt;
549 
551  while(mt) {
553  mt=mt->next;
554  }
555 }
556 
557 
558 
560  GWEN_MEMORY_TABLE *mt;
561 
563  while(mt) {
565  mt=mt->next;
566  }
567 }
568 
569 
570