gwenhywfar 4.0.3

memory.c

Go to the documentation of this file.
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