UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
mem.cpp
Go to the documentation of this file.
1 
6 /*
7 All original material Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 Original file from Quake 2 v3.21: quake2-2.31/game/q_shared.c
10 Copyright (C) 1997-2001 Id Software, Inc.
11 
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 as published by the Free Software Foundation; either version 2
15 of the License, or (at your option) any later version.
16 
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 
21 See the GNU General Public License for more details.
22 
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 
27 */
28 
29 #include "common.h"
30 #include <SDL_thread.h>
31 
32 #define MEM_MAX_POOLNAME 64
33 #define MEM_HASH 11
34 
36  uint32_t sentinel;
37 };
38 
39 struct memBlock_t {
41 
42  uint32_t topSentinel;
45  int tagNum;
47  char const* allocFile;
48  int allocLine;
50  size_t memSize;
52  uint32_t botSentinel;
53 };
54 
55 struct memPool_t {
57  bool inUse;
61  uint32_t blockCount;
62  uint32_t byteCount;
64  char const* createFile;
65  int createLine;
66 };
67 
68 #define MEM_HEAD_SENTINEL_TOP 0xFEBDFAED
69 #define MEM_HEAD_SENTINEL_BOT 0xD0BAF0FF
70 #define MEM_FOOT_SENTINEL 0xF00DF00D
71 
72 static SDL_mutex* z_lock;
73 
74 #define MEM_MAX_POOLCOUNT 32
75 
77 static uint32_t m_numPools;
78 
79 /*==============================================================================
80 POOL MANAGEMENT
81 ==============================================================================*/
82 
83 static memPool_t* Mem_FindPool (const char* name)
84 {
85  memPool_t* pool;
86  uint32_t i;
87 
88  for (i = 0, pool = &m_poolList[0]; i < m_numPools; pool++, i++) {
89  if (!pool->inUse)
90  continue;
91  if (!Q_streq(name, pool->name))
92  continue;
93 
94  return pool;
95  }
96 
97  return nullptr;
98 }
99 
103 memPool_t* _Mem_CreatePool (const char* name, const char* fileName, const int fileLine)
104 {
105  /* Check name */
106  if (!name || !name[0])
107  Sys_Error("Mem_CreatePool: nullptr name %s:#%i", fileName, fileLine);
108  if (strlen(name) + 1 >= MEM_MAX_POOLNAME)
109  Com_Printf("Mem_CreatePoole: name '%s' too long, truncating!\n", name);
110 
111  /* See if it already exists */
112  memPool_t* pool = Mem_FindPool(name);
113  if (pool)
114  return pool;
115 
116  /* Nope, create a slot */
117  uint32_t i;
118  for (i = 0, pool = &m_poolList[0]; i < m_numPools; pool++, i++) {
119  if (!pool->inUse)
120  break;
121  }
122  if (i == m_numPools) {
123  if (m_numPools + 1 >= MEM_MAX_POOLCOUNT)
124  Sys_Error("Mem_CreatePool: MEM_MAX_POOLCOUNT");
125  pool = &m_poolList[m_numPools++];
126  }
127 
128  /* Store values */
129  for (i = 0; i < MEM_HASH; i++)
130  pool->blocks[i] = nullptr;
131  pool->blockCount = 0;
132  pool->byteCount = 0;
133  pool->createFile = fileName;
134  pool->createLine = fileLine;
135  pool->inUse = true;
136  Q_strncpyz(pool->name, name, sizeof(pool->name));
137 
138  return pool;
139 }
140 
146 void _Mem_DeletePool (memPool_t* pool, const char* fileName, const int fileLine)
147 {
148  if (!pool)
149  return;
150 
151  /* Release all allocated memory */
152  _Mem_FreePool(pool, fileName, fileLine);
153 
154  /* Simple, yes? */
155  pool->inUse = false;
156  pool->name[0] = '\0';
157 }
158 
159 /*==============================================================================
160 POOL AND TAG MEMORY ALLOCATION
161 ==============================================================================*/
162 
163 static memBlock_t* Mem_PtrToBlock(void* const ptr)
164 {
165  return static_cast<memBlock_t*>(ptr) - 1;
166 }
167 
168 static void* Mem_BlockToPtr(memBlock_t* const mem)
169 {
170  return mem + 1;
171 }
172 
174 {
175  return reinterpret_cast<memBlockFoot_t*>(reinterpret_cast<byte*>(Mem_BlockToPtr(mem)) + mem->memSize);
176 }
177 
178 static size_t Mem_BlockRawSize(memBlock_t const* const mem)
179 {
180  return mem->memSize + sizeof(memBlock_t) + sizeof(memBlockFoot_t);
181 }
182 
183 static void _Mem_CheckSentinels (memBlock_t* const mem, const char* fileName, const int fileLine)
184 {
185  /* Check sentinels */
186  if (mem->topSentinel != MEM_HEAD_SENTINEL_TOP) {
187  Sys_Error("Mem_CheckSentinels: bad memory header top sentinel [buffer underflow]\n"
188  "free: %s:#%i", fileName, fileLine);
189  } else if (mem->botSentinel != MEM_HEAD_SENTINEL_BOT) {
190  Sys_Error("Mem_CheckSentinels: bad memory header bottom sentinel [buffer underflow]\n"
191  "free: %s:#%i", fileName, fileLine);
192  } else if (Mem_BlockToFooter(mem)->sentinel != MEM_FOOT_SENTINEL) {
193  Sys_Error("Mem_CheckSentinels: bad memory footer sentinel [buffer overflow]\n"
194  "pool: %s\n"
195  "alloc: %s:#%i\n"
196  "free: %s:#%i",
197  mem->pool ? mem->pool->name : "UNKNOWN", mem->allocFile, mem->allocLine, fileName, fileLine);
198  }
199 }
200 
204 void _Mem_Free (void* ptr, const char* fileName, const int fileLine)
205 {
206  if (!ptr)
207  return;
208 
209  memBlock_t* const mem = Mem_PtrToBlock(ptr);
210  _Mem_CheckSentinels(mem, fileName, fileLine);
211 
212  SDL_LockMutex(z_lock);
213 
214  /* Decrement counters */
215  mem->pool->blockCount--;
216  mem->pool->byteCount -= Mem_BlockRawSize(mem);
217 
218  /* De-link it */
219  memBlock_t** prev = &mem->pool->blocks[(uintptr_t)mem % MEM_HASH];
220  for (;;) {
221  memBlock_t* search = *prev;
222  if (!search)
223  break;
224 
225  if (search == mem) {
226  *prev = search->next;
227  break;
228  }
229  prev = &search->next;
230  }
231 
232  SDL_UnlockMutex(z_lock);
233 
234  /* Free it */
235  free(mem);
236 }
237 
241 void _Mem_FreeTag (memPool_t* pool, const int tagNum, const char* fileName, const int fileLine)
242 {
243  if (!pool)
244  return;
245 
246  for (int j = 0; j < MEM_HASH; j++) {
247  for (memBlock_t* mem = pool->blocks[j], *next = nullptr; mem; mem = next) {
248  next = mem->next;
249  if (mem->tagNum == tagNum)
250  _Mem_Free(Mem_BlockToPtr(mem), fileName, fileLine);
251  }
252  }
253 }
254 
260 void _Mem_FreePool (memPool_t* pool, const char* fileName, const int fileLine)
261 {
262  if (!pool)
263  return;
264 
265  for (int j = 0; j < MEM_HASH; j++) {
266  for (memBlock_t* mem = pool->blocks[j], *next = nullptr; mem; mem = next) {
267  next = mem->next;
268  _Mem_Free(Mem_BlockToPtr(mem), fileName, fileLine);
269  }
270  }
271 
272  assert(pool->blockCount == 0);
273  assert(pool->byteCount == 0);
274 }
275 
279 void* _Mem_Alloc (size_t size, bool zeroFill, memPool_t* pool, const int tagNum, const char* fileName, const int fileLine)
280 {
281  /* Check pool */
282  if (!pool)
283  Sys_Error("Mem_Alloc: Error - no pool given\n" "alloc: %s:#%i", fileName, fileLine);
284 
285  /* Check size */
286  if (size <= 0)
287  Sys_Error("Mem_Alloc: Attempted allocation of '" UFO_SIZE_T "' memory ignored\n" "alloc: %s:#%i", size, fileName, fileLine);
288 
289  if (size > 0x40000000)
290  Sys_Error("Mem_Alloc: Attempted allocation of '" UFO_SIZE_T "' bytes!\n" "alloc: %s:#%i", size, fileName, fileLine);
291 
292  /* Add header and round to cacheline */
293  size = (size + sizeof(memBlock_t) + sizeof(memBlockFoot_t) + 31) & ~31;
294  memBlock_t* mem = static_cast<memBlock_t* >(malloc(size));
295  if (!mem)
296  Sys_Error("Mem_Alloc: failed on allocation of '" UFO_SIZE_T "' bytes\n" "alloc: %s:#%i", size, fileName, fileLine);
297 
298  /* Zero fill */
299  if (zeroFill)
300  memset(mem, 0, size);
301 
302  /* Fill in the header */
304  mem->tagNum = tagNum;
305  mem->memSize = size - sizeof(memBlock_t) - sizeof(memBlockFoot_t);
306  mem->pool = pool;
307  mem->allocFile = fileName;
308  mem->allocLine = fileLine;
310 
311  /* Fill in the footer */
313 
314  SDL_LockMutex(z_lock);
315 
316  /* For integrity checking and stats */
317  pool->blockCount++;
318  pool->byteCount += size;
319 
320  /* Link it in to the appropriate pool */
321  mem->next = pool->blocks[(uintptr_t)mem % MEM_HASH];
322  pool->blocks[(uintptr_t)mem % MEM_HASH] = mem;
323 
324  SDL_UnlockMutex(z_lock);
325 
326  return Mem_BlockToPtr(mem);
327 }
328 
329 void* _Mem_ReAlloc (void* ptr, size_t size, const char* fileName, const int fileLine)
330 {
331  if (!size)
332  Sys_Error("Use Mem_Free instead");
333 
334  if (!ptr)
335  Sys_Error("Use Mem_Alloc instead");
336 
337  memBlock_t* const mem = Mem_PtrToBlock(ptr);
338  _Mem_CheckSentinels(mem, fileName, fileLine);
339 
340  /* if size matches, do nothing */
341  if (mem->memSize == size)
342  return ptr;
343 
344  memPool_t* pool = mem->pool;
345 
346  /* allocate memory for the new size */
347  void* newPtr = _Mem_Alloc(size, false, pool, mem->tagNum, fileName, fileLine);
348 
349  /* copy old data */
350  memcpy(newPtr, ptr, std::min(mem->memSize, size));
351  if (mem->memSize < size) {
352  const size_t delta = size - mem->memSize;
353  memset((byte*)newPtr + mem->memSize, 0, delta);
354  }
355 
356  /* if there was old data, free it */
357  _Mem_Free(ptr, fileName, fileLine);
358 
359  _Mem_CheckSentinels(Mem_PtrToBlock(newPtr), fileName, fileLine);
360 
361  return newPtr;
362 }
363 
364 /*==============================================================================
365 MISC FUNCTIONS
366 ==============================================================================*/
367 
377 char* _Mem_PoolStrDupTo (const char* in, char** out, memPool_t* pool, const int tagNum, const char* fileName, const int fileLine)
378 {
379  if (!out)
380  return nullptr;
381  *out = _Mem_PoolStrDup(in, pool, tagNum, fileName, fileLine);
382  return *out;
383 }
384 
385 void* _Mem_PoolDup (const void* in, size_t size, memPool_t* pool, const int tagNum, const char* fileName, const int fileLine)
386 {
387  assert(in != nullptr);
388  assert(size > 0);
389 
390  void* copy = _Mem_Alloc(size, false, pool, tagNum, fileName, fileLine);
391  memcpy(copy, in, size);
392  return copy;
393 }
394 
403 char* _Mem_PoolStrDup (const char* in, memPool_t* pool, const int tagNum, const char* fileName, const int fileLine)
404 {
405  char* out = (char*)_Mem_Alloc((size_t)(strlen(in) + 1), true, pool, tagNum, fileName, fileLine);
406  strcpy(out, in);
407 
408  return out;
409 }
410 
414 uint32_t _Mem_PoolSize (memPool_t* pool)
415 {
416  if (!pool)
417  return 0;
418 
419  return pool->byteCount;
420 }
421 
422 uint32_t _Mem_ChangeTag (memPool_t* pool, const int tagFrom, const int tagTo)
423 {
424  if (!pool)
425  return 0;
426 
427  uint32_t numChanged = 0;
428 
429  for (int j = 0; j < MEM_HASH; j++) {
430  for (memBlock_t* mem = pool->blocks[j]; mem; mem = mem->next) {
431  if (mem->tagNum == tagFrom) {
432  mem->tagNum = tagTo;
433  numChanged++;
434  }
435  }
436  }
437 
438  return numChanged;
439 }
440 
441 static void _Mem_CheckPoolIntegrity (memPool_t* pool, const char* fileName, const int fileLine)
442 {
443  uint32_t blocks;
444  uint32_t size;
445  int j = 0;
446 
447  assert(pool);
448  if (!pool)
449  return;
450 
451  /* Check sentinels */
452  for (j = 0, blocks = 0, size = 0; j < MEM_HASH; j++) {
453  for (memBlock_t* mem = pool->blocks[j]; mem; blocks++, mem = mem->next) {
454  size += Mem_BlockRawSize(mem);
455  _Mem_CheckSentinels(mem, fileName, fileLine);
456  }
457  }
458 
459  /* Check block/byte counts */
460  if (pool->blockCount != blocks)
461  Sys_Error("Mem_CheckPoolIntegrity: bad block count\n" "check: %s:#%i", fileName, fileLine);
462  if (pool->byteCount != size)
463  Sys_Error("Mem_CheckPoolIntegrity: bad pool size\n" "check: %s:#%i", fileName, fileLine);
464 }
465 
466 void _Mem_CheckGlobalIntegrity (const char* fileName, const int fileLine)
467 {
468  memPool_t* pool;
469  uint32_t i;
470 
471  for (i = 0, pool = &m_poolList[0]; i < m_numPools; pool++, i++) {
472  if (pool->inUse)
473  _Mem_CheckPoolIntegrity(pool, fileName, fileLine);
474  }
475 }
476 
482 bool _Mem_AllocatedInPool (memPool_t* pool, const void* pointer)
483 {
484  if (!pool)
485  return false;
486 
487  /* if it's in the pool, it must be in THIS block */
488  memBlock_t* mem = pool->blocks[(uintptr_t)pointer % MEM_HASH];
489  /* Cycle through the blocks */
490  for ( ; mem; mem = mem->next) {
491  if (Mem_BlockToPtr(mem) == pointer)
492  return true;
493  }
494 
495  return false;
496 }
497 
498 #ifdef COMPILE_UFO
499 /*==============================================================================
500 CONSOLE COMMANDS
501 ==============================================================================*/
502 
503 static void Mem_Check_f (void)
504 {
506 }
507 
508 static void Mem_Stats_f (void)
509 {
510  uint32_t totalBytes, i;
511  memPool_t* pool;
512 
513  if (Cmd_Argc() > 1) {
514  memPool_t* best;
515  memBlock_t* mem;
516 
517  best = nullptr;
518  for (i = 0, pool = &m_poolList[0]; i < m_numPools; pool++, i++) {
519  if (!pool->inUse)
520  continue;
521  if (strstr(pool->name, Cmd_Args())) {
522  if (best) {
523  Com_Printf("Too many matches for '%s'...\n", Cmd_Args());
524  return;
525  }
526  best = pool;
527  }
528  }
529  if (!best) {
530  Com_Printf("No matches for '%s'...\n", Cmd_Args());
531  return;
532  }
533 
534  Com_Printf("Pool stats for '%s':\n", best->name);
535  Com_Printf("block line file size \n");
536  Com_Printf("----- ----- -------------------- ---------- \n");
537 
538  uint32_t totalBytes = 0;
539  int j = 0;
540  for (j = 0; j < MEM_HASH; j++) {
541  for (i = 0, mem = best->blocks[j]; mem; mem = mem->next, i++) {
542  if (i & 1)
544 
545  size_t const size = Mem_BlockRawSize(mem);
546 
547  Com_Printf("%5i %5i %20s " UFO_SIZE_T "B\n", i + 1, mem->allocLine, mem->allocFile, size);
548 
549  totalBytes += size;
550  }
551  }
552 
553  Com_Printf("----------------------------------------\n");
554  Com_Printf("Total: %i blocks, %i bytes (%6.3fMB)\n", i, totalBytes, totalBytes/1048576.0f);
555  return;
556  }
557 
558  Com_Printf("Memory stats:\n");
559  Com_Printf(" blocks size name\n");
560  Com_Printf("--- ------ ---------- ---------- --------\n");
561 
562  uint32_t totalBlocks = 0;
563  totalBytes = 0;
564  uint32_t poolNum = 0;
565  for (i = 0, pool = &m_poolList[0]; i < m_numPools; pool++, i++) {
566  if (!pool->inUse)
567  continue;
568 
569  poolNum++;
570  if (poolNum & 1)
572 
573  Com_Printf("#%2i %6i %9iB (%6.3fMB) %s\n", poolNum, pool->blockCount, pool->byteCount, pool->byteCount/1048576.0f, pool->name);
574 
575  totalBlocks += pool->blockCount;
576  totalBytes += pool->byteCount;
577  }
578 
579  Com_Printf("----------------------------------------\n");
580  Com_Printf("Total: %i pools, %i blocks, %i bytes (%6.3fMB)\n", i, totalBlocks, totalBytes, totalBytes/1048576.0f);
581 }
582 #endif
583 
588 void Mem_Init (void)
589 {
590 #ifdef COMPILE_UFO
591  Cmd_AddCommand("mem_stats", Mem_Stats_f, "Prints out current internal memory statistics");
592  Cmd_AddCommand("mem_check", Mem_Check_f, "Checks global memory integrity");
593 #endif
594 
595  z_lock = SDL_CreateMutex();
596 }
597 
603 void Mem_Shutdown (void)
604 {
605  memPool_t* pool;
606  int i;
607 
608  /* don't use cvars, debug print or anything else inside of this loop
609  * the mem you are trying to use here might already be wiped away */
610  for (i = 0, pool = &m_poolList[0]; i < m_numPools; pool++, i++) {
611  if (!pool->inUse)
612  continue;
613  Mem_DeletePool(pool);
614  }
615 
616  SDL_DestroyMutex(z_lock);
617  z_lock = nullptr;
618 }
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition: cmd.cpp:744
size_t memSize
Definition: mem.cpp:50
char const * allocFile
Definition: mem.cpp:47
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
#define MEM_HEAD_SENTINEL_BOT
Definition: mem.cpp:69
static void * Mem_BlockToPtr(memBlock_t *const mem)
Definition: mem.cpp:168
void Mem_Shutdown(void)
Definition: mem.cpp:603
uint32_t byteCount
Definition: mem.cpp:62
void * _Mem_PoolDup(const void *in, size_t size, memPool_t *pool, const int tagNum, const char *fileName, const int fileLine)
Definition: mem.cpp:385
static uint32_t m_numPools
Definition: mem.cpp:77
void * _Mem_Alloc(size_t size, bool zeroFill, memPool_t *pool, const int tagNum, const char *fileName, const int fileLine)
Optionally returns 0 filled memory allocated in a pool with a tag.
Definition: mem.cpp:279
QGL_EXTERN GLint GLenum GLboolean GLsizei const GLvoid * pointer
Definition: r_gl.h:94
static memPool_t * Mem_FindPool(const char *name)
Definition: mem.cpp:83
int createLine
Definition: mem.cpp:65
int tagNum
Definition: mem.cpp:45
uint32_t botSentinel
Definition: mem.cpp:52
#define MEM_MAX_POOLCOUNT
Definition: mem.cpp:74
#define MEM_FOOT_SENTINEL
Definition: mem.cpp:70
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
uint32_t sentinel
Definition: mem.cpp:36
uint32_t _Mem_PoolSize(memPool_t *pool)
Definition: mem.cpp:414
uint32_t topSentinel
Definition: mem.cpp:42
#define MEM_MAX_POOLNAME
Definition: mem.cpp:32
memPool_t * pool
Definition: mem.cpp:44
uint32_t _Mem_ChangeTag(memPool_t *pool, const int tagFrom, const int tagTo)
Definition: mem.cpp:422
char * _Mem_PoolStrDupTo(const char *in, char **out, memPool_t *pool, const int tagNum, const char *fileName, const int fileLine)
Saves a string to client hunk.
Definition: mem.cpp:377
#define Mem_CheckGlobalIntegrity()
Definition: mem.h:54
static memBlockFoot_t * Mem_BlockToFooter(memBlock_t *const mem)
Definition: mem.cpp:173
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
bool _Mem_AllocatedInPool(memPool_t *pool, const void *pointer)
Definition: mem.cpp:482
void _Mem_Free(void *ptr, const char *fileName, const int fileLine)
Definition: mem.cpp:204
bool inUse
Definition: mem.cpp:57
void _Mem_CheckGlobalIntegrity(const char *fileName, const int fileLine)
Definition: mem.cpp:466
GLsizei size
Definition: r_gl.h:152
static void _Mem_CheckSentinels(memBlock_t *const mem, const char *fileName, const int fileLine)
Definition: mem.cpp:183
void _Mem_FreePool(memPool_t *pool, const char *fileName, const int fileLine)
Free all items within a pool.
Definition: mem.cpp:260
static size_t Mem_BlockRawSize(memBlock_t const *const mem)
Definition: mem.cpp:178
int Cmd_Argc(void)
Return the number of arguments of the current command. "command parameter" will result in a argc of 2...
Definition: cmd.cpp:505
static void _Mem_CheckPoolIntegrity(memPool_t *pool, const char *fileName, const int fileLine)
Definition: mem.cpp:441
#define Mem_DeletePool(pool)
Definition: mem.h:33
#define MEM_HEAD_SENTINEL_TOP
Definition: mem.cpp:68
void * _Mem_ReAlloc(void *ptr, size_t size, const char *fileName, const int fileLine)
Definition: mem.cpp:329
uint32_t blockCount
Definition: mem.cpp:61
#define S_COLOR_GREEN
Definition: common.h:219
char const * createFile
Definition: mem.cpp:64
static memBlock_t * Mem_PtrToBlock(void *const ptr)
Definition: mem.cpp:163
memPool_t * _Mem_CreatePool(const char *name, const char *fileName, const int fileLine)
Definition: mem.cpp:103
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
static SDL_mutex * z_lock
Definition: mem.cpp:72
char * _Mem_PoolStrDup(const char *in, memPool_t *pool, const int tagNum, const char *fileName, const int fileLine)
No need to null terminate the extra spot because Mem_Alloc returns zero-filled memory.
Definition: mem.cpp:403
char name[MEM_MAX_POOLNAME]
Definition: mem.cpp:56
int allocLine
Definition: mem.cpp:48
QGL_EXTERN GLint i
Definition: r_gl.h:113
void Mem_Init(void)
Definition: mem.cpp:588
#define MEM_HASH
Definition: mem.cpp:33
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
#define UFO_SIZE_T
Definition: ufotypes.h:89
definitions common between client and server, but not game lib
memBlock_t * blocks[MEM_HASH]
Definition: mem.cpp:59
#define Q_streq(a, b)
Definition: shared.h:136
void _Mem_FreeTag(memPool_t *pool, const int tagNum, const char *fileName, const int fileLine)
Free memory blocks assigned to a specified tag within a pool.
Definition: mem.cpp:241
memBlock_t * next
Definition: mem.cpp:40
uint8_t byte
Definition: ufotypes.h:34
const char * Cmd_Args(void)
Returns a single string containing argv(1) to argv(argc()-1)
Definition: cmd.cpp:526
void _Mem_DeletePool(memPool_t *pool, const char *fileName, const int fileLine)
Definition: mem.cpp:146
static memPool_t m_poolList[MEM_MAX_POOLCOUNT]
Definition: mem.cpp:76