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