wwmemlog.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWDebug *
  23. * *
  24. * $Archive:: /Commando/Code/wwdebug/wwmemlog.cpp $*
  25. * *
  26. * Original Author:: Greg Hjelstrom *
  27. * *
  28. * $Author:: Jani_p $*
  29. * *
  30. * $Modtime:: 11/21/01 2:03p $*
  31. * *
  32. * $Revision:: 27 $*
  33. * *
  34. *---------------------------------------------------------------------------------------------*
  35. * Functions: *
  36. * WWMemoryLogClass::Allocate_Memory -- allocates memory *
  37. * WWMemoryLogClass::Release_Memory -- frees memory *
  38. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  39. #include "always.h"
  40. #include "wwmemlog.h"
  41. #include "wwdebug.h"
  42. #include "vector.h"
  43. #include "fastallocator.h"
  44. #include <windows.h>
  45. #define USE_FAST_ALLOCATOR
  46. #ifdef STEVES_NEW_CATCHER
  47. #define DISABLE_MEMLOG 1
  48. #else //STEVES_NEW_CATCHER
  49. #ifdef PARAM_EDITING_ON
  50. #define DISABLE_MEMLOG 1
  51. #else //PARAM_EDITING_ON
  52. #define DISABLE_MEMLOG 1
  53. #endif //PARAM_EDITING_ON
  54. #endif //STEVES_NEW_CATCHER*/
  55. #ifdef USE_FAST_ALLOCATOR
  56. #define ALLOC_MEMORY(n) FastAllocatorGeneral::Get_Allocator()->Alloc(n)
  57. #define FREE_MEMORY(p) FastAllocatorGeneral::Get_Allocator()->Free(p)
  58. #else
  59. #define ALLOC_MEMORY(n) ::malloc(n)
  60. #define FREE_MEMORY(p) ::free(p)
  61. #endif
  62. /*
  63. ** Enable one of the following #defines to specify which thread-sychronization
  64. ** method to use.
  65. */
  66. #ifndef _UNIX
  67. #define MEMLOG_USE_MUTEX 0
  68. #define MEMLOG_USE_CRITICALSECTION 1
  69. #define MEMLOG_USE_FASTCRITICALSECTION 0
  70. #else
  71. #undef DISABLE_MEMLOG
  72. #define DISABLE_MEMLOG 1
  73. #define MEMLOG_USE_MUTEX 0
  74. #define MEMLOG_USE_CRITICALSECTION 0
  75. #define MEMLOG_USE_FASTCRITICALSECTION 0
  76. #endif
  77. #if (DISABLE_MEMLOG == 0)
  78. bool WWMemoryLogClass::IsMemoryLogEnabled=true;
  79. #else
  80. bool WWMemoryLogClass::IsMemoryLogEnabled=false;
  81. #endif
  82. static unsigned AllocateCount;
  83. static unsigned FreeCount;
  84. /*
  85. ** Name for each memory category. I'm padding the array with some "undefined" strings in case
  86. ** someone forgets to set the name when adding a new category.
  87. */
  88. static char * _MemoryCategoryNames[] =
  89. {
  90. "UNKNOWN",
  91. "Geometry",
  92. "Animation",
  93. "Texture",
  94. "Pathfind",
  95. "Vis",
  96. "Sound",
  97. "CullingData",
  98. "Strings",
  99. "GameData",
  100. "PhysicsData",
  101. "W3dData",
  102. "StaticAllocations",
  103. "GameInit",
  104. "Renderer",
  105. "Network",
  106. "BINK",
  107. "<undefined>",
  108. "<undefined>",
  109. "<undefined>",
  110. "<undefined>",
  111. };
  112. /**
  113. ** MemoryCounterClass
  114. ** This object will store statistics for each memory category. It can provide things like
  115. ** the current amount of allocated memory and the peak amount of allocated memory.
  116. */
  117. class MemoryCounterClass
  118. {
  119. public:
  120. MemoryCounterClass(void) : CurrentAllocation(0), PeakAllocation(0) { }
  121. void Memory_Allocated(int size) { CurrentAllocation+=size; PeakAllocation = max(PeakAllocation,CurrentAllocation); }
  122. void Memory_Released(int size) { CurrentAllocation-=size; }
  123. int Get_Current_Allocated_Memory(void) { return CurrentAllocation; }
  124. int Get_Peak_Allocated_Memory(void) { return PeakAllocation; }
  125. protected:
  126. int CurrentAllocation;
  127. int PeakAllocation;
  128. };
  129. /**
  130. ** ActiveCategoryStackClass
  131. ** This object is used to keep track of the "active memory category". Whenever memory is allocated
  132. ** it will be charged to the current active memory category. To be thread-safe, there will be
  133. ** one ActiveCategoryStack per thread that is encountered in the program.
  134. */
  135. const int MAX_CATEGORY_STACK_DEPTH = 1024;
  136. class ActiveCategoryStackClass : public VectorClass<int>
  137. {
  138. public:
  139. ActiveCategoryStackClass(void) :
  140. VectorClass<int>(MAX_CATEGORY_STACK_DEPTH),
  141. ThreadID(-1),
  142. Count(0)
  143. { }
  144. // If object was created but not Init'd, ThreadID will be -1 and Count == 0
  145. // If object was created and Init'd, ThreadID will not be -1. We expect Count to return to 1 after all Pop's
  146. ~ActiveCategoryStackClass(void) { WWASSERT((ThreadID == -1 && Count == 0) || (ThreadID != -1 && Count == 1)); }
  147. ActiveCategoryStackClass & operator = (const ActiveCategoryStackClass & that);
  148. bool operator == (const ActiveCategoryStackClass &) { return false; }
  149. bool operator != (const ActiveCategoryStackClass &) { return true; }
  150. void Init(int thread_id) { ThreadID = thread_id; Count = 0; Push(MEM_UNKNOWN); }
  151. void Set_Thread_ID(int id) { WWASSERT(ThreadID != -1); ThreadID = id; }
  152. int Get_Thread_ID(void) { return ThreadID; }
  153. void Push(int active_category) { WWASSERT(ThreadID != -1); (*this)[Count] = active_category; Count++; }
  154. void Pop(void) { WWASSERT(ThreadID != -1) ; Count--; }
  155. int Current(void) { WWASSERT(ThreadID != -1); return (*this)[Count-1]; }
  156. protected:
  157. int ThreadID;
  158. int Count;
  159. };
  160. /**
  161. ** ActiveCategoryClass
  162. ** This is a dynamic vector of ActiveCategoryStackClasses which adds a new stack each time
  163. ** a new thread is encountered. It also is able to return to you the active category for
  164. ** the currently active thread automatically.
  165. */
  166. const int MAX_CATEGORY_STACKS = 256; // maximum number of threads we expect to encounter...
  167. class ActiveCategoryClass : public VectorClass<ActiveCategoryStackClass>
  168. {
  169. public:
  170. ActiveCategoryClass(void) : VectorClass<ActiveCategoryStackClass>(MAX_CATEGORY_STACKS), Count(0) { Get_Active_Stack().Push(MEM_STATICALLOCATION); }
  171. void Push(int active_category) { Get_Active_Stack().Push(active_category); }
  172. void Pop(void) { Get_Active_Stack().Pop(); }
  173. int Current(void) { return Get_Active_Stack().Current(); }
  174. protected:
  175. ActiveCategoryStackClass & Get_Active_Stack(void);
  176. int Count;
  177. };
  178. /**
  179. ** MemLogClass
  180. ** This class ties all of the logging datastructures together into a single object
  181. ** which can be created on demand when the first 'new' call is encountered.
  182. */
  183. class MemLogClass
  184. {
  185. public:
  186. int Get_Current_Allocated_Memory(int category);
  187. int Get_Peak_Allocated_Memory(int category);
  188. /*
  189. ** Interface for recording allocations and de-allocations
  190. */
  191. int Register_Memory_Allocated(int size);
  192. void Register_Memory_Released(int category,int size);
  193. void Push_Active_Category(int category);
  194. void Pop_Active_Category(void);
  195. void Init();
  196. private:
  197. MemoryCounterClass _MemoryCounters[MEM_COUNT];
  198. ActiveCategoryClass _ActiveCategoryTracker;
  199. };
  200. /**
  201. ** Static Variables
  202. ** _TheMemLog - object which encapsulates all logging. will be allocated on first use
  203. ** _MemLogMutex - handle to the mutex used to arbtirate access to the logging data structures
  204. ** _MemLogLockCounter - count of the active mutex locks.
  205. */
  206. static MemLogClass * _TheMemLog = NULL;
  207. static bool _MemLogAllocated = false;
  208. #if MEMLOG_USE_MUTEX
  209. static void * _MemLogMutex = NULL;
  210. static int _MemLogLockCounter = 0;
  211. #endif
  212. #if MEMLOG_USE_CRITICALSECTION
  213. static bool _MemLogCriticalSectionAllocated = false;
  214. static char _MemLogCriticalSectionHandle[sizeof(CRITICAL_SECTION)];
  215. #endif
  216. #if MEMLOG_USE_FASTCRITICALSECTION
  217. volatile unsigned _MemLogSemaphore = 0;
  218. #endif
  219. /*
  220. ** Use this code to get access to the mutex...
  221. */
  222. WWINLINE void * Get_Mem_Log_Mutex(void)
  223. {
  224. #if MEMLOG_USE_MUTEX
  225. if (_MemLogMutex == NULL) {
  226. _MemLogMutex=CreateMutex(NULL,false,NULL);
  227. WWASSERT(_MemLogMutex);
  228. }
  229. return _MemLogMutex;
  230. #endif
  231. #if MEMLOG_USE_CRITICALSECTION
  232. if (_MemLogCriticalSectionAllocated == false) {
  233. InitializeCriticalSection((CRITICAL_SECTION*)_MemLogCriticalSectionHandle);
  234. _MemLogCriticalSectionAllocated = true;
  235. }
  236. return _MemLogCriticalSectionHandle;
  237. #endif
  238. }
  239. WWINLINE void Lock_Mem_Log_Mutex(void)
  240. {
  241. #if MEMLOG_USE_MUTEX
  242. void * mutex = Get_Mem_Log_Mutex();
  243. #ifdef DEBUG_CRASHING
  244. int res =
  245. #endif
  246. WaitForSingleObject(mutex,INFINITE);
  247. WWASSERT(res==WAIT_OBJECT_0);
  248. _MemLogLockCounter++;
  249. #endif
  250. #if MEMLOG_USE_CRITICALSECTION
  251. Get_Mem_Log_Mutex();
  252. EnterCriticalSection((CRITICAL_SECTION*)_MemLogCriticalSectionHandle);
  253. #endif
  254. #if MEMLOG_USE_FASTCRITICALSECTION
  255. volatile unsigned& nFlag=_MemLogSemaphore;
  256. #define ts_lock _emit 0xF0
  257. assert(((unsigned)&nFlag % 4) == 0);
  258. __asm mov ebx, [nFlag]
  259. __asm ts_lock
  260. __asm bts dword ptr [ebx], 0
  261. __asm jc The_Bit_Was_Previously_Set_So_Try_Again
  262. return;
  263. The_Bit_Was_Previously_Set_So_Try_Again:
  264. ThreadClass::Switch_Thread();
  265. __asm mov ebx, [nFlag]
  266. __asm ts_lock
  267. __asm bts dword ptr [ebx], 0
  268. __asm jc The_Bit_Was_Previously_Set_So_Try_Again
  269. #endif
  270. }
  271. WWINLINE void Unlock_Mem_Log_Mutex(void)
  272. {
  273. #if MEMLOG_USE_MUTEX
  274. void * mutex = Get_Mem_Log_Mutex();
  275. _MemLogLockCounter--;
  276. #ifdef DEBUG_CRASHING
  277. int res=
  278. #endif
  279. ReleaseMutex(mutex);
  280. WWASSERT(res);
  281. #endif
  282. #if MEMLOG_USE_CRITICALSECTION
  283. Get_Mem_Log_Mutex();
  284. LeaveCriticalSection((CRITICAL_SECTION*)_MemLogCriticalSectionHandle);
  285. #endif
  286. #if MEMLOG_USE_FASTCRITICALSECTION
  287. _MemLogSemaphore = 0;
  288. #endif
  289. }
  290. class MemLogMutexLockClass
  291. {
  292. public:
  293. MemLogMutexLockClass(void) { Lock_Mem_Log_Mutex(); }
  294. ~MemLogMutexLockClass(void) { Unlock_Mem_Log_Mutex(); }
  295. };
  296. /***************************************************************************************************
  297. **
  298. ** ActiveCategoryStackClass Implementation
  299. **
  300. ***************************************************************************************************/
  301. ActiveCategoryStackClass &
  302. ActiveCategoryStackClass::operator = (const ActiveCategoryStackClass & that)
  303. {
  304. if (this != &that) {
  305. VectorClass<int>::operator == (that);
  306. ThreadID = that.ThreadID;
  307. Count = that.Count;
  308. }
  309. return *this;
  310. }
  311. /***************************************************************************************************
  312. **
  313. ** ActiveCategoryClass Implementation
  314. **
  315. ***************************************************************************************************/
  316. ActiveCategoryStackClass & ActiveCategoryClass::Get_Active_Stack(void)
  317. {
  318. int current_thread = ::GetCurrentThreadId();
  319. /*
  320. ** If we already have an allocated category stack for the current thread,
  321. ** just return its active category.
  322. */
  323. for (int i=0; i<Count; i++) {
  324. ActiveCategoryStackClass & cat_stack = (*this)[i];
  325. if (cat_stack.Get_Thread_ID() == current_thread) {
  326. return cat_stack;
  327. }
  328. }
  329. /*
  330. ** If we fall through to here, we need to allocate a new category stack
  331. ** for this thread.
  332. */
  333. (*this)[Count].Init(current_thread);
  334. Count++;
  335. return (*this)[Count-1];
  336. }
  337. /***************************************************************************************************
  338. **
  339. ** MemLogClass Implementation
  340. **
  341. ***************************************************************************************************/
  342. int MemLogClass::Get_Current_Allocated_Memory(int category)
  343. {
  344. MemLogMutexLockClass lock;
  345. return _MemoryCounters[category].Get_Current_Allocated_Memory();
  346. }
  347. int MemLogClass::Get_Peak_Allocated_Memory(int category)
  348. {
  349. MemLogMutexLockClass lock;
  350. return _MemoryCounters[category].Get_Peak_Allocated_Memory();
  351. }
  352. void MemLogClass::Init()
  353. {
  354. {
  355. MemLogMutexLockClass lock;
  356. WWASSERT(_ActiveCategoryTracker.Current()==MEM_STATICALLOCATION);
  357. }
  358. Pop_Active_Category(); // Remove staticallocation state forever
  359. }
  360. int MemLogClass::Register_Memory_Allocated(int size)
  361. {
  362. MemLogMutexLockClass lock;
  363. int active_category = _ActiveCategoryTracker.Current();
  364. WWASSERT((active_category >= 0) && (active_category < MEM_COUNT));
  365. _MemoryCounters[active_category].Memory_Allocated(size);
  366. return active_category;
  367. }
  368. void MemLogClass::Register_Memory_Released(int category,int size)
  369. {
  370. MemLogMutexLockClass lock;
  371. _MemoryCounters[category].Memory_Released(size);
  372. }
  373. void MemLogClass::Push_Active_Category(int category)
  374. {
  375. MemLogMutexLockClass lock;
  376. WWASSERT((category >= 0) && (category < MEM_COUNT));
  377. _ActiveCategoryTracker.Push(category);
  378. }
  379. void MemLogClass::Pop_Active_Category(void)
  380. {
  381. MemLogMutexLockClass lock;
  382. _ActiveCategoryTracker.Pop();
  383. }
  384. /***************************************************************************************************
  385. **
  386. ** WWMemoryLogClass Implementation
  387. **
  388. ***************************************************************************************************/
  389. int WWMemoryLogClass::Get_Category_Count(void)
  390. {
  391. return MEM_COUNT;
  392. }
  393. const char * WWMemoryLogClass::Get_Category_Name(int category)
  394. {
  395. return _MemoryCategoryNames[category];
  396. }
  397. int WWMemoryLogClass::Get_Current_Allocated_Memory(int category)
  398. {
  399. return Get_Log()->Get_Current_Allocated_Memory(category);
  400. }
  401. int WWMemoryLogClass::Get_Peak_Allocated_Memory(int category)
  402. {
  403. return Get_Log()->Get_Peak_Allocated_Memory(category);
  404. }
  405. void WWMemoryLogClass::Push_Active_Category(int category)
  406. {
  407. #if (DISABLE_MEMLOG == 0)
  408. Get_Log()->Push_Active_Category(category);
  409. #endif //(DISABLE_MEMLOG == 0)
  410. }
  411. void WWMemoryLogClass::Pop_Active_Category(void)
  412. {
  413. #if (DISABLE_MEMLOG == 0)
  414. Get_Log()->Pop_Active_Category();
  415. #endif //(DISABLE_MEMLOG == 0)
  416. }
  417. int WWMemoryLogClass::Register_Memory_Allocated(int size)
  418. {
  419. return Get_Log()->Register_Memory_Allocated(size);
  420. }
  421. void WWMemoryLogClass::Register_Memory_Released(int category,int size)
  422. {
  423. Get_Log()->Register_Memory_Released(category,size);
  424. }
  425. static void _MemLogCleanup(void)
  426. {
  427. delete _TheMemLog;
  428. }
  429. MemLogClass * WWMemoryLogClass::Get_Log(void)
  430. {
  431. MemLogMutexLockClass lock;
  432. if (_TheMemLog == NULL) {
  433. //assert(!_MemLogAllocated);
  434. _TheMemLog = W3DNEW MemLogClass;
  435. #ifdef STEVES_NEW_CATCHER
  436. /*
  437. ** This was me trying to be clever and fix the memory leak in the memlog. Unfortunately, the Get_Log member can be called
  438. ** during the process of exiting the process (IYSWIM) and you get it trying to re-allocate the MemLogClass I just freed.
  439. ** Solution is just to disable memlog when I'm trying to find memory leaks. ST - 6/18/2001 9:51PM
  440. */
  441. if (!_MemLogAllocated) {
  442. atexit(&Release_Log);
  443. }
  444. _MemLogAllocated = true;
  445. #endif //STEVES_NEW_CATCHER
  446. }
  447. return _TheMemLog;
  448. }
  449. /***********************************************************************************************
  450. * WWMemoryLogClass::Release_Log -- Free the memory used by WWMemoryLogClass so it doesn't leak*
  451. * *
  452. * *
  453. * *
  454. * INPUT: Nothing *
  455. * *
  456. * OUTPUT: Nothing *
  457. * *
  458. * WARNINGS: Called as part of _onexit processing *
  459. * *
  460. * It's messy, but I assume there's a reason it's not statically allocated... *
  461. * OK, now I get it *
  462. * *
  463. * HISTORY: *
  464. * 6/13/2001 8:55PM ST : Created *
  465. *=============================================================================================*/
  466. void WWMemoryLogClass::Release_Log(void)
  467. {
  468. MemLogMutexLockClass lock;
  469. if (_TheMemLog) {
  470. delete _TheMemLog;
  471. _TheMemLog = NULL;
  472. }
  473. }
  474. /***************************************************************************************************
  475. **
  476. ** Allocating and Freeing memory
  477. **
  478. ** PLEASE NOTE: The user is expected to implement global new and delete functions in his own
  479. ** code which call WWMemoryLogClass::Allocate_Memory and WWMemoryLogClass::Release_Memory.
  480. ** This was the only solution I could come up given that some APPS have their own new and delete
  481. ** functions or enable the CRT ones. It was also not an option to move this entire system into
  482. ** the APP because I wanted all of our LIBs to participate in the memory usage logging...
  483. **
  484. ***************************************************************************************************/
  485. const int WWMEMLOG_KEY0 = (unsigned('G')<<24) | (unsigned('g')<<16) | (unsigned('0')<<8) | unsigned('l');
  486. const int WWMEMLOG_KEY1 = (unsigned('~')<<24) | (unsigned('_')<<16) | (unsigned('d')<<8) | unsigned('3');
  487. /**
  488. ** MemoryLogStruct
  489. ** This structure is added to the beginning of each memory allocation to facilitate
  490. ** tracking which category the memory belongs to when it is freed. The size of
  491. ** this struct is also 16 bytes so that we wont be seriously affecting the alignment
  492. ** of allocated memory...
  493. */
  494. struct MemoryLogStruct
  495. {
  496. MemoryLogStruct(int category,int size) :
  497. Key0(WWMEMLOG_KEY0),
  498. Key1(WWMEMLOG_KEY1),
  499. Category(category),
  500. Size(size)
  501. {}
  502. bool Is_Valid_Memory_Log(void) { return ((Key0 == WWMEMLOG_KEY0) && (Key1 == WWMEMLOG_KEY1)); }
  503. int Key0; // if this is not equal to WWMEMLOG_KEY0 then we don't have a valid log
  504. int Key1; // should be equal to WWMEMLOG_KEY1
  505. int Category; // category this memory belongs to
  506. int Size; // size of the allocation
  507. };
  508. /***********************************************************************************************
  509. * WWMemoryLogClass::Allocate_Memory -- allocates memory *
  510. * *
  511. * This function adds a header to the memory allocated so that when the memory is freed *
  512. * the proper memory category size can be decremented. The application using this logging *
  513. * system should call this function from inside its overloaded 'new' operator. *
  514. * *
  515. * INPUT: *
  516. * *
  517. * OUTPUT: *
  518. * *
  519. * WARNINGS: *
  520. * *
  521. * HISTORY: *
  522. * 5/29/2001 gth : Created. *
  523. *=============================================================================================*/
  524. void * WWMemoryLogClass::Allocate_Memory(size_t size)
  525. {
  526. AllocateCount++;
  527. #if DISABLE_MEMLOG
  528. return ALLOC_MEMORY(size);
  529. #else
  530. __declspec( thread ) static bool reentrancy_test = false;
  531. MemLogMutexLockClass lock;
  532. if (reentrancy_test) {
  533. return ALLOC_MEMORY(size);
  534. } else {
  535. reentrancy_test = true;
  536. /*
  537. ** Allocate space for the requested buffer + our logging structure
  538. */
  539. void * ptr = ALLOC_MEMORY(size + sizeof(MemoryLogStruct));
  540. if (ptr != NULL) {
  541. /*
  542. ** Record this allocation
  543. */
  544. int active_category = WWMemoryLogClass::Register_Memory_Allocated(size);
  545. /*
  546. ** Write our logging structure into the beginning of the buffer. I'm using
  547. ** placement new syntax to initialize the log structure right in the memory buffer
  548. */
  549. new(ptr) MemoryLogStruct(active_category,size);
  550. /*
  551. ** Return the allocated memory to the user, skipping past our log structure.
  552. */
  553. reentrancy_test = false;
  554. return (void*)(((char *)ptr) + sizeof(MemoryLogStruct));
  555. } else {
  556. reentrancy_test = false;
  557. return ptr;
  558. }
  559. }
  560. #endif //DISABLE_MEMLOG
  561. }
  562. /***********************************************************************************************
  563. * WWMemoryLogClass::Release_Memory -- frees memory *
  564. * *
  565. * This function checks for a wwmemlog header and decrements the relevant memory category. *
  566. * It should be called in the application's custom delete operator. *
  567. * *
  568. * INPUT: *
  569. * *
  570. * OUTPUT: *
  571. * *
  572. * WARNINGS: *
  573. * *
  574. * HISTORY: *
  575. * 5/29/2001 gth : Created. *
  576. *=============================================================================================*/
  577. void WWMemoryLogClass::Release_Memory(void *ptr)
  578. {
  579. FreeCount++;
  580. #if DISABLE_MEMLOG
  581. FREE_MEMORY(ptr);
  582. #else
  583. MemLogMutexLockClass lock;
  584. if (ptr) {
  585. /*
  586. ** Check if this memory is preceeded by a valid MemoryLogStruct
  587. */
  588. MemoryLogStruct * memlog = (MemoryLogStruct*)((char*)ptr - sizeof(MemoryLogStruct));
  589. if (memlog->Is_Valid_Memory_Log()) {
  590. /*
  591. ** Valid MemoryLogStruct found, track the de-allocation and pass on
  592. ** to the built-in free function.
  593. */
  594. WWMemoryLogClass::Register_Memory_Released(memlog->Category,memlog->Size);
  595. FREE_MEMORY((void*)memlog);
  596. } else {
  597. /*
  598. ** No valid MemoryLogStruct found, just call free on the memory.
  599. */
  600. FREE_MEMORY(ptr);
  601. }
  602. }
  603. #endif //DISABLE_MEMLOG
  604. }
  605. // Reset allocate and free counters
  606. void WWMemoryLogClass::Reset_Counters()
  607. {
  608. AllocateCount=0;
  609. FreeCount=0;
  610. }
  611. // Return allocate count since last reset
  612. int WWMemoryLogClass::Get_Allocate_Count()
  613. {
  614. return AllocateCount;
  615. }
  616. // Return allocate count since last reset
  617. int WWMemoryLogClass::Get_Free_Count()
  618. {
  619. return FreeCount;
  620. }
  621. void WWMemoryLogClass::Init()
  622. {
  623. Get_Log()->Init();
  624. }