memory.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  $RCSfile$
00003  -------------------
00004  cvs         : $Id$
00005  begin       : Sat Jun 28 2003
00006  copyright   : (C) 2003 by Martin Preuss
00007  email       : martin@libchipcard.de
00008 
00009  ***************************************************************************
00010  *                                                                         *
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU Lesser General Public            *
00013  *   License as published by the Free Software Foundation; either          *
00014  *   version 2.1 of the License, or (at your option) any later version.    *
00015  *                                                                         *
00016  *   This library is distributed in the hope that it will be useful,       *
00017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00019  *   Lesser General Public License for more details.                       *
00020  *                                                                         *
00021  *   You should have received a copy of the GNU Lesser General Public      *
00022  *   License along with this library; if not, write to the Free Software   *
00023  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
00024  *   MA  02111-1307  USA                                                   *
00025  *                                                                         *
00026  ***************************************************************************/
00027 
00028 #ifdef HAVE_CONFIG_H
00029 # include <config.h>
00030 #endif
00031 
00032 /*#define ENABLE_MY_SMALL_BLOCK_ALLOC*/
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 #ifdef 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     /*fprintf(stderr, "GWEN debug: at %u: found block with %u bytes (%s)\n",
00220             p-mt->data,
00221             rsize,
00222             (bsize & GWEN_MEMORY_MASK_INUSE)?"used":"free");*/
00223     if (rsize && !(bsize & GWEN_MEMORY_MASK_INUSE)) {
00224       /* unused block */
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   //GWEN_Memory_Table_Append(gwen_memory__first_table, mt);
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     /* write header for next block */
00368     nsize=rsize-dsize-GWEN_MEMORY_SIZELEN;
00369     np=p+GWEN_MEMORY_SIZELEN+dsize;
00370     /*fprintf(stderr,
00371             "Splitting block from %u to %u/%u (relpos %u)\n",
00372             rsize, dsize, nsize, np-p); */
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   /* fprintf(stderr, "GWEN debug: allocated block internally (%p).\n", p); */
00382 
00383   return (void*)GWEN_MEMORY_GETDATA(p);
00384 }
00385 
00386 
00387 
00388 void *GWEN_Memory_malloc(size_t wsize) {
00389 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
00390   void *p;
00391   size_t dsize;
00392 #endif
00393 
00394   if (GWEN_UNLIKELY(wsize==0)) {
00395     fprintf(stderr,
00396             "GWEN error: allocating 0 bytes, maybe a program error\n");
00397     abort();
00398   }
00399 
00400 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
00401   dsize=(wsize+GWEN_MEMORY_GRANULARITY-1) & ~(GWEN_MEMORY_GRANULARITY-1);
00402 
00403   if (dsize<GWEN_MEMORY_MAXBLOCK) {
00404     /* allocate a small block */
00405     /*if (gwen_memory__verbous)
00406       fprintf(stderr, "GWEN info: Allocating %u bytes internally\n",
00407               dsize);*/
00408     p=GWEN_Memory__Malloc(dsize & GWEN_MEMORY_MASK_LEN);
00409   }
00410   else {
00411     unsigned char *pc;
00412 
00413     /* allocate big block via system */
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   /*fprintf(stderr, "GWEN debug: allocated block (%p).\n", p);*/
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 #ifdef 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 #ifdef 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 #ifdef 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       /*fprintf(stderr,
00504               "GWEN debug: deallocating block at %p externally\n", p); */
00505 
00506       if (gwen_memory__nofree==0)
00507         free((void*)pc);
00508     }
00509     else {
00510       /*fprintf(stderr,
00511               "GWEN debug: deallocating %u bytes at %p internally\n",
00512               (dsize & GWEN_MEMORY_MASK_LEN), p); */
00513       //gwen_memory__released_since_collect+=dsize;
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_LIKELY(gwen_memory__nofree==0))
00523     free(p);
00524 #endif
00525 }
00526 
00527 
00528 
00529 char *GWEN_Memory_strdup(const char *s) {
00530 #ifdef ENABLE_MY_SMALL_BLOCK_ALLOC
00531   unsigned int dsize;
00532   char *p;
00533 #endif
00534 
00535   assert(s);
00536 #ifdef 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 

Generated on Thu Aug 20 13:54:39 2009 for gwenhywfar by  doxygen 1.5.9