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;
00027 int bnum;
00028 int bsize;
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
00114
00115 nChunkHeader *ch;
00116 while ((ch = (nChunkHeader *) this->chunks.GetHead())) {
00117 char *b = ((char *)ch) + sizeof(nChunkHeader);
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 this->FreeChunk(ch);
00147 }
00148
00149
00150
00151
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
00172 nChunkHeader *ch = (nChunkHeader *) c;
00173 ch->nd.nNode::nNode();
00174 ch->bnum = bnum;
00175 ch->bsize = block_size;
00176 this->chunks.AddTail((nNode *)ch);
00177
00178
00179 char *f = c + sizeof(nChunkHeader);
00180 char *p = c + chunk_size;
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
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
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;
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
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
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
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
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
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
00510