00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 # include <config.h>
00030 #endif
00031
00032
00033
00034
00035
00036 #include "memory_p.h"
00037 #include <gwenhywfar/gwenhywfarapi.h>
00038 #include <gwenhywfar/types.h>
00039 #include <gwenhywfar/stringlist.h>
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <string.h>
00043 #ifdef HAVE_STRINGS_H
00044 # include <strings.h>
00045 #endif
00046 #include <assert.h>
00047
00048 #ifdef HAVE_UNISTD_H
00049 # include <unistd.h>
00050 #endif
00051
00052
00053 static GWEN_MEMORY_TABLE *gwen_memory__first_table=0;
00054 static int gwen_memory__debug=0;
00055 static int gwen_memory__nofree=0;
00056 static int gwen_memory__verbous=0;
00057 static size_t gwen_memory__allocated_bytes=0;
00058 static size_t gwen_memory__allocated_calls=0;
00059 static size_t gwen_memory__allocated_reused=0;
00060
00061 #if ENABLE_MY_SMALL_BLOCK_ALLOC
00062 static size_t gwen_memory__released_since_collect=0;
00063 #endif
00064
00065
00066
00067 int GWEN_Memory_ModuleInit(){
00068 const char *s;
00069
00070 s=getenv(GWEN_MEMORY_ENV_DEBUG);
00071 if (s) {
00072 fprintf(stderr, "Memory debugging is enabled\n");
00073 gwen_memory__debug=1;
00074 gwen_memory__nofree=(getenv(GWEN_MEMORY_ENV_NO_FREE)!=0);
00075 gwen_memory__verbous=(getenv(GWEN_MEMORY_ENV_VERBOUS)!=0);
00076 }
00077 return 0;
00078 }
00079
00080
00081
00082 int GWEN_Memory_ModuleFini(){
00083 GWEN_MEMORY_TABLE *mt;
00084
00085 mt=gwen_memory__first_table;
00086 while(mt) {
00087 GWEN_MEMORY_TABLE *next;
00088
00089 next=mt->next;
00090 GWEN_Memory_Table_free(mt);
00091 mt=next;
00092 }
00093
00094 if (gwen_memory__verbous) {
00095 size_t avg=0;
00096 size_t bytes;
00097 const char *suffix;
00098
00099 if (gwen_memory__allocated_calls)
00100 avg=gwen_memory__allocated_bytes/gwen_memory__allocated_calls;
00101
00102 if (gwen_memory__allocated_bytes>(1024*1024)) {
00103 bytes=gwen_memory__allocated_bytes/(1024*1024);
00104 suffix="mb";
00105 }
00106 else if (gwen_memory__allocated_bytes>1024) {
00107 bytes=gwen_memory__allocated_bytes/1024;
00108 suffix="kb";
00109 }
00110 else {
00111 bytes=gwen_memory__allocated_bytes;
00112 suffix="bytes";
00113 }
00114
00115 fprintf(stderr,
00116 "GWEN info: %zu %s allocated in %zu calls "
00117 "(%zu times reused, average %zu bytes)\n",
00118 bytes, suffix,
00119 gwen_memory__allocated_calls,
00120 gwen_memory__allocated_reused,
00121 avg);
00122 }
00123
00124 return 0;
00125 }
00126
00127
00128
00129 void GWEN_Memory_Report(){
00130 return;
00131 }
00132
00133
00134
00135
00136
00137 GWEN_MEMORY_TABLE *GWEN_Memory_Table_new() {
00138 GWEN_MEMORY_TABLE *mt;
00139 unsigned char *p;
00140 unsigned short dsize;
00141
00142 if (gwen_memory__verbous)
00143 fprintf(stderr, "GWEN info: allocating memory table\n");
00144 mt=(GWEN_MEMORY_TABLE*)malloc(sizeof(GWEN_MEMORY_TABLE));
00145 assert(mt);
00146 memset(mt, 0, sizeof(GWEN_MEMORY_TABLE));
00147 dsize=GWEN_MEMORY_MAXBLOCK;
00148 p=mt->data;
00149 GWEN_MEMORY_WRITESIZE(p, dsize);
00150
00151 return mt;
00152 }
00153
00154
00155
00156 void GWEN_Memory_Table_free(GWEN_MEMORY_TABLE *mt) {
00157 if (mt) {
00158 if (gwen_memory__debug) {
00159 unsigned char *p;
00160 unsigned char *end;
00161
00162 p=mt->data;
00163 end=p+GWEN_MEMORY_TABLE_LEN;
00164 while(p<end) {
00165 unsigned short bsize;
00166 unsigned short rsize;
00167
00168 bsize=GWEN_MEMORY_READSIZE(p);
00169 rsize=bsize & GWEN_MEMORY_MASK_LEN;
00170 if (bsize & GWEN_MEMORY_MASK_MALLOCED) {
00171 fprintf(stderr,
00172 "GWEN warning: Block %p still allocated (%d bytes)\n",
00173 GWEN_MEMORY_GETDATA(p),
00174 rsize);
00175 }
00176 p+=rsize+GWEN_MEMORY_SIZELEN;
00177 }
00178 }
00179 free(mt);
00180 }
00181 }
00182
00183
00184
00185 void GWEN_Memory_Table_Append(GWEN_MEMORY_TABLE *head, GWEN_MEMORY_TABLE *mt){
00186 GWEN_MEMORY_TABLE *last;
00187
00188 assert(head);
00189 assert(mt);
00190
00191 last=head;
00192 while(last->next)
00193 last=last->next;
00194 last->next=mt;
00195 }
00196
00197
00198
00199 void GWEN_Memory_Table_Insert(GWEN_MEMORY_TABLE *mt){
00200 mt->next=gwen_memory__first_table;
00201 gwen_memory__first_table=mt;
00202 }
00203
00204
00205
00206 unsigned char *GWEN_Memory_Table__FindFreeBlock(GWEN_MEMORY_TABLE *mt,
00207 unsigned short dsize) {
00208 unsigned char *end;
00209 unsigned char *p;
00210
00211 end=mt->data+GWEN_MEMORY_TABLE_LEN;
00212 p=mt->data;
00213 while(p<end) {
00214 unsigned short bsize;
00215 unsigned short rsize;
00216
00217 bsize=GWEN_MEMORY_READSIZE(p);
00218 rsize=bsize & GWEN_MEMORY_MASK_LEN;
00219
00220
00221
00222
00223 if (rsize && !(bsize & GWEN_MEMORY_MASK_INUSE)) {
00224
00225 if (rsize==dsize ||
00226 rsize>=(dsize+GWEN_MEMORY_SIZELEN+GWEN_MEMORY_MINREMAIN)) {
00227 return p;
00228 }
00229 }
00230 p+=rsize+GWEN_MEMORY_SIZELEN;
00231 }
00232
00233 return 0;
00234 }
00235
00236
00237
00238 void GWEN_Memory_Table__CollectAt(GWEN_MEMORY_TABLE *mt,
00239 unsigned char *p) {
00240 unsigned char *end;
00241 unsigned short nsize=0;
00242 unsigned char *np;
00243 int cnt=0;
00244
00245 np=p;
00246 end=mt->data+GWEN_MEMORY_TABLE_LEN;
00247
00248 while(np<end) {
00249 unsigned short bsize;
00250 unsigned short rsize;
00251
00252 bsize=GWEN_MEMORY_READSIZE(np);
00253 rsize=bsize & GWEN_MEMORY_MASK_LEN;
00254 if (rsize && !(bsize & GWEN_MEMORY_MASK_INUSE)) {
00255 nsize+=rsize;
00256 if (cnt)
00257 nsize+=GWEN_MEMORY_SIZELEN;
00258 cnt++;
00259 }
00260 else
00261 break;
00262
00263 np+=rsize+GWEN_MEMORY_SIZELEN;
00264 }
00265
00266 if (cnt>1) {
00267 fprintf(stderr, "GWEN info: collected %u bytes\n", nsize);
00268 GWEN_MEMORY_WRITESIZE(p, nsize);
00269 }
00270
00271
00272 }
00273
00274
00275
00276 void GWEN_Memory_Table__Collect(GWEN_MEMORY_TABLE *mt) {
00277 unsigned char *p;
00278 unsigned char *end;
00279
00280 end=mt->data+GWEN_MEMORY_TABLE_LEN;
00281 p=mt->data;
00282 while(p<end) {
00283 unsigned short bsize;
00284 unsigned short rsize;
00285
00286 GWEN_Memory_Table__CollectAt(mt, p);
00287 bsize=GWEN_MEMORY_READSIZE(p);
00288 rsize=bsize & GWEN_MEMORY_MASK_LEN;
00289 p+=rsize+GWEN_MEMORY_SIZELEN;
00290 }
00291 }
00292
00293
00294
00295 void GWEN_Memory_Table__Dump(GWEN_MEMORY_TABLE *mt) {
00296 unsigned char *p;
00297 unsigned char *end;
00298
00299 p=mt->data;
00300 end=p+GWEN_MEMORY_TABLE_LEN;
00301 while(p<end) {
00302 unsigned short bsize;
00303 unsigned short rsize;
00304
00305 bsize=GWEN_MEMORY_READSIZE(p);
00306 rsize=bsize & GWEN_MEMORY_MASK_LEN;
00307 fprintf(stderr,
00308 "GWEN debug: at %5zu: found block with %5u bytes [%p] (%s)\n",
00309 p-mt->data,
00310 rsize,
00311 p,
00312 (bsize & GWEN_MEMORY_MASK_INUSE)?"used":"free");
00313 p+=rsize+GWEN_MEMORY_SIZELEN;
00314 }
00315 }
00316
00317
00318
00319 unsigned char *GWEN_Memory__FindFreeBlock(unsigned short dsize) {
00320 GWEN_MEMORY_TABLE *mt;
00321 unsigned char *p=0;
00322
00323 if (dsize>GWEN_MEMORY_MAXBLOCK) {
00324 fprintf(stderr, "GWEN error: Memory block too big (%d>%d)\n",
00325 dsize, GWEN_MEMORY_MAXBLOCK);
00326 abort();
00327 }
00328 if (gwen_memory__first_table==0)
00329 gwen_memory__first_table=GWEN_Memory_Table_new();
00330
00331 mt=gwen_memory__first_table;
00332 assert(mt);
00333
00334 while(mt) {
00335 p=GWEN_Memory_Table__FindFreeBlock(mt, dsize);
00336 if (p)
00337 return p;
00338 mt=mt->next;
00339 }
00340
00341 mt=GWEN_Memory_Table_new();
00342
00343 GWEN_Memory_Table_Insert(mt);
00344 p=GWEN_Memory_Table__FindFreeBlock(mt, dsize);
00345 assert(p);
00346
00347 return p;
00348 }
00349
00350
00351
00352 void *GWEN_Memory__Malloc(unsigned short dsize) {
00353 unsigned char *p;
00354 unsigned short bsize;
00355 unsigned short rsize;
00356
00357 p=GWEN_Memory__FindFreeBlock(dsize);
00358 assert(p);
00359
00360 bsize=GWEN_MEMORY_READSIZE(p);
00361 rsize=bsize & GWEN_MEMORY_MASK_LEN;
00362
00363 if (rsize>dsize) {
00364 unsigned char *np;
00365 unsigned short nsize;
00366
00367
00368 nsize=rsize-dsize-GWEN_MEMORY_SIZELEN;
00369 np=p+GWEN_MEMORY_SIZELEN+dsize;
00370
00371
00372
00373 GWEN_MEMORY_WRITESIZE(np, (nsize & GWEN_MEMORY_MASK_LEN));
00374 }
00375 else
00376 gwen_memory__allocated_reused++;
00377
00378 GWEN_MEMORY_WRITESIZE(p, (dsize |
00379 GWEN_MEMORY_MASK_INUSE |
00380 GWEN_MEMORY_MASK_MALLOCED));
00381
00382
00383 return (void*)GWEN_MEMORY_GETDATA(p);
00384 }
00385
00386
00387
00388 void *GWEN_Memory_malloc(size_t wsize) {
00389 #if ENABLE_MY_SMALL_BLOCK_ALLOC
00390 void *p;
00391 size_t dsize;
00392 #endif
00393
00394 if (wsize==0) {
00395 fprintf(stderr,
00396 "GWEN error: allocating 0 bytes, maybe a program error\n");
00397 abort();
00398 }
00399
00400 #if ENABLE_MY_SMALL_BLOCK_ALLOC
00401 dsize=(wsize+GWEN_MEMORY_GRANULARITY-1) & ~(GWEN_MEMORY_GRANULARITY-1);
00402
00403 if (dsize<GWEN_MEMORY_MAXBLOCK) {
00404
00405
00406
00407
00408 p=GWEN_Memory__Malloc(dsize & GWEN_MEMORY_MASK_LEN);
00409 }
00410 else {
00411 unsigned char *pc;
00412
00413
00414 if (gwen_memory__verbous)
00415 fprintf(stderr, "GWEN info: Allocating %u bytes externally\n",
00416 dsize);
00417 pc=(unsigned char*)malloc(dsize+GWEN_MEMORY_SIZELEN);
00418 assert(pc);
00419 GWEN_MEMORY_WRITESIZE(pc, GWEN_MEMORY_EXTERNAL);
00420 p=GWEN_MEMORY_GETDATA(pc);
00421 }
00422
00423 gwen_memory__allocated_bytes+=dsize;
00424 gwen_memory__allocated_calls++;
00425
00426 return p;
00427 #else
00428 return malloc(wsize);
00429 #endif
00430 }
00431
00432
00433
00434 void *GWEN_Memory_realloc(void *oldp, size_t nsize) {
00435 #if ENABLE_MY_SMALL_BLOCK_ALLOC
00436 void *p;
00437 unsigned char *pc;
00438 unsigned short dsize;
00439 unsigned short rsize;
00440 #endif
00441
00442 assert(oldp);
00443 assert(nsize);
00444
00445 #if ENABLE_MY_SMALL_BLOCK_ALLOC
00446 pc=GWEN_MEMORY_GETSTART(oldp);
00447 dsize=GWEN_MEMORY_READSIZE(pc);
00448 rsize=dsize & GWEN_MEMORY_MASK_LEN;
00449
00450 if (!(dsize & GWEN_MEMORY_MASK_MALLOCED)) {
00451 fprintf(stderr, "GWEN error: Block %p already free'd\n", oldp);
00452 abort();
00453 }
00454
00455 if (!(dsize & GWEN_MEMORY_MASK_INUSE)) {
00456 fprintf(stderr, "GWEN error: Block %p not in use\n", oldp);
00457 abort();
00458 }
00459
00460 p=GWEN_Memory_malloc(nsize);
00461 memmove(p, oldp, rsize);
00462 GWEN_Memory_dealloc(oldp);
00463 return p;
00464 #else
00465 return realloc(oldp, nsize);
00466 #endif
00467 }
00468
00469
00470
00471 void GWEN_Memory_dealloc(void *p) {
00472 #if ENABLE_MY_SMALL_BLOCK_ALLOC
00473 if (p) {
00474 unsigned char *pc;
00475 unsigned short dsize;
00476
00477 pc=GWEN_MEMORY_GETSTART(p);
00478 dsize=GWEN_MEMORY_READSIZE(pc);
00479
00480 if (!(dsize & GWEN_MEMORY_MASK_MALLOCED)) {
00481 fprintf(stderr, "GWEN error: Block %p already free'd\n", p);
00482 abort();
00483 }
00484
00485 if (!(dsize & GWEN_MEMORY_MASK_INUSE)) {
00486 fprintf(stderr, "GWEN error: Block %p not in use\n", p);
00487 abort();
00488 }
00489
00490 if (gwen_memory__nofree==0) {
00491 GWEN_MEMORY_WRITESIZE(pc,
00492 (dsize &
00493 ~GWEN_MEMORY_MASK_MALLOCED &
00494 ~GWEN_MEMORY_MASK_INUSE));
00495 }
00496 else {
00497 GWEN_MEMORY_WRITESIZE(pc,
00498 (dsize &
00499 ~GWEN_MEMORY_MASK_MALLOCED));
00500 }
00501
00502 if (dsize==GWEN_MEMORY_EXTERNAL) {
00503
00504
00505
00506 if (gwen_memory__nofree==0)
00507 free((void*)pc);
00508 }
00509 else {
00510
00511
00512
00513
00514 if (gwen_memory__released_since_collect>GWEN_MEMORY_COLLECT_AFTER){
00515 fprintf(stderr, "GWEN info: collecting free blocks\n");
00516 GWEN_Memory_Collect();
00517 gwen_memory__released_since_collect=0;
00518 }
00519 }
00520 }
00521 #else
00522 if (gwen_memory__nofree==0)
00523 free(p);
00524 #endif
00525 }
00526
00527
00528
00529 char *GWEN_Memory_strdup(const char *s) {
00530 #if ENABLE_MY_SMALL_BLOCK_ALLOC
00531 unsigned int dsize;
00532 char *p;
00533 #endif
00534
00535 assert(s);
00536 #if ENABLE_MY_SMALL_BLOCK_ALLOC
00537 dsize=strlen(s);
00538
00539 p=(char*)GWEN_Memory_malloc(dsize+1);
00540 assert(p);
00541 memmove(p, s, dsize+1);
00542 return p;
00543 #else
00544 return strdup(s);
00545 #endif
00546 }
00547
00548
00549
00550 void GWEN_Memory_Dump() {
00551 GWEN_MEMORY_TABLE *mt;
00552
00553 mt=gwen_memory__first_table;
00554 while(mt) {
00555 GWEN_Memory_Table__Dump(mt);
00556 mt=mt->next;
00557 }
00558 }
00559
00560
00561
00562 void GWEN_Memory_Collect() {
00563 GWEN_MEMORY_TABLE *mt;
00564
00565 mt=gwen_memory__first_table;
00566 while(mt) {
00567 GWEN_Memory_Table__Collect(mt);
00568 mt=mt->next;
00569 }
00570 }
00571
00572
00573