newspeoplefor developersdocumentationdownloads

nmemory.cc

Go to the documentation of this file.
00001 //------------------------------------------------------------------------------
00011 #include "kernel/ntypes.h"
00012 
00013 #if defined(__NEBULA_MEM_MANAGER__) || defined(DOXYGEN)
00014 
00015 #include "kernel/nmutex.h"
00016 #include "util/nlist.h"
00017 #include "util/nnode.h"
00018 #include "kernel/nkernelserver.h"
00019 
00020 #undef n_malloc
00021 #undef n_calloc
00022 #undef n_free
00023 
00024 struct nChunkHeader
00025 {
00026     nNode nd;           // muss im ersten Element bleiben!
00027     int bnum;           // Block-Anzahl
00028     int bsize;          // Block-Groesse
00029 };
00030 
00031 struct nBlockHeader
00032 {
00033     enum
00034     {
00035         N_SRCNAME_LEN = 16,
00036     };
00037     struct nBlockHeader *next;
00038     int size;
00039     char src_name[N_SRCNAME_LEN];
00040     int  src_line;
00041     int magic;
00042 };
00043 
00044 struct nBlockPostfix
00045 {
00046     int magic;
00047 };
00048 
00049 class nMemManager
00050 {
00051 public:
00052     enum
00053     {
00054         N_MINBLOCK = 4,     
00055         N_MAXBLOCK = 10,    
00056         N_NUMBLOCKSIZES = (1+(N_MAXBLOCK - N_MINBLOCK)),
00057         N_PREFIX_MAGIC_COOKIE  = 0xDEADBEEF,
00058         N_POSTFIX_MAGIC_COOKIE = 0xFEEBDAED,
00059     };
00060 
00061     nMutex mutex;
00062     nList chunks;
00063     nBlockHeader *blocks[N_NUMBLOCKSIZES];
00064     int b_size[N_NUMBLOCKSIZES];
00065     int b_num[N_NUMBLOCKSIZES];
00066 
00068     nMemManager();
00070     ~nMemManager();
00072     nBlockHeader *NewChunk(int, int);
00074     void FreeChunk(nChunkHeader *);
00076     void *Malloc(int, const char *, int);
00078     void *Realloc(void *, int, const char *, int);
00080     void Free(void *);
00081 };
00082 
00083 static nMemManager mem;
00084 
00085 int n_memallocated = 0;
00086 int n_memused      = 0;
00087 int n_memnumalloc  = 0;
00088 
00089 //------------------------------------------------------------------------------
00093 nMemManager::nMemManager()
00094 {
00095     int i;
00096     for (i=0; i<(int)N_NUMBLOCKSIZES; i++)
00097     {
00098         b_size[i] = (1<<(i+N_MINBLOCK));
00099         b_num[i]  = (16*1024) / b_size[i];
00100         blocks[i] = this->NewChunk(b_size[i],b_num[i]);
00101         if (NULL == blocks[i]) n_error("Out Of Memory!");
00102     }
00103 }
00104 
00105 //------------------------------------------------------------------------------
00111 nMemManager::~nMemManager()
00112 {
00113 //    FILE *fp = NULL;
00114 
00115     nChunkHeader *ch;
00116     while ((ch = (nChunkHeader *) this->chunks.GetHead())) {
00117         char *b = ((char *)ch) + sizeof(nChunkHeader);
00118 
00119 /*
00120     FIXME: memlog disabled temporally, since it clutters the working directory
00121 
00122         int i;
00123         for (i=0; i<ch->bnum; i++,b+=ch->bsize) {
00124             nBlockHeader *bh = (nBlockHeader *)b;
00125             if (bh->size != 0) {
00126                 // Erster MemLeak? Dann Logfile erzeugen.
00127                 if (!fp) {
00128                     fp = fopen("n_memlog.txt","w");
00129                     if (fp) {
00130                         time_t ltime;
00131                         struct tm *t;
00132                         time(&ltime);
00133                         t = localtime(&ltime);
00134                         fprintf(fp,"Nebula Memory Log\n=================\n%s\n\n",asctime(t));
00135                     }
00136                 }
00137                 if (fp) {
00138                     fprintf(fp,"*** MEM LEAK DETECTED! ***\n");
00139                     fprintf(fp,"size = %d\n",bh->size);
00140                     fprintf(fp,"src  = %s\n",bh->src_name);
00141                     fprintf(fp,"line = %d\n",bh->src_line);
00142                 }
00143             }
00144         }
00145 */
00146         this->FreeChunk(ch);
00147     }
00148 /*
00149     if (fp) {
00150         fprintf(fp,"---\nEOF\n");
00151         fclose(fp);
00152     }
00153 */
00154 }
00155 
00156 //------------------------------------------------------------------------------
00163 nBlockHeader *nMemManager::NewChunk(int bsize, int bnum)
00164 {
00165     int block_size = bsize + sizeof(nBlockHeader) + sizeof(nBlockPostfix);
00166     int chunk_size = sizeof(nChunkHeader) + (block_size*bnum);
00167     char *c = (char *) malloc(chunk_size);
00168     if (c) {
00169         n_memallocated += chunk_size;
00170 
00171         // initialize chunk header
00172         nChunkHeader *ch = (nChunkHeader *) c;
00173         ch->nd.nNode::nNode();      // manually construct node.
00174         ch->bnum  = bnum;
00175         ch->bsize = block_size;
00176         this->chunks.AddTail((nNode *)ch);
00177 
00178         // initialize the blocks
00179         char *f = c + sizeof(nChunkHeader); // first Block
00180         char *p = c + chunk_size;           // last Block + 1
00181         char *next = NULL;
00182         while (p > f) {
00183             p -= block_size;
00184             nBlockHeader *bh = (nBlockHeader *)p;
00185             bh->next = (nBlockHeader *) next;
00186             bh->size = 0;
00187             strcpy(bh->src_name,"<new>");
00188             bh->src_line = 0;
00189             bh->magic = N_PREFIX_MAGIC_COOKIE;
00190             next = p;
00191         }
00192         return (nBlockHeader *) f;
00193     }
00194     return NULL;
00195 }
00196 
00197 //------------------------------------------------------------------------------
00203 void nMemManager::FreeChunk(nChunkHeader *ch)
00204 {
00205     n_memallocated -= sizeof(nChunkHeader) + (ch->bsize*ch->bnum);
00206     ch->nd.Remove();
00207     ch->nd.nNode::~nNode();
00208     free((void *)ch);
00209 }
00210 
00211 //------------------------------------------------------------------------------
00219 void *nMemManager::Malloc(int size, const char *src_name, int src_line)
00220 {
00221     mutex.Lock();
00222     char *p = NULL;
00223 
00224     // ensure source name fits
00225     int len = strlen(src_name)+1;
00226     int off = len - nBlockHeader::N_SRCNAME_LEN;
00227     if (off < 0) off = 0;
00228 
00229     if (size > (1<<N_MAXBLOCK)) {
00230         // memory wanted is bigger than max block size, so create a new individual chunk.
00231         p = (char *) this->NewChunk(size,1);
00232         if (p) {
00233             nBlockHeader *bh  = (nBlockHeader *) p;
00234             nBlockPostfix *bp = (nBlockPostfix *) (p + size + sizeof(nBlockHeader));
00235             bh->next = (nBlockHeader *) -1L;    // flag for n_free()/Free()
00236             bh->size = size;
00237             strcpy(bh->src_name,&(src_name[off]));
00238             bh->src_line = src_line;
00239             bh->magic = N_PREFIX_MAGIC_COOKIE;
00240             bp->magic = N_POSTFIX_MAGIC_COOKIE;
00241             p += sizeof(nBlockHeader);
00242             n_memused += size;
00243             n_memnumalloc++;
00244         }
00245     } else {
00246         // find suitable block size
00247         int i;
00248         for (i=0; i<(int)(N_NUMBLOCKSIZES-1); i++) {
00249             int mask = ~(b_size[i]-1);
00250             if ((size & mask) == 0) {
00251                 break;
00252             }
00253         }
00254         p = (char *) blocks[i];
00255         if (p) {
00256             nBlockHeader  *bh = (nBlockHeader *)  p;
00257             nBlockPostfix *bp = (nBlockPostfix *) (p + size + sizeof(nBlockHeader));
00258             blocks[i] = bh->next;
00259             if (NULL == blocks[i]) {
00260                 // need a new chunk
00261                 blocks[i] = this->NewChunk(b_size[i],b_num[i]);
00262                 if (NULL == blocks[i]) n_error("Out Of Memory!\n");
00263             }
00264             bh->next  = (nBlockHeader *) i;
00265             bh->size  = size;
00266             strcpy(bh->src_name,&(src_name[off]));
00267             bh->src_line = src_line;
00268             bh->magic = N_PREFIX_MAGIC_COOKIE;
00269             bp->magic = N_POSTFIX_MAGIC_COOKIE;
00270             p += sizeof(nBlockHeader);
00271             n_memused += size;
00272             n_memnumalloc++;
00273         }
00274     }
00275     mutex.Unlock();
00276     return p;
00277 }
00278 
00279 
00280 //------------------------------------------------------------------------------
00290 void *nMemManager::Realloc(void *oldp, int size, const char *src_name, int src_line)
00291 {
00292     if (oldp == NULL)
00293     {
00294         return this->Malloc(size, src_name, src_line);
00295     }
00296 
00297     if (size == 0)
00298     {
00299         this->Free(oldp);
00300     }
00301 
00302     char *oldpc = (char *) oldp;
00303     nBlockHeader  *bh = (nBlockHeader *) (oldpc - sizeof(nBlockHeader));
00304 
00305     int old_size = bh->size;
00306 
00307     void *p = this->Malloc(size, src_name, src_line);
00308 
00309     if (p != NULL)
00310     {
00311         memcpy(p, oldp, (size > old_size) ? old_size : size);
00312         this->Free(oldp);
00313     }
00314 
00315     return p;
00316 }
00317 
00318 
00319 //------------------------------------------------------------------------------
00325 void nMemManager::Free(void *p)
00326 {
00327     mutex.Lock();
00328 
00329     char *pc = (char *) p;
00330     nBlockHeader  *bh = (nBlockHeader *) (pc - sizeof(nBlockHeader));
00331     nBlockPostfix *bp;
00332 
00333     // is the block corrupt?
00334     if (bh->magic != (int)N_PREFIX_MAGIC_COOKIE)
00335     {
00336         n_error("Free(): START OF MEM BLOCK CORRUPTED: src=%s, line=%d\n", bh->src_name, bh->src_line);
00337     }
00338     bp = (nBlockPostfix *) (pc + bh->size);
00339     if (bp->magic != (int)N_POSTFIX_MAGIC_COOKIE) {
00340         n_error("Free(): END OF MEM BLOCK CORRUPTED: src=%s, line=%d\n", bh->src_name, bh->src_line);
00341     }
00342 
00343     // update memory stats
00344     n_memused -= bh->size;
00345     n_memnumalloc--;
00346 
00347     strcpy(bh->src_name,"<freed>");
00348     bh->src_line = 0;
00349 
00350     if (((int)bh->next) == -1L) {
00351         // block was allocated as individual chunk
00352         nChunkHeader *ch = (nChunkHeader *) (((char *)bh) - sizeof(nChunkHeader));
00353         bh->size = 0;
00354         this->FreeChunk(ch);
00355     } else {
00356         int i = (int) bh->next;
00357         nBlockHeader *next = blocks[i];
00358         blocks[i] = bh;
00359         bh->next = next;
00360         bh->size = 0;
00361     }
00362     mutex.Unlock();
00363 }
00364 
00365 //------------------------------------------------------------------------------
00371 void *nn_malloc(size_t size, const char *file, int line)
00372 {
00373     return mem.Malloc(size,file,line);
00374 }
00375 
00376 //------------------------------------------------------------------------------
00382 void n_free(void *p)
00383 {
00384     mem.Free(p);
00385 }
00386 
00387 //------------------------------------------------------------------------------
00393 void *nn_calloc(size_t num, size_t size, const char *file, int line)
00394 {
00395     size_t all_size = num*size;
00396     void *p = mem.Malloc(all_size,file,line);
00397     if (p) memset(p,0,sizeof(all_size));
00398     return p;
00399 }
00400 
00401 //------------------------------------------------------------------------------
00407 void *nn_realloc(void *p, size_t size, const char *file, int line)
00408 {
00409     return mem.Realloc(p, size, file, line);
00410 }
00411 //-------------------------------------------------------------------
00412 #elif __WIN32__
00413 //-------------------------------------------------------------------
00414 #ifdef __XBxX__
00415 #include "xbox/nxbwrapper.h"
00416 #else
00417 #include <windows.h>
00418 #endif
00419 
00420 //------------------------------------------------------------------------------
00427 void* nn_malloc(size_t size, const char* file, int line)
00428 {
00429     HGLOBAL ptr = GlobalAlloc(0, size);
00430     n_assert(ptr);
00431     return ptr;
00432 }
00433 
00434 //------------------------------------------------------------------------------
00438 void nn_free(void* p)
00439 {
00440     GlobalFree((HGLOBAL) p);
00441 }
00442 
00443 //------------------------------------------------------------------------------
00447 void* nn_calloc(size_t num, size_t size, const char*, int)
00448 {
00449     HGLOBAL ptr = GlobalAlloc(GMEM_ZEROINIT, size*num);
00450     n_assert(ptr);
00451     return ptr;
00452 }
00453 
00454 
00455 //------------------------------------------------------------------------------
00459 void* nn_realloc(void* p, size_t size, const char*, int)
00460 {
00461     HGLOBAL ptr = GlobalReAlloc((HGLOBAL)p, size, GMEM_MOVEABLE);
00462     n_assert(ptr);
00463     return ptr;
00464 }
00465 //-------------------------------------------------------------------
00466 #else
00467 //-------------------------------------------------------------------
00468 
00469 //------------------------------------------------------------------------------
00473 void *nn_malloc(size_t size, const char *, int)
00474 {
00475     return malloc(size);
00476 }
00477 
00478 //------------------------------------------------------------------------------
00482 void n_free(void *p)
00483 {
00484     free(p);
00485 }
00486 
00487 //------------------------------------------------------------------------------
00491 void *nn_calloc(size_t num, size_t size, const char *, int)
00492 {
00493     return calloc(num,size);
00494 }
00495 
00496 //------------------------------------------------------------------------------
00500 void *nn_realloc(void *p, size_t size, const char *, int)
00501 {
00502     return realloc(p, size);
00503 }
00504 
00505 //-------------------------------------------------------------------
00506 #endif
00507 
00508 //-------------------------------------------------------------------
00509 //  EOF
00510 //-------------------------------------------------------------------

Copyright © 1999-2005 by the contributing authors. Ideas, requests, problems: Send feedback.