diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt
index 0c91e47cc5d..494d544f73d 100644
--- a/Core/GameEngine/CMakeLists.txt
+++ b/Core/GameEngine/CMakeLists.txt
@@ -45,7 +45,7 @@ set(GAMEENGINE_SRC
Include/Common/GameDefines.h
# Include/Common/GameEngine.h
# Include/Common/GameLOD.h
-# Include/Common/GameMemory.h
+ Include/Common/GameMemory.h
Include/Common/GameMusic.h
Include/Common/GameSounds.h
# Include/Common/GameSpyMiscPreferences.h
@@ -646,13 +646,13 @@ set(GAMEENGINE_SRC
# Source/Common/System/FunctionLexicon.cpp
# Source/Common/System/GameCommon.cpp
#Source/Common/System/GameMemory.cpp # is conditionally appended
+ #Source/Common/System/GameMemoryInit.cpp # is conditionally appended
# Source/Common/System/GameType.cpp
# Source/Common/System/Geometry.cpp
# Source/Common/System/KindOf.cpp
# Source/Common/System/List.cpp
Source/Common/System/LocalFile.cpp
Source/Common/System/LocalFileSystem.cpp
- #Source/Common/System/MemoryInit.cpp # is conditionally appended
# Source/Common/System/ObjectStatusTypes.cpp
# Source/Common/System/QuotedPrintable.cpp
# Source/Common/System/Radar.cpp
@@ -1139,14 +1139,18 @@ set(GAMEENGINE_SRC
if(RTS_GAMEMEMORY_ENABLE)
# Uses the original Game Memory implementation.
list(APPEND GAMEENGINE_SRC
-# Source/Common/System/GameMemory.cpp
-# Source/Common/System/MemoryInit.cpp
+ Source/Common/System/GameMemory.cpp
+ Source/Common/System/GameMemoryInit.cpp
+ Source/Common/System/GameMemoryInitDMA_Generals.inl
+ Source/Common/System/GameMemoryInitDMA_GeneralsMD.inl
+ Source/Common/System/GameMemoryInitPools_Generals.inl
+ Source/Common/System/GameMemoryInitPools_GeneralsMD.inl
)
else()
# Uses the null implementation when disabled.
list(APPEND GAMEENGINE_SRC
-# Source/Common/System/GameMemoryNull.cpp
-# Include/Common/GameMemoryNull.h
+ Source/Common/System/GameMemoryNull.cpp
+ Include/Common/GameMemoryNull.h
)
endif()
diff --git a/Core/GameEngine/Include/Common/GameDefines.h b/Core/GameEngine/Include/Common/GameDefines.h
index 8a9f5158c85..3df8fb30903 100644
--- a/Core/GameEngine/Include/Common/GameDefines.h
+++ b/Core/GameEngine/Include/Common/GameDefines.h
@@ -59,3 +59,11 @@
#ifndef ENABLE_FILESYSTEM_EXISTENCE_CACHE
#define ENABLE_FILESYSTEM_EXISTENCE_CACHE (1)
#endif
+
+// Enable obsolete code. This mainly refers to code that existed in Generals but was removed in GeneralsMD.
+// Disable and remove this when Generals and GeneralsMD are merged.
+#if RTS_GENERALS
+#ifndef USE_OBSOLETE_GENERALS_CODE
+#define USE_OBSOLETE_GENERALS_CODE (1)
+#endif
+#endif
diff --git a/GeneralsMD/Code/GameEngine/Include/Common/GameMemory.h b/Core/GameEngine/Include/Common/GameMemory.h
similarity index 100%
rename from GeneralsMD/Code/GameEngine/Include/Common/GameMemory.h
rename to Core/GameEngine/Include/Common/GameMemory.h
diff --git a/Generals/Code/GameEngine/Include/Common/GameMemoryNull.h b/Core/GameEngine/Include/Common/GameMemoryNull.h
similarity index 100%
rename from Generals/Code/GameEngine/Include/Common/GameMemoryNull.h
rename to Core/GameEngine/Include/Common/GameMemoryNull.h
diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/GameMemory.cpp b/Core/GameEngine/Source/Common/System/GameMemory.cpp
similarity index 100%
rename from GeneralsMD/Code/GameEngine/Source/Common/System/GameMemory.cpp
rename to Core/GameEngine/Source/Common/System/GameMemory.cpp
diff --git a/Core/GameEngine/Source/Common/System/GameMemoryInit.cpp b/Core/GameEngine/Source/Common/System/GameMemoryInit.cpp
new file mode 100644
index 00000000000..3f559fbdd05
--- /dev/null
+++ b/Core/GameEngine/Source/Common/System/GameMemoryInit.cpp
@@ -0,0 +1,154 @@
+/*
+** Command & Conquer Generals Zero Hour(tm)
+** Copyright 2025 Electronic Arts Inc.
+**
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// //
+// (c) 2001-2003 Electronic Arts Inc. //
+// //
+////////////////////////////////////////////////////////////////////////////////
+
+// FILE: MemoryInit.cpp
+//-----------------------------------------------------------------------------
+//
+// Westwood Studios Pacific.
+//
+// Confidential Information
+// Copyright (C) 2001 - All Rights Reserved
+//
+//-----------------------------------------------------------------------------
+//
+// Project: RTS3
+//
+// File name: MemoryInit.cpp
+//
+// Created: Steven Johnson, August 2001
+//
+// Desc: Memory manager
+//
+// ----------------------------------------------------------------------------
+#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
+
+// SYSTEM INCLUDES
+
+// USER INCLUDES
+#include "Lib/BaseType.h"
+#include "Common/GameMemory.h"
+
+struct PoolSizeRec
+{
+ const char* name;
+ Int initial;
+ Int overflow;
+};
+
+#if RTS_GENERALS
+#include "GameMemoryInitDMA_Generals.inl"
+#include "GameMemoryInitPools_Generals.inl"
+#elif RTS_ZEROHOUR
+#include "GameMemoryInitDMA_GeneralsMD.inl"
+#include "GameMemoryInitPools_GeneralsMD.inl"
+#endif
+
+//-----------------------------------------------------------------------------
+void userMemoryManagerGetDmaParms(Int *numSubPools, const PoolInitRec **pParms)
+{
+ *numSubPools = ARRAY_SIZE(DefaultDMA);
+ *pParms = DefaultDMA;
+}
+
+//-----------------------------------------------------------------------------
+void userMemoryAdjustPoolSize(const char *poolName, Int& initialAllocationCount, Int& overflowAllocationCount)
+{
+ if (initialAllocationCount > 0)
+ return;
+
+ for (const PoolSizeRec* p = PoolSizes; p->name != NULL; ++p)
+ {
+ if (strcmp(p->name, poolName) == 0)
+ {
+ initialAllocationCount = p->initial;
+ overflowAllocationCount = p->overflow;
+ return;
+ }
+ }
+
+ DEBUG_CRASH(("Initial size for pool %s not found -- you should add it to MemoryInit.cpp",poolName));
+}
+
+//-----------------------------------------------------------------------------
+static Int roundUpMemBound(Int i)
+{
+ const int MEM_BOUND_ALIGNMENT = 4;
+
+ if (i < MEM_BOUND_ALIGNMENT)
+ return MEM_BOUND_ALIGNMENT;
+ else
+ return (i + (MEM_BOUND_ALIGNMENT-1)) & ~(MEM_BOUND_ALIGNMENT-1);
+}
+
+//-----------------------------------------------------------------------------
+void userMemoryManagerInitPools()
+{
+ // note that we MUST use stdio stuff here, and not the normal game file system
+ // (with bigfile support, etc), because that relies on memory pools, which
+ // aren't yet initialized properly! so rely ONLY on straight stdio stuff here.
+ // (not even AsciiString. thanks.)
+
+ // since we're called prior to main, the cur dir might not be what
+ // we expect. so do it the hard way.
+ char buf[_MAX_PATH];
+ ::GetModuleFileName(NULL, buf, sizeof(buf));
+ char* pEnd = buf + strlen(buf);
+ while (pEnd != buf)
+ {
+ if (*pEnd == '\\')
+ {
+ *pEnd = 0;
+ break;
+ }
+ --pEnd;
+ }
+ strcat(buf, "\\Data\\INI\\MemoryPools.ini");
+
+ FILE* fp = fopen(buf, "r");
+ if (fp)
+ {
+ char poolName[256];
+ int initial, overflow;
+ while (fgets(buf, _MAX_PATH, fp))
+ {
+ if (buf[0] == ';')
+ continue;
+ if (sscanf(buf, "%s %d %d", poolName, &initial, &overflow ) == 3)
+ {
+ for (PoolSizeRec* p = PoolSizes; p->name != NULL; ++p)
+ {
+ if (stricmp(p->name, poolName) == 0)
+ {
+ // currently, these must be multiples of 4. so round up.
+ p->initial = roundUpMemBound(initial);
+ p->overflow = roundUpMemBound(overflow);
+ break; // from for-p
+ }
+ }
+ }
+ }
+ fclose(fp);
+ }
+}
+
diff --git a/Core/GameEngine/Source/Common/System/GameMemoryInitDMA_Generals.inl b/Core/GameEngine/Source/Common/System/GameMemoryInitDMA_Generals.inl
new file mode 100644
index 00000000000..98a7809fe08
--- /dev/null
+++ b/Core/GameEngine/Source/Common/System/GameMemoryInitDMA_Generals.inl
@@ -0,0 +1,29 @@
+/*
+** Command & Conquer Generals(tm)
+** Copyright 2025 TheSuperHackers
+**
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program. If not, see .
+*/
+
+static const PoolInitRec DefaultDMA[] =
+{
+ // name, allocSize, initialCount, overflowCount
+ { "dmaPool_16", 16, 65536, 1024 },
+ { "dmaPool_32", 32, 150000, 1024 },
+ { "dmaPool_64", 64, 60000, 1024 },
+ { "dmaPool_128", 128, 32768, 1024 },
+ { "dmaPool_256", 256, 8192, 1024 },
+ { "dmaPool_512", 512, 8192, 1024 },
+ { "dmaPool_1024", 1024, 24000, 1024 }
+};
diff --git a/Core/GameEngine/Source/Common/System/GameMemoryInitDMA_GeneralsMD.inl b/Core/GameEngine/Source/Common/System/GameMemoryInitDMA_GeneralsMD.inl
new file mode 100644
index 00000000000..91c67d3f391
--- /dev/null
+++ b/Core/GameEngine/Source/Common/System/GameMemoryInitDMA_GeneralsMD.inl
@@ -0,0 +1,29 @@
+/*
+** Command & Conquer Generals Zero Hour(tm)
+** Copyright 2025 TheSuperHackers
+**
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program. If not, see .
+*/
+
+static const PoolInitRec DefaultDMA[] =
+{
+ // name, allocSize, initialCount, overflowCount
+ { "dmaPool_16", 16, 130000, 10000 },
+ { "dmaPool_32", 32, 250000, 10000 },
+ { "dmaPool_64", 64, 100000, 10000 },
+ { "dmaPool_128", 128, 80000, 10000 },
+ { "dmaPool_256", 256, 20000, 5000 },
+ { "dmaPool_512", 512, 16000, 5000 },
+ { "dmaPool_1024", 1024, 6000, 1024 }
+};
diff --git a/Generals/Code/GameEngine/Source/Common/System/MemoryInit.cpp b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_Generals.inl
similarity index 83%
rename from Generals/Code/GameEngine/Source/Common/System/MemoryInit.cpp
rename to Core/GameEngine/Source/Common/System/GameMemoryInitPools_Generals.inl
index 0b0c7ee9539..b049809df14 100644
--- a/Generals/Code/GameEngine/Source/Common/System/MemoryInit.cpp
+++ b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_Generals.inl
@@ -1,6 +1,6 @@
/*
** Command & Conquer Generals(tm)
-** Copyright 2025 Electronic Arts Inc.
+** Copyright 2025 TheSuperHackers
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
@@ -16,71 +16,9 @@
** along with this program. If not, see .
*/
-////////////////////////////////////////////////////////////////////////////////
-// //
-// (c) 2001-2003 Electronic Arts Inc. //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
-// FILE: MemoryInit.cpp
-//-----------------------------------------------------------------------------
-//
-// Westwood Studios Pacific.
-//
-// Confidential Information
-// Copyright (C) 2001 - All Rights Reserved
-//
-//-----------------------------------------------------------------------------
-//
-// Project: RTS3
-//
-// File name: MemoryInit.cpp
-//
-// Created: Steven Johnson, August 2001
-//
-// Desc: Memory manager
-//
-// ----------------------------------------------------------------------------
-#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
-
-// SYSTEM INCLUDES
-
-// USER INCLUDES
-#include "Lib/BaseType.h"
-#include "Common/GameMemory.h"
-
-
-//-----------------------------------------------------------------------------
-void userMemoryManagerGetDmaParms(Int *numSubPools, const PoolInitRec **pParms)
-{
- static const PoolInitRec defaultDMA[7] =
- {
- // name, allocsize, initialcount, overflowcount
- { "dmaPool_16", 16, 65536, 1024 },
- { "dmaPool_32", 32, 150000, 1024 },
- { "dmaPool_64", 64, 60000, 1024 },
- { "dmaPool_128", 128, 32768, 1024 },
- { "dmaPool_256", 256, 8192, 1024 },
- { "dmaPool_512", 512, 8192, 1024 },
- { "dmaPool_1024", 1024, 24000, 1024 }
- };
-
- *numSubPools = 7;
- *pParms = defaultDMA;
-}
-
-//-----------------------------------------------------------------------------
-struct PoolSizeRec
-{
- const char* name;
- Int initial;
- Int overflow;
-};
-
-//-----------------------------------------------------------------------------
// And please be careful of duplicates. They are not rejected.
// not const -- we might override from INI
-static PoolSizeRec sizes[] =
+static PoolSizeRec PoolSizes[] =
{
{ "PartitionContactListNode", 2048, 512 },
{ "BattleshipUpdate", 32, 32 },
@@ -123,6 +61,7 @@ static PoolSizeRec sizes[] =
{ "AIGroupPool", 64, 32 },
{ "AIDockMachinePool", 256, 32 },
{ "AIGuardMachinePool", 32, 32 },
+ { "AIGuardRetaliateMachinePool", 32, 32 },
{ "AITNGuardMachinePool", 32, 32 },
{ "PathNodePool", 8192, 1024 },
{ "PathPool", 256, 16 },
@@ -143,6 +82,9 @@ static PoolSizeRec sizes[] =
{ "ObjectSMCHelperPool", 4096, 256 },
{ "ObjectWeaponStatusHelperPool", 4096, 256 },
{ "ObjectDefectionHelperPool", 4096, 256 },
+ { "StatusDamageHelper", 1500, 256 },
+ { "SubdualDamageHelper", 1500, 256 },
+ { "TempWeaponBonusHelper", 4096, 256 },
{ "Locomotor", 2048, 32 },
{ "LocomotorTemplate", 128, 32 },
{ "ObjectPool", 4096, 32 },
@@ -159,6 +101,10 @@ static PoolSizeRec sizes[] =
{ "AudioEventInfo", 1200, 64 },
{ "AudioRequest", 256, 8 },
{ "AutoHealBehavior", 4096, 32 },
+ { "WeaponBonusUpdate", 16, 16 },
+ { "GrantStealthBehavior", 4096, 32 },
+ { "NeutronBlastBehavior", 4096, 32 },
+ { "CountermeasuresBehavior", 256, 32 },
{ "BaseRegenerateUpdate", 64, 32 },
{ "BoneFXDamage", 64, 32 },
{ "BoneFXUpdate", 64, 32 },
@@ -172,11 +118,15 @@ static PoolSizeRec sizes[] =
{ "EjectPilotDie", 1024, 32 },
{ "CrushDie", 1024, 32 },
{ "DamDie", 8, 8 },
+#if USE_OBSOLETE_GENERALS_CODE
{ "DelayedUpgrade", 32, 32 },
{ "DelayedWeaponSetUpgradeUpdate", 32, 32 },
+#endif
{ "DeliverPayloadStateMachine", 32, 32 },
{ "DeliverPayloadAIUpdate", 32, 32 },
{ "DeletionUpdate", 128, 32 },
+ { "SmartBombTargetHomingUpdate", 8, 8 },
+ { "DynamicAudioEventInfo", 16, 256 }, // Note: some levels have none, some have lots. Since all are allocated at level load time, we can set this low for the levels with none.
{ "HackInternetStateMachine", 32, 32 },
{ "HackInternetAIUpdate", 32, 32 },
{ "MissileAIUpdate", 512, 32 },
@@ -203,6 +153,7 @@ static PoolSizeRec sizes[] =
{ "GenerateMinefieldBehavior", 32, 32 },
{ "HelicopterSlowDeathBehavior", 64, 32 },
{ "ParkingPlaceBehavior", 32, 32 },
+ { "FlightDeckBehavior", 8, 8 },
#ifdef ALLOW_SURRENDER
{ "POWTruckAIUpdate", 32, 32, },
{ "POWTruckBehavior", 32, 32, },
@@ -211,10 +162,12 @@ static PoolSizeRec sizes[] =
{ "PropagandaCenterBehavior", 16, 16 },
#endif
{ "PropagandaTowerBehavior", 16, 16 },
+ { "BunkerBusterBehavior", 16, 16 },
{ "ObjectTracker", 128, 32 },
{ "OCLUpdate", 16, 16 },
{ "BodyParticleSystem", 128, 64 },
{ "HighlanderBody", 2048, 128 },
+ { "UndeadBody", 32, 32 },
{ "HordeUpdate", 128, 32 },
{ "ImmortalBody", 2048, 128 },
{ "InactiveBody", 2048, 32 },
@@ -227,11 +180,14 @@ static PoolSizeRec sizes[] =
{ "PilotFindVehicleUpdate", 256, 32 },
{ "DemoTrapUpdate", 32, 32 },
{ "ParticleUplinkCannonUpdate", 16, 16 },
+ { "SpectreGunshipUpdate", 8, 8 },
+ { "SpectreGunshipDeploymentUpdate", 8, 8 },
{ "BaikonurLaunchPower", 4, 4 },
{ "RadiusDecalUpdate", 16, 16 },
{ "BattlePlanUpdate", 32, 32 },
{ "LifetimeUpdate", 256, 32 },
{ "LocomotorSetUpgrade", 512, 128 },
+ { "LockWeaponCreate", 64, 128 },
{ "AutoDepositUpdate", 256, 32 },
{ "NeutronMissileUpdate", 512, 32 },
{ "MoneyCrateCollide", 32, 32 },
@@ -239,6 +195,7 @@ static PoolSizeRec sizes[] =
{ "OpenContain", 128, 32 },
{ "OverchargeBehavior", 32, 32 },
{ "OverlordContain", 32, 32 },
+ { "HelixContain", 32, 32 },
{ "ParachuteContain", 128, 32 },
{ "PhysicsBehavior", 600, 32 },
{ "PoisonedBehavior", 512, 64 },
@@ -249,6 +206,7 @@ static PoolSizeRec sizes[] =
{ "QueueProductionExitUpdate", 32, 32 },
{ "RadarUpdate", 16, 16 },
{ "RadarUpgrade", 16, 16 },
+ { "AnimationSteeringUpdate", 1024, 32 },
{ "SupplyWarehouseCripplingBehavior", 16, 16 },
{ "CostModifierUpgrade", 32, 32 },
{ "CashBountyPower", 32, 32 },
@@ -256,6 +214,7 @@ static PoolSizeRec sizes[] =
{ "ObjectCreationUpgrade", 128, 32 },
{ "MinefieldBehavior", 256, 32 },
{ "JetSlowDeathBehavior", 64, 32 },
+ { "BattleBusSlowDeathBehavior", 64, 32 },
{ "RebuildHoleBehavior", 64, 32 },
{ "RebuildHoleExposeDie", 64, 32 },
{ "RepairDockUpdate", 32, 32 },
@@ -298,6 +257,8 @@ static PoolSizeRec sizes[] =
{ "TransitionDamageFX", 256, 32 },
{ "TransportAIUpdate", 64, 32 },
{ "TransportContain", 128, 32 },
+ { "RiderChangeContain", 128, 32 },
+ { "InternetHackContain", 16, 16 },
{ "TunnelContain", 16, 16 },
{ "TunnelContainDie", 32, 32 },
{ "TunnelCreate", 32, 32 },
@@ -310,6 +271,14 @@ static PoolSizeRec sizes[] =
{ "VeterancyGainCreate", 512, 128 },
{ "ConvertToCarBombCrateCollide", 32, 32 },
{ "ConvertToHijackedVehicleCrateCollide", 32, 32 },
+ { "SabotageCommandCenterCrateCollide", 256, 128 },
+ { "SabotageFakeBuildingCrateCollide", 256, 128 },
+ { "SabotageInternetCenterCrateCollide", 256, 128 },
+ { "SabotageMilitaryFactoryCrateCollide", 256, 128 },
+ { "SabotagePowerPlantCrateCollide", 256, 128 },
+ { "SabotageSuperweaponCrateCollide", 256, 128 },
+ { "SabotageSupplyCenterCrateCollide", 256, 128 },
+ { "SabotageSupplyDropzoneCrateCollide", 256, 128 },
{ "JetAIUpdate", 64, 32 },
{ "ChinookAIUpdate", 32, 32 },
{ "WanderAIUpdate", 32, 32 },
@@ -333,23 +302,33 @@ static PoolSizeRec sizes[] =
{ "W3DLaserDraw", 32, 32 },
{ "W3DModelDraw", 4096, 128 },
{ "W3DOverlordTankDraw", 64, 64 },
+ { "W3DOverlordTruckDraw", 64, 64 },
+ { "W3DOverlordAircraftDraw", 64, 64 },
{ "W3DPoliceCarDraw", 32, 32 },
{ "W3DProjectileStreamDraw", 32, 32 },
{ "W3DRopeDraw", 32, 32 },
{ "W3DScienceModelDraw", 32, 32 },
{ "W3DSupplyDraw", 32, 32 },
{ "W3DTankDraw", 256, 32 },
+ { "W3DTreeDraw", 16, 16 },
+ { "W3DPropDraw", 16, 16 },
{ "W3DTracerDraw", 64, 32 },
{ "W3DTruckDraw", 128, 32 },
{ "W3DTankTruckDraw", 32, 16 },
+ { "W3DTreeTextureClass", 4, 4 },
{ "DefaultSpecialPower", 32, 32 },
{ "OCLSpecialPower", 32, 32 },
+ { "FireWeaponPower", 32, 32 },
#ifdef ALLOW_DEMORALIZE
{ "DemoralizeSpecialPower", 16, 16, },
#endif
{ "CashHackSpecialPower", 32, 32 },
{ "CommandSetUpgrade", 32, 32 },
+ { "PassengersFireUpgrade", 32, 32 },
{ "GrantUpgradeCreate", 256, 32 },
+ { "GrantScienceUpgrade", 256, 32 },
+ { "ReplaceObjectUpgrade", 32, 32 },
+ { "ModelConditionUpgrade", 32, 32 },
{ "SpyVisionSpecialPower", 256, 32 },
{ "StealthDetectorUpdate", 256, 32 },
{ "StealthUpdate", 256, 32 },
@@ -370,6 +349,7 @@ static PoolSizeRec sizes[] =
{ "MobNexusContain", 128, 32 },
{ "MobMemberSlavedUpdate", 64, 32 },
{ "EMPUpdate", 64, 32 },
+ { "LeafletDropBehavior", 64, 32 },
{ "Overridable", 32, 32 },
{ "W3DGameWindow", 1024, 32 },
@@ -387,6 +367,12 @@ static PoolSizeRec sizes[] =
{ "AIGuardReturnState", 32, 32 },
{ "AIGuardPickUpCrateState", 32, 32 },
{ "AIGuardAttackAggressorState", 32, 32 },
+ { "AIGuardRetaliateInnerState", 32, 32 },
+ { "AIGuardRetaliateIdleState", 32, 32 },
+ { "AIGuardRetaliateOuterState", 32, 32 },
+ { "AIGuardRetaliateReturnState", 32, 32 },
+ { "AIGuardRetaliatePickUpCrateState", 32, 32 },
+ { "AIGuardRetaliateAttackAggressorState", 32, 32 },
{ "AITNGuardInnerState", 32, 32 },
{ "AITNGuardIdleState", 32, 32 },
{ "AITNGuardOuterState", 32, 32 },
@@ -402,7 +388,9 @@ static PoolSizeRec sizes[] =
{ "AIDeadState", 600, 32 },
{ "AIDockState", 600, 32 },
{ "AIExitState", 600, 32 },
+ { "AIExitInstantlyState", 600, 32 },
{ "AIGuardState", 600, 32 },
+ { "AIGuardRetaliateState", 600, 32 },
{ "AITunnelNetworkGuardState", 600, 32 },
{ "AIHuntState", 600, 32 },
{ "AIAttackAreaState", 600, 32 },
@@ -475,6 +463,7 @@ static PoolSizeRec sizes[] =
{ "AIWanderState", 600, 32 },
{ "AIPanicState", 600, 32 },
{ "ChinookMoveToBldgState", 32, 32 },
+ { "ChinookRecordCreationState", 32, 32 },
{ "ScienceInfo", 64, 32 },
{ "RankInfo", 32, 32 },
@@ -505,6 +494,7 @@ static PoolSizeRec sizes[] =
{ "AttackPriorityInfo", 32, 32 },
{ "SequentialScript", 32, 32 },
{ "Win32LocalFile", 1024, 256 },
+ { "StdLocalFile", 1024, 256 },
{ "RAMFile", 32, 32 },
{ "BattlePlanBonuses", 32, 32 },
{ "KindOfPercentProductionChange", 32, 32 },
@@ -579,7 +569,7 @@ static PoolSizeRec sizes[] =
{ "W3DPrototypeClass", 2048, 32 },
{ "EnumeratedIP", 32, 32 },
{ "WaterTransparencySetting", 4, 4 },
-
+ { "WeatherSetting", 4, 4 },
// W3D pools!
{ "BoxPrototypeClass", 512, 32 },
@@ -591,6 +581,7 @@ static PoolSizeRec sizes[] =
{ "ParticleEmitterPrototypeClass", 32, 32 },
{ "NullPrototypeClass", 32, 32 },
{ "HLodPrototypeClass", 512, 32 },
+ { "HLodDefClass", 512, 32 },
{ "DistLODPrototypeClass", 32, 32 },
{ "DazzlePrototypeClass", 32, 32 },
{ "CollectionPrototypeClass", 32, 32 },
@@ -608,7 +599,6 @@ static PoolSizeRec sizes[] =
{ "TerrainTextureClass", 32, 32 },
{ "MeshClass", 16384, 1024 },
{ "HTreeClass", 8192, 32 },
- { "HLodDefClass", 512, 32 },
{ "HLodClass", 4096, 32 },
{ "MeshModelClass", 8192, 32 },
{ "ShareBufferClass", 32768, 1024 },
@@ -663,88 +653,8 @@ static PoolSizeRec sizes[] =
{ "DynamicMeshModel", 32, 32 },
{ "GapFillerClass", 32, 32 },
{ "FontCharsClass", 64, 32 },
-
+ { "ThumbnailManagerClass", 32, 32},
+ { "SmudgeSet", 32, 32},
+ { "Smudge", 128, 32},
{ 0, 0, 0 }
};
-
-//-----------------------------------------------------------------------------
-void userMemoryAdjustPoolSize(const char *poolName, Int& initialAllocationCount, Int& overflowAllocationCount)
-{
- if (initialAllocationCount > 0)
- return;
-
- for (const PoolSizeRec* p = sizes; p->name != NULL; ++p)
- {
- if (strcmp(p->name, poolName) == 0)
- {
- initialAllocationCount = p->initial;
- overflowAllocationCount = p->overflow;
- return;
- }
- }
-
- DEBUG_CRASH(("Initial size for pool %s not found -- you should add it to MemoryInit.cpp",poolName));
-}
-
-//-----------------------------------------------------------------------------
-static Int roundUpMemBound(Int i)
-{
- const int MEM_BOUND_ALIGNMENT = 4;
-
- if (i < MEM_BOUND_ALIGNMENT)
- return MEM_BOUND_ALIGNMENT;
- else
- return (i + (MEM_BOUND_ALIGNMENT-1)) & ~(MEM_BOUND_ALIGNMENT-1);
-}
-
-//-----------------------------------------------------------------------------
-void userMemoryManagerInitPools()
-{
- // note that we MUST use stdio stuff here, and not the normal game file system
- // (with bigfile support, etc), because that relies on memory pools, which
- // aren't yet initialized properly! so rely ONLY on straight stdio stuff here.
- // (not even AsciiString. thanks.)
-
- // since we're called prior to main, the cur dir might not be what
- // we expect. so do it the hard way.
- char buf[_MAX_PATH];
- ::GetModuleFileName(NULL, buf, sizeof(buf));
- char* pEnd = buf + strlen(buf);
- while (pEnd != buf)
- {
- if (*pEnd == '\\')
- {
- *pEnd = 0;
- break;
- }
- --pEnd;
- }
- strcat(buf, "\\Data\\INI\\MemoryPools.ini");
-
- FILE* fp = fopen(buf, "r");
- if (fp)
- {
- char poolName[256];
- int initial, overflow;
- while (fgets(buf, _MAX_PATH, fp))
- {
- if (buf[0] == ';')
- continue;
- if (sscanf(buf, "%s %d %d", poolName, &initial, &overflow ) == 3)
- {
- for (PoolSizeRec* p = sizes; p->name != NULL; ++p)
- {
- if (stricmp(p->name, poolName) == 0)
- {
- // currently, these must be multiples of 4. so round up.
- p->initial = roundUpMemBound(initial);
- p->overflow = roundUpMemBound(overflow);
- break; // from for-p
- }
- }
- }
- }
- fclose(fp);
- }
-}
-
diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/MemoryInit.cpp b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl
similarity index 84%
rename from GeneralsMD/Code/GameEngine/Source/Common/System/MemoryInit.cpp
rename to Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl
index e5e989307a1..2bf2e64c151 100644
--- a/GeneralsMD/Code/GameEngine/Source/Common/System/MemoryInit.cpp
+++ b/Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl
@@ -1,6 +1,6 @@
/*
** Command & Conquer Generals Zero Hour(tm)
-** Copyright 2025 Electronic Arts Inc.
+** Copyright 2025 TheSuperHackers
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
@@ -16,71 +16,9 @@
** along with this program. If not, see .
*/
-////////////////////////////////////////////////////////////////////////////////
-// //
-// (c) 2001-2003 Electronic Arts Inc. //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
-// FILE: MemoryInit.cpp
-//-----------------------------------------------------------------------------
-//
-// Westwood Studios Pacific.
-//
-// Confidential Information
-// Copyright (C) 2001 - All Rights Reserved
-//
-//-----------------------------------------------------------------------------
-//
-// Project: RTS3
-//
-// File name: MemoryInit.cpp
-//
-// Created: Steven Johnson, August 2001
-//
-// Desc: Memory manager
-//
-// ----------------------------------------------------------------------------
-#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
-
-// SYSTEM INCLUDES
-
-// USER INCLUDES
-#include "Lib/BaseType.h"
-#include "Common/GameMemory.h"
-
-
-//-----------------------------------------------------------------------------
-void userMemoryManagerGetDmaParms(Int *numSubPools, const PoolInitRec **pParms)
-{
- static const PoolInitRec defaultDMA[7] =
- {
- // name, allocsize, initialcount, overflowcount
- { "dmaPool_16", 16, 130000, 10000 },
- { "dmaPool_32", 32, 250000, 10000 },
- { "dmaPool_64", 64, 100000, 10000 },
- { "dmaPool_128", 128, 80000, 10000 },
- { "dmaPool_256", 256, 20000, 5000 },
- { "dmaPool_512", 512, 16000, 5000 },
- { "dmaPool_1024", 1024, 6000, 1024}
- };
-
- *numSubPools = 7;
- *pParms = defaultDMA;
-}
-
-//-----------------------------------------------------------------------------
-struct PoolSizeRec
-{
- const char* name;
- Int initial;
- Int overflow;
-};
-
-//-----------------------------------------------------------------------------
// And please be careful of duplicates. They are not rejected.
// not const -- we might override from INI
-static PoolSizeRec sizes[] =
+static PoolSizeRec PoolSizes[] =
{
{ "PartitionContactListNode", 2048, 512 },
{ "BattleshipUpdate", 32, 32 },
@@ -184,7 +122,7 @@ static PoolSizeRec sizes[] =
{ "DeliverPayloadAIUpdate", 32, 32 },
{ "DeletionUpdate", 128, 32 },
{ "SmartBombTargetHomingUpdate", 8, 8 },
- { "DynamicAudioEventInfo", 16, 256 }, // Note: some levels have none, some have lots. Since all are allocated at level load time, we can set this low for the levels with none.
+ { "DynamicAudioEventInfo", 16, 256 }, // Note: some levels have none, some have lots. Since all are allocated at level load time, we can set this low for the levels with none.
{ "HackInternetStateMachine", 32, 32 },
{ "HackInternetAIUpdate", 32, 32 },
{ "MissileAIUpdate", 512, 32 },
@@ -716,85 +654,3 @@ static PoolSizeRec sizes[] =
{ "Smudge", 128, 32},
{ 0, 0, 0 }
};
-
-//-----------------------------------------------------------------------------
-void userMemoryAdjustPoolSize(const char *poolName, Int& initialAllocationCount, Int& overflowAllocationCount)
-{
- if (initialAllocationCount > 0)
- return;
-
- for (const PoolSizeRec* p = sizes; p->name != NULL; ++p)
- {
- if (strcmp(p->name, poolName) == 0)
- {
- initialAllocationCount = p->initial;
- overflowAllocationCount = p->overflow;
- return;
- }
- }
-
- DEBUG_CRASH(("Initial size for pool %s not found -- you should add it to MemoryInit.cpp",poolName));
-}
-
-//-----------------------------------------------------------------------------
-static Int roundUpMemBound(Int i)
-{
- const int MEM_BOUND_ALIGNMENT = 4;
-
- if (i < MEM_BOUND_ALIGNMENT)
- return MEM_BOUND_ALIGNMENT;
- else
- return (i + (MEM_BOUND_ALIGNMENT-1)) & ~(MEM_BOUND_ALIGNMENT-1);
-}
-
-//-----------------------------------------------------------------------------
-void userMemoryManagerInitPools()
-{
- // note that we MUST use stdio stuff here, and not the normal game file system
- // (with bigfile support, etc), because that relies on memory pools, which
- // aren't yet initialized properly! so rely ONLY on straight stdio stuff here.
- // (not even AsciiString. thanks.)
-
- // since we're called prior to main, the cur dir might not be what
- // we expect. so do it the hard way.
- char buf[_MAX_PATH];
- ::GetModuleFileName(NULL, buf, sizeof(buf));
- char* pEnd = buf + strlen(buf);
- while (pEnd != buf)
- {
- if (*pEnd == '\\')
- {
- *pEnd = 0;
- break;
- }
- --pEnd;
- }
- strcat(buf, "\\Data\\INI\\MemoryPools.ini");
-
- FILE* fp = fopen(buf, "r");
- if (fp)
- {
- char poolName[256];
- int initial, overflow;
- while (fgets(buf, _MAX_PATH, fp))
- {
- if (buf[0] == ';')
- continue;
- if (sscanf(buf, "%s %d %d", poolName, &initial, &overflow ) == 3)
- {
- for (PoolSizeRec* p = sizes; p->name != NULL; ++p)
- {
- if (stricmp(p->name, poolName) == 0)
- {
- // currently, these must be multiples of 4. so round up.
- p->initial = roundUpMemBound(initial);
- p->overflow = roundUpMemBound(overflow);
- break; // from for-p
- }
- }
- }
- }
- fclose(fp);
- }
-}
-
diff --git a/Generals/Code/GameEngine/Source/Common/System/GameMemoryNull.cpp b/Core/GameEngine/Source/Common/System/GameMemoryNull.cpp
similarity index 100%
rename from Generals/Code/GameEngine/Source/Common/System/GameMemoryNull.cpp
rename to Core/GameEngine/Source/Common/System/GameMemoryNull.cpp
diff --git a/Generals/Code/GameEngine/CMakeLists.txt b/Generals/Code/GameEngine/CMakeLists.txt
index 41fd59b68b8..64236aa60d3 100644
--- a/Generals/Code/GameEngine/CMakeLists.txt
+++ b/Generals/Code/GameEngine/CMakeLists.txt
@@ -42,7 +42,7 @@ set(GAMEENGINE_SRC
# Include/Common/GameDefines.h
Include/Common/GameEngine.h
Include/Common/GameLOD.h
- Include/Common/GameMemory.h
+# Include/Common/GameMemory.h
# Include/Common/GameMusic.h
# Include/Common/GameSounds.h
Include/Common/GameSpyMiscPreferences.h
@@ -1060,14 +1060,16 @@ set(GAMEENGINE_SRC
if(RTS_GAMEMEMORY_ENABLE)
# Uses the original Game Memory implementation.
list(APPEND GAMEENGINE_SRC
- Source/Common/System/GameMemory.cpp
- Source/Common/System/MemoryInit.cpp
+# Source/Common/System/GameMemory.cpp
+# Source/Common/System/GameMemoryInitDMA_Generals.inl
+# Source/Common/System/GameMemoryInitPools_Generals.inl
+# Source/Common/System/MemoryInit.cpp
)
else()
# Uses the null implementation when disabled.
list(APPEND GAMEENGINE_SRC
- Source/Common/System/GameMemoryNull.cpp
- Include/Common/GameMemoryNull.h
+# Source/Common/System/GameMemoryNull.cpp
+# Include/Common/GameMemoryNull.h
)
endif()
diff --git a/Generals/Code/GameEngine/Include/Common/GameMemory.h b/Generals/Code/GameEngine/Include/Common/GameMemory.h
deleted file mode 100644
index b069822943d..00000000000
--- a/Generals/Code/GameEngine/Include/Common/GameMemory.h
+++ /dev/null
@@ -1,919 +0,0 @@
-/*
-** Command & Conquer Generals(tm)
-** Copyright 2025 Electronic Arts Inc.
-**
-** This program is free software: you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation, either version 3 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program. If not, see .
-*/
-
-////////////////////////////////////////////////////////////////////////////////
-// //
-// (c) 2001-2003 Electronic Arts Inc. //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
-// FILE: Memory.h
-//-----------------------------------------------------------------------------
-//
-// Westwood Studios Pacific.
-//
-// Confidential Information
-// Copyright (C); 2001 - All Rights Reserved
-//
-//-----------------------------------------------------------------------------
-//
-// Project: RTS3
-//
-// File name: Memory.h
-//
-// Created: Steven Johnson, August 2001
-//
-// Desc: Memory manager
-//
-//-----------------------------------------------------------------------------
-///////////////////////////////////////////////////////////////////////////////
-
-#pragma once
-
-#ifndef _GAME_MEMORY_H_
-#define _GAME_MEMORY_H_
-
-// Turn off memory pool checkpointing for now.
-#ifndef DISABLE_MEMORYPOOL_CHECKPOINTING
- #define DISABLE_MEMORYPOOL_CHECKPOINTING 1
-#endif
-
-#if defined(RTS_DEBUG) && !defined(MEMORYPOOL_DEBUG_CUSTOM_NEW) && !defined(DISABLE_MEMORYPOOL_DEBUG_CUSTOM_NEW)
- #define MEMORYPOOL_DEBUG_CUSTOM_NEW
-#endif
-
-//#if defined(RTS_DEBUG) && !defined(MEMORYPOOL_DEBUG) && !defined(DISABLE_MEMORYPOOL_DEBUG)
-#if defined(RTS_DEBUG) && !defined(MEMORYPOOL_DEBUG) && !defined(DISABLE_MEMORYPOOL_DEBUG)
- #define MEMORYPOOL_DEBUG
-#endif
-
-// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
-
-#include
-#include
-#ifdef MEMORYPOOL_OVERRIDE_MALLOC
- #include
-#endif
-
-// USER INCLUDES //////////////////////////////////////////////////////////////
-
-#include "Lib/BaseType.h"
-#include "Common/Debug.h"
-#include "Common/Errors.h"
-
-// MACROS //////////////////////////////////////////////////////////////////
-
-#ifdef MEMORYPOOL_DEBUG
-
- // by default, enable free-block-retention for checkpointing in debug mode
- #if !defined(DISABLE_MEMORYPOOL_CHECKPOINTING) || DISABLE_MEMORYPOOL_CHECKPOINTING == 0
- #define MEMORYPOOL_CHECKPOINTING
- #endif
-
- // by default, enable bounding walls in debug mode (unless we have specifically disabled them)
- #ifndef DISABLE_MEMORYPOOL_BOUNDINGWALL
- #define MEMORYPOOL_BOUNDINGWALL
- #endif
-
- #if !defined(MEMORYPOOL_STACKTRACE) && !defined(DISABLE_MEMORYPOOL_STACKTRACE)
- #define MEMORYPOOL_STACKTRACE
- #endif
-
- // flags for the memory-report options.
- enum
- {
-
-#ifdef MEMORYPOOL_CHECKPOINTING
- // ------------------------------------------------------
- // you usually won't use the _REPORT bits directly; see below for more convenient combinations.
-
- // you must set at least one of the 'allocate' bits.
- _REPORT_CP_ALLOCATED_BEFORE = 0x0001,
- _REPORT_CP_ALLOCATED_BETWEEN = 0x0002,
- _REPORT_CP_ALLOCATED_DONTCARE = (_REPORT_CP_ALLOCATED_BEFORE|_REPORT_CP_ALLOCATED_BETWEEN),
-
- // you must set at least one of the 'freed' bits.
- _REPORT_CP_FREED_BEFORE = 0x0010,
- _REPORT_CP_FREED_BETWEEN = 0x0020,
- _REPORT_CP_FREED_NEVER = 0x0040, // ie, still in existence
- _REPORT_CP_FREED_DONTCARE = (_REPORT_CP_FREED_BEFORE|_REPORT_CP_FREED_BETWEEN|_REPORT_CP_FREED_NEVER),
- // ------------------------------------------------------
-#endif // MEMORYPOOL_CHECKPOINTING
-
-#ifdef MEMORYPOOL_CHECKPOINTING
- /** display the stacktrace for allocation location for all blocks found.
- this bit may be mixed-n-matched with any other flag.
- */
- REPORT_CP_STACKTRACE = 0x0100,
-#endif
-
- /** display stats for each pool, in addition to each block.
- (this is useful for finding suitable allocation counts for the pools.)
- this bit may be mixed-n-matched with any other flag.
- */
- REPORT_POOLINFO = 0x0200,
-
- /** report on the overall memory situation (including all pools and dma's).
- this bit may be mixed-n-matched with any other flag.
- */
- REPORT_FACTORYINFO = 0x0400,
-
- /** report on pools that have overflowed their initial allocation.
- this bit may be mixed-n-matched with any other flag.
- */
- REPORT_POOL_OVERFLOW = 0x0800,
-
- /** simple-n-cheap leak checking */
- REPORT_SIMPLE_LEAKS = 0x1000,
-
-#ifdef MEMORYPOOL_CHECKPOINTING
- /** report on blocks that were allocated between the checkpoints.
- (don't care if they were freed or not.)
- */
- REPORT_CP_ALLOCATES = (_REPORT_CP_ALLOCATED_BETWEEN | _REPORT_CP_FREED_DONTCARE),
-
- /** report on blocks that were freed between the checkpoints.
- (don't care when they were allocated.)
- */
- REPORT_CP_FREES = (_REPORT_CP_ALLOCATED_DONTCARE | _REPORT_CP_FREED_BETWEEN),
-
- /** report on blocks that were allocated between the checkpoints, and still exist
- (note that this reports *potential* leaks -- some such blocks may be desired)
- */
- REPORT_CP_LEAKS = (_REPORT_CP_ALLOCATED_BETWEEN | _REPORT_CP_FREED_NEVER),
-
- /** report on blocks that existed before checkpoint #1 and still exist now.
- */
- REPORT_CP_LONGTERM = (_REPORT_CP_ALLOCATED_BEFORE | _REPORT_CP_FREED_NEVER),
-
- /** report on blocks that were allocated-and-freed between the checkpoints.
- */
- REPORT_CP_TRANSIENT = (_REPORT_CP_ALLOCATED_BETWEEN | _REPORT_CP_FREED_BETWEEN),
-
- /** report on all blocks that currently exist
- */
- REPORT_CP_EXISTING = (_REPORT_CP_ALLOCATED_BEFORE | _REPORT_CP_ALLOCATED_BETWEEN | _REPORT_CP_FREED_NEVER),
-
- /** report on all blocks that have ever existed (!) (or at least, since the last call
- to debugResetCheckpoints)
- */
- REPORT_CP_ALL = (_REPORT_CP_ALLOCATED_DONTCARE | _REPORT_CP_FREED_DONTCARE)
-#endif // MEMORYPOOL_CHECKPOINTING
-
- };
-
-#endif // MEMORYPOOL_DEBUG
-
-// TheSuperHackers @build xezon 30/03/2025 Define DISABLE_GAMEMEMORY to use a null implementations for Game Memory.
-// Useful for address sanitizer checks and other investigations.
-// Is included below the macros so that memory pool debug code can still be used.
-#ifdef DISABLE_GAMEMEMORY
-#include "GameMemoryNull.h"
-#else
-
-#ifdef MEMORYPOOL_DEBUG
-
- #define DECLARE_LITERALSTRING_ARG1 const char * debugLiteralTagString
- #define PASS_LITERALSTRING_ARG1 debugLiteralTagString
- #define DECLARE_LITERALSTRING_ARG2 , const char * debugLiteralTagString
- #define PASS_LITERALSTRING_ARG2 , debugLiteralTagString
-
- #define MP_LOC_SUFFIX /*" [" DEBUG_FILENLINE "]"*/
-
- #define allocateBlock(ARGLITERAL) allocateBlockImplementation(ARGLITERAL MP_LOC_SUFFIX)
- #define allocateBlockDoNotZero(ARGLITERAL) allocateBlockDoNotZeroImplementation(ARGLITERAL MP_LOC_SUFFIX)
- #define allocateBytes(ARGCOUNT,ARGLITERAL) allocateBytesImplementation(ARGCOUNT, ARGLITERAL MP_LOC_SUFFIX)
- #define allocateBytesDoNotZero(ARGCOUNT,ARGLITERAL) allocateBytesDoNotZeroImplementation(ARGCOUNT, ARGLITERAL MP_LOC_SUFFIX)
- #define newInstanceDesc(ARGCLASS,ARGLITERAL) new(ARGCLASS::ARGCLASS##_GLUE_NOT_IMPLEMENTED, ARGLITERAL MP_LOC_SUFFIX) ARGCLASS
- #define newInstance(ARGCLASS) new(ARGCLASS::ARGCLASS##_GLUE_NOT_IMPLEMENTED, __FILE__) ARGCLASS
-
-#else
-
- #define DECLARE_LITERALSTRING_ARG1
- #define PASS_LITERALSTRING_ARG1
- #define DECLARE_LITERALSTRING_ARG2
- #define PASS_LITERALSTRING_ARG2
-
- #define allocateBlock(ARGLITERAL) allocateBlockImplementation()
- #define allocateBlockDoNotZero(ARGLITERAL) allocateBlockDoNotZeroImplementation()
- #define allocateBytes(ARGCOUNT,ARGLITERAL) allocateBytesImplementation(ARGCOUNT)
- #define allocateBytesDoNotZero(ARGCOUNT,ARGLITERAL) allocateBytesDoNotZeroImplementation(ARGCOUNT)
- #define newInstanceDesc(ARGCLASS,ARGLITERAL) new(ARGCLASS::ARGCLASS##_GLUE_NOT_IMPLEMENTED) ARGCLASS
- #define newInstance(ARGCLASS) new(ARGCLASS::ARGCLASS##_GLUE_NOT_IMPLEMENTED) ARGCLASS
-
-#endif
-
-// FORWARD REFERENCES /////////////////////////////////////////////////////////
-
-class MemoryPoolSingleBlock;
-class MemoryPoolBlob;
-class MemoryPool;
-class MemoryPoolFactory;
-class DynamicMemoryAllocator;
-class BlockCheckpointInfo;
-
-// TYPE DEFINES ///////////////////////////////////////////////////////////////
-
-// ----------------------------------------------------------------------------
-/**
- This class is purely a convenience used to pass optional arguments to initMemoryManager(),
- and by extension, to createDynamicMemoryAllocator(). You can specify how many sub-pools you
- want, what size each is, what the allocation counts are to be, etc. Most apps will
- construct an array of these to pass to initMemoryManager() and never use it elsewhere.
-*/
-struct PoolInitRec
-{
- const char *poolName; ///< name of the pool; by convention, "dmaPool_XXX" where XXX is allocationSize
- Int allocationSize; ///< size, in bytes, of the pool.
- Int initialAllocationCount; ///< initial number of blocks to allocate.
- Int overflowAllocationCount; ///< when the pool runs out of space, allocate more blocks in this increment
-};
-
-enum
-{
- MAX_DYNAMICMEMORYALLOCATOR_SUBPOOLS = 8 ///< The max number of subpools allowed in a DynamicMemoryAllocator
-};
-
-#ifdef MEMORYPOOL_CHECKPOINTING
-// ----------------------------------------------------------------------------
-/**
- This class exists purely for coding convenience, and should never be used by external code.
- It simply allows MemoryPool and DynamicMemoryAllocator to share checkpoint-related
- code in a seamless way.
-*/
-class Checkpointable
-{
-private:
- BlockCheckpointInfo *m_firstCheckpointInfo; ///< head of the linked list of checkpoint infos for this pool/dma
- Bool m_cpiEverFailed; ///< flag to detect if we ran out of memory accumulating checkpoint info.
-
-protected:
-
- Checkpointable();
- ~Checkpointable();
-
- /// create a new checkpoint info and add it to the list.
- BlockCheckpointInfo *debugAddCheckpointInfo(
- const char *debugLiteralTagString,
- Int allocCheckpoint,
- Int blockSize
- );
-
-public:
- /// dump a checkpoint report to logfile
- void debugCheckpointReport(Int flags, Int startCheckpoint, Int endCheckpoint, const char *poolName);
- /// reset all the checkpoints for this pool/dma
- void debugResetCheckpoints();
-};
-#endif
-
-// ----------------------------------------------------------------------------
-/**
- A MemoryPool provides a way to efficiently allocate objects of the same (or similar)
- size. We allocate large a large chunk of memory (a "blob") and subdivide it into
- even-size chunks, doling these out as needed. If the first blob gets full, we allocate
- additional blobs as necessary. A given pool can allocate blocks of only one size;
- if you need a different size, you should use a different pool.
-*/
-class MemoryPool
-#ifdef MEMORYPOOL_CHECKPOINTING
- : public Checkpointable
-#endif
-{
-private:
-
- MemoryPoolFactory *m_factory; ///< the factory that created us
- MemoryPool *m_nextPoolInFactory; ///< linked list node, managed by factory
- const char *m_poolName; ///< name of this pool. (literal string; must not be freed)
- Int m_allocationSize; ///< size of the blocks allocated by this pool, in bytes
- Int m_initialAllocationCount; ///< number of blocks to be allocated in initial blob
- Int m_overflowAllocationCount; ///< number of blocks to be allocated in any subsequent blob(s)
- Int m_usedBlocksInPool; ///< total number of blocks in use in the pool.
- Int m_totalBlocksInPool; ///< total number of blocks in all blobs of this pool (used or not).
- Int m_peakUsedBlocksInPool; ///< high-water mark of m_usedBlocksInPool
- MemoryPoolBlob *m_firstBlob; ///< head of linked list: first blob for this pool.
- MemoryPoolBlob *m_lastBlob; ///< tail of linked list: last blob for this pool. (needed for efficiency)
- MemoryPoolBlob *m_firstBlobWithFreeBlocks; ///< first blob in this pool that has at least one unallocated block.
-
-private:
- /// create a new blob with the given number of blocks.
- MemoryPoolBlob* createBlob(Int allocationCount);
-
- /// destroy a blob.
- Int freeBlob(MemoryPoolBlob *blob);
-
-public:
-
- // 'public' funcs that are really only for use by MemoryPoolFactory
- MemoryPool *getNextPoolInList(); ///< return next pool in linked list
- void addToList(MemoryPool **pHead); ///< add this pool to head of the linked list
- void removeFromList(MemoryPool **pHead); ///< remove this pool from the linked list
- #ifdef MEMORYPOOL_DEBUG
- static void debugPoolInfoReport( MemoryPool *pool, FILE *fp = NULL ); ///< dump a report about this pool to the logfile
- const char *debugGetBlockTagString(void *pBlock); ///< return the tagstring for the given block (assumed to belong to this pool)
- void debugMemoryVerifyPool(); ///< perform internal consistency check on this pool.
- Int debugPoolReportLeaks( const char* owner );
- #endif
- #ifdef MEMORYPOOL_CHECKPOINTING
- void debugResetCheckpoints(); ///< throw away all checkpoint information for this pool.
- #endif
-
-public:
-
- MemoryPool();
-
- /// initialize the given memory pool.
- void init(MemoryPoolFactory *factory, const char *poolName, Int allocationSize, Int initialAllocationCount, Int overflowAllocationCount);
-
- ~MemoryPool();
-
- /// allocate a block from this pool. (don't call directly; use allocateBlock() macro)
- void *allocateBlockImplementation(DECLARE_LITERALSTRING_ARG1);
-
- /// same as allocateBlockImplementation, but memory returned is not zeroed
- void *allocateBlockDoNotZeroImplementation(DECLARE_LITERALSTRING_ARG1);
-
- /// free the block. it is OK to pass null.
- void freeBlock(void *pMem);
-
- /// return the factory that created (and thus owns) this pool.
- MemoryPoolFactory *getOwningFactory();
-
- /// return the name of this pool. the result is a literal string and must not be freed.
- const char *getPoolName();
-
- /// return the block allocation size of this pool.
- Int getAllocationSize();
-
- /// return the number of free (available) blocks in this pool.
- Int getFreeBlockCount();
-
- /// return the number of blocks in use in this pool.
- Int getUsedBlockCount();
-
- /// return the total number of blocks in this pool. [ == getFreeBlockCount() + getUsedBlockCount() ]
- Int getTotalBlockCount();
-
- /// return the high-water mark for getUsedBlockCount()
- Int getPeakBlockCount();
-
- /// return the initial allocation count for this pool
- Int getInitialBlockCount();
-
- Int countBlobsInPool();
-
- /// if this pool has any empty blobs, return them to the system.
- Int releaseEmpties();
-
- /// destroy all blocks and blobs in this pool.
- void reset();
-
- #ifdef MEMORYPOOL_DEBUG
- /// return true iff this block was allocated by this pool.
- Bool debugIsBlockInPool(void *pBlock);
- #endif
-};
-
-// ----------------------------------------------------------------------------
-/**
- The DynamicMemoryAllocator class is used to handle unpredictably-sized
- allocation requests. It basically allocates a number of (private) MemoryPools,
- then routes request to the smallest-size pool that will satisfy the request.
- (Requests too large for any of the pool are routed to the system memory allocator.)
- You should normally use this in place of malloc/free or (global) new/delete.
-*/
-class DynamicMemoryAllocator
-#ifdef MEMORYPOOL_CHECKPOINTING
- : public Checkpointable
-#endif
-{
-private:
- MemoryPoolFactory *m_factory; ///< the factory that created us
- DynamicMemoryAllocator *m_nextDmaInFactory; ///< linked list node, managed by factory
- Int m_numPools; ///< number of subpools (up to MAX_DYNAMICMEMORYALLOCATOR_SUBPOOLS)
- Int m_usedBlocksInDma; ///< total number of blocks allocated, from subpools and "raw"
- MemoryPool *m_pools[MAX_DYNAMICMEMORYALLOCATOR_SUBPOOLS]; ///< the subpools
- MemoryPoolSingleBlock *m_rawBlocks; ///< linked list of "raw" blocks allocated directly from system
-
- /// return the best pool for the given allocSize, or null if none are suitable
- MemoryPool *findPoolForSize(Int allocSize);
-
-public:
-
- // 'public' funcs that are really only for use by MemoryPoolFactory
-
- DynamicMemoryAllocator *getNextDmaInList(); ///< return next dma in linked list
- void addToList(DynamicMemoryAllocator **pHead); ///< add this dma to the list
- void removeFromList(DynamicMemoryAllocator **pHead); ///< remove this dma from the list
- #ifdef MEMORYPOOL_DEBUG
- Int debugCalcRawBlockBytes(Int *numBlocks); ///< calculate the number of bytes in "raw" (non-subpool) blocks
- void debugMemoryVerifyDma(); ///< perform internal consistency check
- const char *debugGetBlockTagString(void *pBlock); ///< return the tagstring for the given block (assumed to belong to this dma)
- void debugDmaInfoReport( FILE *fp = NULL ); ///< dump a report about this pool to the logfile
- Int debugDmaReportLeaks();
- #endif
- #ifdef MEMORYPOOL_CHECKPOINTING
- void debugResetCheckpoints(); ///< toss all checkpoint information
- #endif
-
-public:
-
- DynamicMemoryAllocator();
-
- /// initialize the dma. pass 0/null for numSubPool/parms to get some reasonable default subpools.
- void init(MemoryPoolFactory *factory, Int numSubPools, const PoolInitRec pParms[]);
-
- ~DynamicMemoryAllocator();
-
- /// allocate bytes from this pool. (don't call directly; use allocateBytes() macro)
- void *allocateBytesImplementation(Int numBytes DECLARE_LITERALSTRING_ARG2);
-
- /// like allocateBytesImplementation, but zeroes the memory before returning
- void *allocateBytesDoNotZeroImplementation(Int numBytes DECLARE_LITERALSTRING_ARG2);
-
-#ifdef MEMORYPOOL_DEBUG
- void debugIgnoreLeaksForThisBlock(void* pBlockPtr);
-#endif
-
- /// free the bytes. (assumes allocated by this dma.)
- void freeBytes(void* pMem);
-
- /**
- return the actual number of bytes that would be allocated
- if you tried to allocate the given size. (It will generally be slightly
- larger than you request.) This lets you use extra space if you're gonna get it anyway...
- The idea is that you will call this before doing a memory allocation, to see if
- you got any extra "bonus" space.
- */
- Int getActualAllocationSize(Int numBytes);
-
- /// destroy all allocations performed by this DMA.
- void reset();
-
- Int getDmaMemoryPoolCount() const { return m_numPools; }
- MemoryPool* getNthDmaMemoryPool(Int i) const { return m_pools[i]; }
-
- #ifdef MEMORYPOOL_DEBUG
-
- /// return true iff this block was allocated by this dma
- Bool debugIsBlockInDma(void *pBlock);
-
- /// return true iff the pool is a subpool of this dma
- Bool debugIsPoolInDma(MemoryPool *pool);
-
- #endif // MEMORYPOOL_DEBUG
-};
-
-// ----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-enum { MAX_SPECIAL_USED = 256 };
-#endif
-
-// ----------------------------------------------------------------------------
-/**
- The class that manages all the MemoryPools and DynamicMemoryAllocators.
- Usually you will create exactly one of these (TheMemoryPoolFactory)
- and use it for everything.
-*/
-class MemoryPoolFactory
-{
-private:
- MemoryPool *m_firstPoolInFactory; ///< linked list of pools
- DynamicMemoryAllocator *m_firstDmaInFactory; ///< linked list of dmas
-#ifdef MEMORYPOOL_CHECKPOINTING
- Int m_curCheckpoint; ///< most recent checkpoint value
-#endif
-#ifdef MEMORYPOOL_DEBUG
- Int m_usedBytes; ///< total bytes in use
- Int m_physBytes; ///< total bytes allocated to all pools (includes unused blocks)
- Int m_peakUsedBytes; ///< high-water mark of m_usedBytes
- Int m_peakPhysBytes; ///< high-water mark of m_physBytes
- Int m_usedBytesSpecial[MAX_SPECIAL_USED];
- Int m_usedBytesSpecialPeak[MAX_SPECIAL_USED];
- Int m_physBytesSpecial[MAX_SPECIAL_USED];
- Int m_physBytesSpecialPeak[MAX_SPECIAL_USED];
-#endif
-
-public:
-
- // 'public' funcs that are really only for use by MemoryPool and friends
- #ifdef MEMORYPOOL_DEBUG
- /// adjust the usedBytes and physBytes variables by the given amoun ts.
- void adjustTotals(const char* tagString, Int usedDelta, Int physDelta);
- #endif
- #ifdef MEMORYPOOL_CHECKPOINTING
- /// return the current checkpoint value.
- Int getCurCheckpoint() { return m_curCheckpoint; }
- #endif
-
-public:
-
- MemoryPoolFactory();
- void init();
- ~MemoryPoolFactory();
-
- /// create a new memory pool with the given settings. if a pool with the given name already exists, return it.
- MemoryPool *createMemoryPool(const PoolInitRec *parms);
-
- /// overloaded version of createMemoryPool with explicit parms.
- MemoryPool *createMemoryPool(const char *poolName, Int allocationSize, Int initialAllocationCount, Int overflowAllocationCount);
-
- /// return the pool with the given name. if no such pool exists, return null.
- MemoryPool *findMemoryPool(const char *poolName);
-
- /// destroy the given pool.
- void destroyMemoryPool(MemoryPool *pMemoryPool);
-
- /// create a DynamicMemoryAllocator with subpools with the given parms.
- DynamicMemoryAllocator *createDynamicMemoryAllocator(Int numSubPools, const PoolInitRec pParms[]);
-
- /// destroy the given DynamicMemoryAllocator.
- void destroyDynamicMemoryAllocator(DynamicMemoryAllocator *dma);
-
- /// destroy the contents of all pools and dmas. (the pools and dma's are not destroyed, just reset)
- void reset();
-
- void memoryPoolUsageReport( const char* filename, FILE *appendToFileInstead = NULL );
-
- #ifdef MEMORYPOOL_DEBUG
-
- /// perform internal consistency checking
- void debugMemoryVerify();
-
- /// return true iff the block was allocated by any pool or dma owned by this factory.
- Bool debugIsBlockInAnyPool(void *pBlock);
-
- /// return the tag string for the block.
- const char *debugGetBlockTagString(void *pBlock);
-
- /// dump a report with the given options to the logfile.
- void debugMemoryReport(Int flags, Int startCheckpoint, Int endCheckpoint, FILE *fp = NULL );
-
- void debugSetInitFillerIndex(Int index);
-
- #endif
- #ifdef MEMORYPOOL_CHECKPOINTING
-
- /// set a new checkpoint.
- Int debugSetCheckpoint();
-
- /// reset all checkpoint information.
- void debugResetCheckpoints();
-
- #endif
-};
-
-// how many bytes are we allowed to 'waste' per pool allocation before the debug code starts yelling at us...
-#define MEMORY_POOL_OBJECT_ALLOCATION_SLOP 16
-
-// ----------------------------------------------------------------------------
-#define GCMP_FIND(ARGCLASS, ARGPOOLNAME) \
-private: \
- static MemoryPool *getClassMemoryPool() \
- { \
- /* \
- Note that this static variable will be initialized exactly once: the first time \
- control flows over this section of code. This allows us to neatly resolve the \
- order-of-execution problem for static variables, ensuring this is not executed \
- prior to the initialization of TheMemoryPoolFactory. \
- */ \
- DEBUG_ASSERTCRASH(TheMemoryPoolFactory, ("TheMemoryPoolFactory is NULL")); \
- static MemoryPool *The##ARGCLASS##Pool = TheMemoryPoolFactory->findMemoryPool(ARGPOOLNAME); \
- DEBUG_ASSERTCRASH(The##ARGCLASS##Pool, ("Pool \"%s\" not found (did you set it up in initMemoryPools?)", ARGPOOLNAME)); \
- DEBUG_ASSERTCRASH(The##ARGCLASS##Pool->getAllocationSize() >= sizeof(ARGCLASS), ("Pool \"%s\" is too small for this class (currently %d, need %d)", ARGPOOLNAME, The##ARGCLASS##Pool->getAllocationSize(), sizeof(ARGCLASS))); \
- DEBUG_ASSERTCRASH(The##ARGCLASS##Pool->getAllocationSize() <= sizeof(ARGCLASS)+MEMORY_POOL_OBJECT_ALLOCATION_SLOP, ("Pool \"%s\" is too large for this class (currently %d, need %d)", ARGPOOLNAME, The##ARGCLASS##Pool->getAllocationSize(), sizeof(ARGCLASS))); \
- return The##ARGCLASS##Pool; \
- }
-
-// ----------------------------------------------------------------------------
-#define GCMP_CREATE(ARGCLASS, ARGPOOLNAME, ARGINITIAL, ARGOVERFLOW) \
-private: \
- static MemoryPool *getClassMemoryPool() \
- { \
- /* \
- Note that this static variable will be initialized exactly once: the first time \
- control flows over this section of code. This allows us to neatly resolve the \
- order-of-execution problem for static variables, ensuring this is not executed \
- prior to the initialization of TheMemoryPoolFactory. \
- */ \
- DEBUG_ASSERTCRASH(TheMemoryPoolFactory, ("TheMemoryPoolFactory is NULL")); \
- static MemoryPool *The##ARGCLASS##Pool = TheMemoryPoolFactory->createMemoryPool(ARGPOOLNAME, sizeof(ARGCLASS), ARGINITIAL, ARGOVERFLOW); \
- DEBUG_ASSERTCRASH(The##ARGCLASS##Pool, ("Pool \"%s\" not found (did you set it up in initMemoryPools?)", ARGPOOLNAME)); \
- DEBUG_ASSERTCRASH(The##ARGCLASS##Pool->getAllocationSize() >= sizeof(ARGCLASS), ("Pool \"%s\" is too small for this class (currently %d, need %d)", ARGPOOLNAME, The##ARGCLASS##Pool->getAllocationSize(), sizeof(ARGCLASS))); \
- DEBUG_ASSERTCRASH(The##ARGCLASS##Pool->getAllocationSize() <= sizeof(ARGCLASS)+MEMORY_POOL_OBJECT_ALLOCATION_SLOP, ("Pool \"%s\" is too large for this class (currently %d, need %d)", ARGPOOLNAME, The##ARGCLASS##Pool->getAllocationSize(), sizeof(ARGCLASS))); \
- return The##ARGCLASS##Pool; \
- }
-
-// ----------------------------------------------------------------------------
-#define MEMORY_POOL_GLUE_WITHOUT_GCMP(ARGCLASS) \
-protected: \
- virtual ~ARGCLASS(); \
-public: \
- enum ARGCLASS##MagicEnum { ARGCLASS##_GLUE_NOT_IMPLEMENTED = 0 }; \
-public: \
- inline void *operator new(size_t s, ARGCLASS##MagicEnum e DECLARE_LITERALSTRING_ARG2) \
- { \
- DEBUG_ASSERTCRASH(s == sizeof(ARGCLASS), ("The wrong operator new is being called; ensure all objects in the hierarchy have MemoryPoolGlue set up correctly")); \
- return ARGCLASS::getClassMemoryPool()->allocateBlockImplementation(PASS_LITERALSTRING_ARG1); \
- } \
-public: \
- /* \
- Note that this delete operator can't be called directly; it is called \
- only if the analogous new operator is called, AND the constructor \
- throws an exception... \
- */ \
- inline void operator delete(void *p, ARGCLASS##MagicEnum e DECLARE_LITERALSTRING_ARG2) \
- { \
- ARGCLASS::getClassMemoryPool()->freeBlock(p); \
- } \
-protected: \
- /* \
- Make normal new and delete protected, so they can't be called by the outside world. \
- Note that delete is funny, in that it can still be called by the class itself; \
- this is safe but not recommended, for consistency purposes. More problematically, \
- it can be called by another class that has declared itself 'friend' to us. \
- In theory, this shouldn't work, since it may not use the right operator-delete, \
- and thus the wrong memory pool; in practice, it seems the right delete IS called \
- in MSVC -- it seems to make operator delete virtual if the destructor is also virtual. \
- At any rate, this is undocumented behavior as far as I can tell, so we put a big old \
- crash into operator delete telling people to do the right thing and call deleteInstance \
- instead -- it'd be nice if we could catch this at compile time, but catching it at \
- runtime seems to be the best we can do... \
- */ \
- inline void *operator new(size_t s) \
- { \
- DEBUG_CRASH(("This operator new should normally never be called... please use new(char*) instead.")); \
- DEBUG_ASSERTCRASH(s == sizeof(ARGCLASS), ("The wrong operator new is being called; ensure all objects in the hierarchy have MemoryPoolGlue set up correctly")); \
- throw ERROR_BUG; \
- return 0; \
- } \
- inline void operator delete(void *p) \
- { \
- DEBUG_CRASH(("Please call deleteInstance instead of delete.")); \
- ARGCLASS::getClassMemoryPool()->freeBlock(p); \
- } \
-private: \
- virtual MemoryPool *getObjectMemoryPool() \
- { \
- return ARGCLASS::getClassMemoryPool(); \
- } \
-public: /* include this line at the end to reset visibility to 'public' */
-
-// ----------------------------------------------------------------------------
-#define MEMORY_POOL_GLUE(ARGCLASS, ARGPOOLNAME) \
- MEMORY_POOL_GLUE_WITHOUT_GCMP(ARGCLASS) \
- GCMP_FIND(ARGCLASS, ARGPOOLNAME)
-
-// ----------------------------------------------------------------------------
-#define MEMORY_POOL_GLUE_WITH_EXPLICIT_CREATE(ARGCLASS, ARGPOOLNAME, ARGINITIAL, ARGOVERFLOW) \
- MEMORY_POOL_GLUE_WITHOUT_GCMP(ARGCLASS) \
- GCMP_CREATE(ARGCLASS, ARGPOOLNAME, ARGINITIAL, ARGOVERFLOW)
-
-// ----------------------------------------------------------------------------
-#define MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(ARGCLASS, ARGPOOLNAME) \
- MEMORY_POOL_GLUE_WITHOUT_GCMP(ARGCLASS) \
- GCMP_CREATE(ARGCLASS, ARGPOOLNAME, -1, -1)
-
-// ----------------------------------------------------------------------------
-// this is the version for an Abstract Base Class, which will never be instantiated...
-#define MEMORY_POOL_GLUE_ABC(ARGCLASS) \
-protected: \
- virtual ~ARGCLASS(); \
-public: \
- enum ARGCLASS##MagicEnum { ARGCLASS##_GLUE_NOT_IMPLEMENTED = 0 }; \
-protected: \
- inline void *operator new(size_t s, ARGCLASS##MagicEnum e DECLARE_LITERALSTRING_ARG2) \
- { \
- DEBUG_CRASH(("this should be impossible to call (abstract base class)")); \
- DEBUG_ASSERTCRASH(s == sizeof(ARGCLASS), ("The wrong operator new is being called; ensure all objects in the hierarchy have MemoryPoolGlue set up correctly")); \
- throw ERROR_BUG; \
- return 0; \
- } \
-protected: \
- inline void operator delete(void *p, ARGCLASS##MagicEnum e DECLARE_LITERALSTRING_ARG2) \
- { \
- DEBUG_CRASH(("this should be impossible to call (abstract base class)")); \
- } \
-protected: \
- inline void *operator new(size_t s) \
- { \
- DEBUG_CRASH(("this should be impossible to call (abstract base class)")); \
- DEBUG_ASSERTCRASH(s == sizeof(ARGCLASS), ("The wrong operator new is being called; ensure all objects in the hierarchy have MemoryPoolGlue set up correctly")); \
- throw ERROR_BUG; \
- return 0; \
- } \
- inline void operator delete(void *p) \
- { \
- DEBUG_CRASH(("this should be impossible to call (abstract base class)")); \
- } \
-private: \
- virtual MemoryPool *getObjectMemoryPool() \
- { \
- throw ERROR_BUG; \
- return 0; \
- } \
-public: /* include this line at the end to reset visibility to 'public' */
-
-
-
-// ----------------------------------------------------------------------------
-/**
- This class is provided as a simple and safe way to integrate C++ object allocation
- into MemoryPool usage. To use it, you must have your class inherit from
- MemoryPoolObject, then put the macro MEMORY_POOL_GLUE(MyClassName, "MyPoolName")
- at the start of your class definition. (This does not create the pool itself -- you
- must create that manually using MemoryPoolFactory::createMemoryPool)
-*/
-class MemoryPoolObject
-{
-protected:
-
- /** ensure that all destructors are virtual */
- virtual ~MemoryPoolObject() { }
-
-protected:
- inline void *operator new(size_t s) { DEBUG_CRASH(("This should be impossible")); return 0; }
- inline void operator delete(void *p) { DEBUG_CRASH(("This should be impossible")); }
-
-protected:
-
- virtual MemoryPool *getObjectMemoryPool() = 0;
-
-public:
-
- static void deleteInstanceInternal(MemoryPoolObject* mpo)
- {
- if (mpo)
- {
- MemoryPool *pool = mpo->getObjectMemoryPool(); // save this, since the dtor will nuke our vtbl
- mpo->~MemoryPoolObject(); // it's virtual, so the right one will be called.
- pool->freeBlock((void *)mpo);
- }
- }
-};
-
-inline void deleteInstance(MemoryPoolObject* mpo)
-{
- MemoryPoolObject::deleteInstanceInternal(mpo);
-}
-
-
-// INLINING ///////////////////////////////////////////////////////////////////
-
-// ----------------------------------------------------------------------------
-inline MemoryPoolFactory *MemoryPool::getOwningFactory() { return m_factory; }
-inline MemoryPool *MemoryPool::getNextPoolInList() { return m_nextPoolInFactory; }
-inline const char *MemoryPool::getPoolName() { return m_poolName; }
-inline Int MemoryPool::getAllocationSize() { return m_allocationSize; }
-inline Int MemoryPool::getFreeBlockCount() { return getTotalBlockCount() - getUsedBlockCount(); }
-inline Int MemoryPool::getUsedBlockCount() { return m_usedBlocksInPool; }
-inline Int MemoryPool::getTotalBlockCount() { return m_totalBlocksInPool; }
-inline Int MemoryPool::getPeakBlockCount() { return m_peakUsedBlocksInPool; }
-inline Int MemoryPool::getInitialBlockCount() { return m_initialAllocationCount; }
-
-// ----------------------------------------------------------------------------
-inline DynamicMemoryAllocator *DynamicMemoryAllocator::getNextDmaInList() { return m_nextDmaInFactory; }
-
-// EXTERNALS //////////////////////////////////////////////////////////////////
-
-/**
- Initialize the memory manager. Construct a new MemoryPoolFactory and
- DynamicMemoryAllocator and store 'em in the singletons of the relevant
- names.
-*/
-extern void initMemoryManager();
-
-/**
- return true if initMemoryManager() has been called.
- return false if only preMainInitMemoryManager() has been called.
-*/
-extern Bool isMemoryManagerOfficiallyInited();
-
-/**
- similar to initMemoryManager, but this should be used if the memory manager must be initialized
- prior to main() (e.g., from a static constructor). If preMainInitMemoryManager() is called prior
- to initMemoryManager(), then subsequent calls to either are quietly ignored, AS IS any subsequent
- call to shutdownMemoryManager() [since there's no safe way to ensure that shutdownMemoryManager
- will execute after all static destructors].
-
- (Note: this function is actually not externally visible, but is documented here for clarity.)
-*/
-/* extern void preMainInitMemoryManager(); */
-
-/**
- Shut down the memory manager. Throw away TheMemoryPoolFactory and
- TheDynamicMemoryAllocator.
-*/
-extern void shutdownMemoryManager();
-
-extern MemoryPoolFactory *TheMemoryPoolFactory;
-extern DynamicMemoryAllocator *TheDynamicMemoryAllocator;
-
-/**
- This function is declared in this header, but is not defined anywhere -- you must provide
- it in your code. It is called by initMemoryManager() or preMainInitMemoryManager() in order
- to get the specifics of the subpool for the dynamic memory allocator. (If you just want
- some defaults, set both return arguments to zero.) The reason for this odd setup is that
- we may need to init the memory manager prior to main() [due to static C++ ctors] and
- this allows us a way to get the necessary parameters.
-*/
-extern void userMemoryManagerGetDmaParms(Int *numSubPools, const PoolInitRec **pParms);
-
-/**
- This function is declared in this header, but is not defined anywhere -- you must provide
- it in your code. It is called by initMemoryManager() or preMainInitMemoryManager() in order
- to initialize the pools to be used. (You can define an empty function if you like.)
-*/
-extern void userMemoryManagerInitPools();
-
-/**
- This function is declared in this header, but is not defined anywhere -- you must provide
- it in your code. It is called by createMemoryPool to adjust the allocation size(s) for a
- given pool. Note that the counts are in-out parms!
-*/
-extern void userMemoryAdjustPoolSize(const char *poolName, Int& initialAllocationCount, Int& overflowAllocationCount);
-
-#ifdef __cplusplus
-
-#ifndef _OPERATOR_NEW_DEFINED_
-
- #define _OPERATOR_NEW_DEFINED_
-
- extern void * __cdecl operator new (size_t size);
- extern void __cdecl operator delete (void *p);
-
- extern void * __cdecl operator new[] (size_t size);
- extern void __cdecl operator delete[] (void *p);
-
- // additional overloads to account for VC/MFC funky versions
- extern void* __cdecl operator new(size_t nSize, const char *, int);
- extern void __cdecl operator delete(void *, const char *, int);
-
- extern void* __cdecl operator new[](size_t nSize, const char *, int);
- extern void __cdecl operator delete[](void *, const char *, int);
-
-#if defined(_MSC_VER) && _MSC_VER < 1300
- // additional overloads for 'placement new'
- //inline void* __cdecl operator new (size_t s, void *p) { return p; }
- //inline void __cdecl operator delete (void *, void *p) { }
- inline void* __cdecl operator new[] (size_t s, void *p) { return p; }
- inline void __cdecl operator delete[] (void *, void *p) { }
-#endif
-
-#endif
-
-#ifdef MEMORYPOOL_DEBUG_CUSTOM_NEW
- #define MSGNEW(MSG) new(MSG, 0)
- #define NEW new(__FILE__, __LINE__)
-#else
- #define MSGNEW(MSG) new
- #define NEW new
-#endif
-
-#endif
-
-class STLSpecialAlloc
-{
-public:
- static void* allocate(size_t __n);
- static void deallocate(void* __p, size_t);
-};
-
-#endif //DISABLE_GAMEMEMORY
-
-
-// ----------------------------------------------------------------------------
-/**
- A simple utility class to ensure exception safety; this holds a MemoryPoolObject
- and deletes it in its destructor. Especially useful for iterators!
-*/
-class MemoryPoolObjectHolder
-{
-private:
- MemoryPoolObject *m_mpo;
-public:
- MemoryPoolObjectHolder(MemoryPoolObject *mpo = NULL) : m_mpo(mpo) { }
- void hold(MemoryPoolObject *mpo) { DEBUG_ASSERTCRASH(!m_mpo, ("already holding")); m_mpo = mpo; }
- void release() { m_mpo = NULL; }
- ~MemoryPoolObjectHolder() { deleteInstance(m_mpo); }
-};
-
-
-#define EMPTY_DTOR(CLASS) inline CLASS::~CLASS() { }
-
-#endif // _GAME_MEMORY_H_
diff --git a/Generals/Code/GameEngine/Source/Common/System/GameMemory.cpp b/Generals/Code/GameEngine/Source/Common/System/GameMemory.cpp
deleted file mode 100644
index f760d6f470f..00000000000
--- a/Generals/Code/GameEngine/Source/Common/System/GameMemory.cpp
+++ /dev/null
@@ -1,3590 +0,0 @@
-/*
-** Command & Conquer Generals(tm)
-** Copyright 2025 Electronic Arts Inc.
-**
-** This program is free software: you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation, either version 3 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program. If not, see .
-*/
-
-////////////////////////////////////////////////////////////////////////////////
-// //
-// (c) 2001-2003 Electronic Arts Inc. //
-// //
-////////////////////////////////////////////////////////////////////////////////
-
-// FILE: Memory.cpp
-//-----------------------------------------------------------------------------
-//
-// Westwood Studios Pacific.
-//
-// Confidential Information
-// Copyright (C) 2001 - All Rights Reserved
-//
-//-----------------------------------------------------------------------------
-//
-// Project: RTS3
-//
-// File name: Memory.cpp
-//
-// Created: Steven Johnson, August 2001
-//
-// Desc: Memory manager
-//
-// ----------------------------------------------------------------------------
-
-#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
-
-// SYSTEM INCLUDES
-
-// USER INCLUDES
-#include "Common/GameMemory.h"
-#include "Common/CriticalSection.h"
-#include "Common/Errors.h"
-#include "Common/GlobalData.h"
-#include "Common/PerfTimer.h"
-#ifdef MEMORYPOOL_DEBUG
-#include "GameClient/ClientRandomValue.h"
-#endif
-#ifdef MEMORYPOOL_STACKTRACE
- #include "Common/StackDump.h"
-#endif
-
-#ifdef MEMORYPOOL_DEBUG
-DECLARE_PERF_TIMER(MemoryPoolDebugging)
-DECLARE_PERF_TIMER(MemoryPoolInitFilling)
-#endif
-
-
-
-// ----------------------------------------------------------------------------
-// DEFINES
-// ----------------------------------------------------------------------------
-
-/**
- define MPSB_DLINK to add a backlink to MemoryPoolSingleBlock; this makes it
- faster to free raw DMA blocks.
- @todo verify this speedup is enough to be worth the extra space
-*/
-#define MPSB_DLINK
-
-#ifdef MEMORYPOOL_DEBUG
-
- /**
- if you define MEMORYPOOL_INTENSE_VERIFY, we do intensive verifications after
- nearly every memory operation. this is OFF by default, since it slows down
- things a lot, but is worth turning on for really obscure memory corruption issues.
- */
- #ifndef MEMORYPOOL_INTENSE_VERIFY
- #define NO_MEMORYPOOL_INTENSE_VERIFY
- #endif
-
- /**
- if you define MEMORYPOOL_CHECK_BLOCK_OWNERSHIP, we do lots of calls to verify
- that a block actually belongs to the pool it is called with. this is great
- for debugging, but can be realllly slow, so is off by default.
- */
- #ifndef MEMORYPOOL_CHECK_BLOCK_OWNERSHIP
- #define NO_MEMORYPOOL_CHECK_BLOCK_OWNERSHIP
- #endif
-
- static const char* FREE_SINGLEBLOCK_TAG_STRING = "FREE_SINGLEBLOCK_TAG_STRING";
- const Short SINGLEBLOCK_MAGIC_COOKIE = 12345;
- const Int GARBAGE_FILL_VALUE = 0xdeadbeef;
-
- // flags for m_debugFlags
- enum
- {
- IGNORE_LEAKS = 0x0001
- };
-
- // in debug mode (but not internal), save stacktraces too
- #if !defined(MEMORYPOOL_CHECKPOINTING) && defined(MEMORYPOOL_STACKTRACE) && defined(RTS_DEBUG)
- #define MEMORYPOOL_SINGLEBLOCK_GETS_STACKTRACE
- #endif
-
- #define USE_FILLER_VALUE
-
- const Int MAX_INIT_FILLER_COUNT = 8;
- #ifdef USE_FILLER_VALUE
- static UnsignedInt s_initFillerValue = 0xf00dcafe; // will be replaced, should never be this value at runtime
- static void calcFillerValue(Int index)
- {
- s_initFillerValue = (index & 3) << 1;
- s_initFillerValue |= 0x01;
- s_initFillerValue |= (~(s_initFillerValue << 4)) & 0xf0;
- s_initFillerValue |= (s_initFillerValue << 8);
- s_initFillerValue |= (s_initFillerValue << 16);
- //DEBUG_LOG(("Setting MemoryPool initFillerValue to %08x (index %d)",s_initFillerValue,index));
- }
- #endif
-
-#endif
-
-#ifdef MEMORYPOOL_BOUNDINGWALL
-
- #define WALLCOUNT (2) // default setting of 8 requires 4*4*2==32 extra bytes PER BLOCK
- #define WALLSIZE (WALLCOUNT * sizeof(Int))
-
-#endif
-
-#ifdef MEMORYPOOL_STACKTRACE
-
- #define MEMORYPOOL_STACKTRACE_SIZE (20)
- #define MEMORYPOOL_STACKTRACE_SKIP_SIZE (6)
- #define MEMORYPOOL_STACKTRACE_SIZE_BYTES (MEMORYPOOL_STACKTRACE_SIZE * sizeof(void*))
-
-#endif
-
-// ----------------------------------------------------------------------------
-// PRIVATE DATA
-// ----------------------------------------------------------------------------
-
-#ifdef MEMORYPOOL_BOUNDINGWALL
-
- static Int theBoundingWallPattern = 0xbabeface;
-
-#endif
-
-#ifdef MEMORYPOOL_STACKTRACE
-
- /** the max number levels to dump in the stacktrace. a variable rather than
- constant so that you can fiddle with it in the debugger if desired, to
- get shorter or longer dumps. (you can't go longer than MEMORYPOOL_STACKTRACE_SIZE
- in any event. */
- static Int theStackTraceDepth = 16;
-
-#endif
-
-#ifdef MEMORYPOOL_DEBUG
-
- static Int theTotalSystemAllocationInBytes = 0;
- static Int thePeakSystemAllocationInBytes = 0;
- static Int theTotalLargeBlocks = 0;
- static Int thePeakLargeBlocks = 0;
- Int theTotalDMA = 0;
- Int thePeakDMA = 0;
- Int theWastedDMA = 0;
- Int thePeakWastedDMA = 0;
-
-#ifdef INTENSE_DMA_BOOKKEEPING
- struct UsedNPeak
- {
- Int used, peak, waste, peakwaste;
- UsedNPeak() : used(0), peak(0), waste(0), peakwaste(0) { }
- };
- typedef std::map< const char*, UsedNPeak, std::less > UsedNPeakMap;
- static UsedNPeakMap TheUsedNPeakMap;
- static Int doingIntenseDMA = 0;
-#endif
-
-
-#endif
-
-static Bool thePreMainInitFlag = false;
-static Bool theMainInitFlag = false;
-
-// ----------------------------------------------------------------------------
-// PRIVATE PROTOTYPES
-// ----------------------------------------------------------------------------
-
-/// @todo srj -- make this work for 8
-#define MEM_BOUND_ALIGNMENT 4
-
-static Int roundUpMemBound(Int i);
-static void *sysAllocate(Int numBytes);
-static void *sysAllocateDoNotZero(Int numBytes);
-static void sysFree(void* p);
-static void memset32(void* ptr, Int value, Int bytesToFill);
-#ifdef MEMORYPOOL_STACKTRACE
-static void doStackDumpOutput(const char* m);
-static void doStackDump(void **stacktrace, int size);
-#endif
-static void preMainInitMemoryManager();
-
-// ----------------------------------------------------------------------------
-// PRIVATE FUNCTIONS
-// ----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-/** round up to the nearest multiple of MEM_BOUND_ALIGNMENT */
-static Int roundUpMemBound(Int i)
-{
- return (i + (MEM_BOUND_ALIGNMENT-1)) & ~(MEM_BOUND_ALIGNMENT-1);
-}
-
-//-----------------------------------------------------------------------------
-/**
- identical to sysAllocateDoNotZero, except that the memory block returned
- is filled to all-zero-bytes.
-*/
-static void* sysAllocate(Int numBytes)
-{
- void* p = ::GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, numBytes);
- if (!p)
- throw ERROR_OUT_OF_MEMORY;
-#ifdef MEMORYPOOL_DEBUG
- {
- USE_PERF_TIMER(MemoryPoolDebugging)
- theTotalSystemAllocationInBytes += ::GlobalSize(p);
- if (thePeakSystemAllocationInBytes < theTotalSystemAllocationInBytes)
- thePeakSystemAllocationInBytes = theTotalSystemAllocationInBytes;
- }
-#endif
- return p;
-}
-
-//-----------------------------------------------------------------------------
-/**
- this is the low-level allocator that we use to request memory from the OS.
- all (repeat, all) memory allocations in this module should ultimately
- go thru this routine (or sysAllocate).
-
- note: throws ERROR_OUT_OF_MEMORY on failure; never returns null
-*/
-static void* sysAllocateDoNotZero(Int numBytes)
-{
- void* p = ::GlobalAlloc(GMEM_FIXED, numBytes);
- if (!p)
- throw ERROR_OUT_OF_MEMORY;
-#ifdef MEMORYPOOL_DEBUG
- {
- USE_PERF_TIMER(MemoryPoolDebugging)
- #ifdef USE_FILLER_VALUE
- {
- USE_PERF_TIMER(MemoryPoolInitFilling)
- ::memset32(p, s_initFillerValue, ::GlobalSize(p));
- }
- #endif
- theTotalSystemAllocationInBytes += ::GlobalSize(p);
- if (thePeakSystemAllocationInBytes < theTotalSystemAllocationInBytes)
- thePeakSystemAllocationInBytes = theTotalSystemAllocationInBytes;
- }
-#endif
- return p;
-}
-
-//-----------------------------------------------------------------------------
-/**
- the counterpart to sysAllocate / sysAllocateDoNotZero; used to free blocks
- allocated by them. it is OK to pass null here (it will just be ignored).
-*/
-static void sysFree(void* p)
-{
- if (p)
- {
-#ifdef MEMORYPOOL_DEBUG
- {
- USE_PERF_TIMER(MemoryPoolDebugging)
- ::memset32(p, GARBAGE_FILL_VALUE, ::GlobalSize(p));
- theTotalSystemAllocationInBytes -= ::GlobalSize(p);
- }
-#endif
- ::GlobalFree(p);
- }
-}
-
-// ----------------------------------------------------------------------------
-/**
- fills memory with a 32-bit value (note: assumes the ptr is 4-byte-aligned)
-*/
-static void memset32(void* ptr, Int value, Int bytesToFill)
-{
- Int wordsToFill = bytesToFill>>2;
- bytesToFill -= (wordsToFill<<2);
-
- Int *p = (Int*)ptr;
- for (++wordsToFill; --wordsToFill; )
- *p++ = value;
-
- Byte *b = (Byte *)p;
- for (++bytesToFill; --bytesToFill; )
- *b++ = (Byte)value;
-}
-
-#ifdef MEMORYPOOL_STACKTRACE
-// ----------------------------------------------------------------------------
-/**
- This is just a convenience routine that dumps output from the StackDump module
- to our normal debug log file, with a little massaging for formatting.
-*/
-static void doStackDumpOutput(const char* m)
-{
- const char *PREPEND = "STACKTRACE";
- if (*m == 0)
- {
- DEBUG_LOG((m));
- }
- else
- {
- // Note - I am moving the prepend to the end, as this allows double clicking in the
- // output window to open the file in VisualStudio. jba.
- DEBUG_LOG(("%s, %s",m, PREPEND));
- }
-}
-#endif
-
-#ifdef MEMORYPOOL_STACKTRACE
-// ----------------------------------------------------------------------------
-/**
- dump the given stacktrace to the debug log.
-*/
-static void doStackDump(void **stacktrace, int size)
-{
- ::doStackDumpOutput("Allocation Stack Trace:");
- ::StackDumpFromAddresses(stacktrace, size, ::doStackDumpOutput);
-}
-#endif
-
-// ----------------------------------------------------------------------------
-// PRIVATE TYPES
-// ----------------------------------------------------------------------------
-
-// ----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- This is a auxiliary record that we allocate in debug modes (actually, checkpoint modes)
- to retain extra information about blocks; there is a one-to-one correspondence
- between this record and a block allocation. The interesting bit about this record is that
- we don't deallocate it when the corresponding block is freed; we retain it so we can
- later provide information about what blocks were freed when, etc. Yes, this does chew
- up a lot of memory! That's why it's debug-mode only; the presumption is that developers
- machines have boatloads of RAM. (Note that we *do* free these when resetCheckpoints() is called.)
- Note also that we directly allocate/free these with sysAllocate/sysFree, so ctors/dtors
- are never executed, nor would virtual functions work -- I know, it's a little evil.
-*/
-class BlockCheckpointInfo
-{
-private:
- BlockCheckpointInfo *m_next; ///< next checkpoint in this pool/dma
- const char *m_debugLiteralTagString; ///< the tagstring for the block
- Int m_allocCheckpoint; ///< when it was allocated
- Int m_freeCheckpoint; ///< when it was freed (-1 if still in existence)
- Int m_blockSize; ///< logical size of the block
-#ifdef MEMORYPOOL_STACKTRACE
- void* m_stacktrace[MEMORYPOOL_STACKTRACE_SIZE]; ///< stacktrace of when block was allocated
-#endif
-
- ~BlockCheckpointInfo() {};
-
-public:
-
- BlockCheckpointInfo *getNext(); ///< return next checkpointinfo for this pool/dma
-
- void debugSetFreepoint(Int f); ///< set the checkpoint at which the block was freed.
-
-#ifdef MEMORYPOOL_STACKTRACE
- void **getStacktraceInfo(); ///< return a ptr to the allocation stacktrace info.
-#endif
-
- static BlockCheckpointInfo *addToList(
- BlockCheckpointInfo **pHead,
- const char *debugLiteralTagString,
- Int allocCheckpoint,
- Int blockSize
- );
-
- static void freeList(BlockCheckpointInfo **pHead);
-
- Bool shouldBeInReport(Int flags, Int startCheckpoint, Int endCheckpoint);
-
- static void doBlockCheckpointReport( BlockCheckpointInfo *bi, const char *poolName,
- Int flags, Int startCheckpoint, Int endCheckpoint );
-};
-
-#endif
-
-// ----------------------------------------------------------------------------
-/**
- This is the fundamental allocation unit; when you allocate via (say) MemoryPool::allocateBlock,
- this is what is being allocated for you. (Of course, you don't see the private fields.)
- For the most part, we allocate big chunks of these in a monolithic Blob and subdivide
- from there. (However, we occasionally allocate these individually, for large blocks.)
-
- Note also that we directly allocate/free these with sysAllocate/sysFree, so ctors/dtors
- are never executed, nor would virtual functions work -- I know, it's a little evil.
-*/
-class MemoryPoolSingleBlock
-{
-private:
-
- MemoryPoolBlob *m_owningBlob; ///< will be NULL if the single block was allocated via sysAllocate()
- MemoryPoolSingleBlock *m_nextBlock; ///< if m_owningBlob is nonnull, this points to next free (unallocated) block in the blob; if m_owningBlob is null, this points to the next used (allocated) raw block in the pool.
-#ifdef MPSB_DLINK
- MemoryPoolSingleBlock *m_prevBlock; ///< if m_owningBlob is nonnull, this points to prev free (unallocated) block in the blob; if m_owningBlob is null, this points to the prev used (allocated) raw block in the pool.
-#endif
-#ifdef MEMORYPOOL_CHECKPOINTING
- BlockCheckpointInfo *m_checkpointInfo; ///< ptr to the checkpointinfo for this block
-#endif
-#ifdef MEMORYPOOL_BOUNDINGWALL
- Int m_wallPattern; ///< unique seed value for the bounding-walls for this block
-#endif
-#ifdef MEMORYPOOL_DEBUG
- const char *m_debugLiteralTagString; ///< ptr to the tagstring for this block.
- Int m_logicalSize; ///< logical size of block (not including overhead, walls, etc.)
- Int m_wastedSize; ///< if allocated via DMA, the "wasted" bytes
- Short m_magicCookie; ///< magic value used to verify that the block is one of ours (as opposed to random pointer)
- Short m_debugFlags; ///< misc flags
- #ifdef MEMORYPOOL_SINGLEBLOCK_GETS_STACKTRACE
- void* m_stacktrace[MEMORYPOOL_STACKTRACE_SIZE]; ///< stacktrace of when block was allocated (if not checkpointing)
- #endif
-#endif
-
-private:
-
- void* getUserDataNoDbg();
-#ifdef MEMORYPOOL_BOUNDINGWALL
- void debugFillInWalls();
-#endif
-
-public:
-
- static Int calcRawBlockSize(Int logicalSize);
- static MemoryPoolSingleBlock *rawAllocateSingleBlock(MemoryPoolSingleBlock **pRawListHead, Int logicalSize, MemoryPoolFactory *owningFactory DECLARE_LITERALSTRING_ARG2);
- void removeBlockFromList(MemoryPoolSingleBlock **pHead);
-
- void initBlock(Int logicalSize, MemoryPoolBlob *owningBlob, MemoryPoolFactory *owningFactory DECLARE_LITERALSTRING_ARG2);
- void* getUserData();
- static MemoryPoolSingleBlock *recoverBlockFromUserData(void* pUserData);
- MemoryPoolBlob *getOwningBlob();
-
- MemoryPoolSingleBlock *getNextFreeBlock();
- void setNextFreeBlock(MemoryPoolSingleBlock *b);
- MemoryPoolSingleBlock *getNextRawBlock();
- void setNextRawBlock(MemoryPoolSingleBlock *b);
-
-#ifdef MEMORYPOOL_DEBUG
- void debugIgnoreLeaksForThisBlock();
- const char *debugGetLiteralTagString();
- Int debugGetLogicalSize();
- Int debugGetWastedSize();
- void debugSetWastedSize(Int waste);
- void debugVerifyBlock();
- void debugMarkBlockAsFree();
- Bool debugCheckUnderrun();
- Bool debugCheckOverrun();
- Int debugSingleBlockReportLeak(const char* owner);
-#endif // MEMORYPOOL_DEBUG
-#ifdef MEMORYPOOL_CHECKPOINTING
- BlockCheckpointInfo *debugGetCheckpointInfo();
- void debugSetCheckpointInfo(BlockCheckpointInfo *bi);
- void debugResetCheckpoint();
-#endif
-
-};
-// ----------------------------------------------------------------------------
-class MemoryPoolBlob
-{
-private:
- MemoryPool *m_owningPool; ///< the pool that owns this blob
- MemoryPoolBlob *m_nextBlob; ///< next blob in this pool
- MemoryPoolBlob *m_prevBlob; ///< prev blob in this pool
- MemoryPoolSingleBlock *m_firstFreeBlock; ///< ptr to first available block in this blob
- Int m_usedBlocksInBlob; ///< total allocated blocks in this blob
- Int m_totalBlocksInBlob; ///< total blocks in this blob (allocated + available)
- char *m_blockData; ///< ptr to the blocks (really a MemoryPoolSingleBlock*)
-
-public:
-
- MemoryPoolBlob();
- ~MemoryPoolBlob();
-
- void initBlob(MemoryPool *owningPool, Int allocationCount);
-
- void addBlobToList(MemoryPoolBlob **ppHead, MemoryPoolBlob **ppTail);
- void removeBlobFromList(MemoryPoolBlob **ppHead, MemoryPoolBlob **ppTail);
- MemoryPoolBlob *getNextInList();
- Bool hasAnyFreeBlocks();
-
- MemoryPoolSingleBlock *allocateSingleBlock(DECLARE_LITERALSTRING_ARG1);
- void freeSingleBlock(MemoryPoolSingleBlock *block);
-
- MemoryPool *getOwningPool();
- Int getFreeBlockCount();
- Int getUsedBlockCount();
- Int getTotalBlockCount();
-
-#ifdef MEMORYPOOL_DEBUG
- void debugMemoryVerifyBlob();
- Int debugBlobReportLeaks(const char* owner);
- Bool debugIsBlockInBlob(void *pBlock);
-#endif
-#ifdef MEMORYPOOL_CHECKPOINTING
- void debugResetCheckpoints();
-#endif
-
-};
-
-// ----------------------------------------------------------------------------
-// PUBLIC DATA
-// ----------------------------------------------------------------------------
-
-MemoryPoolFactory *TheMemoryPoolFactory = NULL;
-DynamicMemoryAllocator *TheDynamicMemoryAllocator = NULL;
-
-// ----------------------------------------------------------------------------
-// INLINES
-// ----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-inline BlockCheckpointInfo *BlockCheckpointInfo::getNext() { return m_next; }
-inline void BlockCheckpointInfo::debugSetFreepoint(Int f) { DEBUG_ASSERTCRASH(m_freeCheckpoint == -1, ("already have a freepoint")); m_freeCheckpoint = f; }
-#ifdef MEMORYPOOL_STACKTRACE
-inline void **BlockCheckpointInfo::getStacktraceInfo() { return m_stacktrace; }
-#endif
-#endif
-
-// ----------------------------------------------------------------------------
-/**
- return a ptr to the user-data area of the block (ie, the part the enduser can deal with).
- this call does NO debug verification and is for internal use of class MemoryPoolSingleBlock only.
-*/
-inline void* MemoryPoolSingleBlock::getUserDataNoDbg()
-{
- char* p = ((char*)this) + sizeof(MemoryPoolSingleBlock);
- #ifdef MEMORYPOOL_BOUNDINGWALL
- p += WALLSIZE;
- #endif
- return (void*)p;
-}
-
-/**
- return a ptr to the user-data area of the block (ie, the part the enduser can deal with).
- this call verifies that the block is valid in debug mode.
-*/
-inline void* MemoryPoolSingleBlock::getUserData()
-{
- // yes, verify the block in this case for plain debug mode (not intense-verify mode)
- #ifdef MEMORYPOOL_DEBUG
- debugVerifyBlock();
- #endif
- return getUserDataNoDbg();
-}
-
-/**
- given a desired logical block size, calculate the physical size needed for each
- MemoryPoolSingleBlock (including overhead, etc.)
-*/
-inline /*static*/ Int MemoryPoolSingleBlock::calcRawBlockSize(Int logicalSize)
-{
- Int s = ::roundUpMemBound(logicalSize) + sizeof(MemoryPoolSingleBlock);
- #ifdef MEMORYPOOL_BOUNDINGWALL
- s += WALLSIZE*2;
- #endif
- return s;
-}
-
-/**
- accessor
-*/
-inline MemoryPoolBlob *MemoryPoolSingleBlock::getOwningBlob()
-{
- return m_owningBlob;
-}
-
-/**
- return the next free block in this blob. this call assumes that the block
- in question belongs to a blob, and will assert if not.
-*/
-inline MemoryPoolSingleBlock *MemoryPoolSingleBlock::getNextFreeBlock()
-{
- DEBUG_ASSERTCRASH(m_owningBlob != NULL, ("must be called on blob block"));
- return m_nextBlock;
-}
-
-/**
- set the next free block in this blob. this call assumes that both blocks
- in question belongs to a blob, but will NOT assert if not, since it may be
- called when the blocks are in an inconsistent state.
-*/
-inline void MemoryPoolSingleBlock::setNextFreeBlock(MemoryPoolSingleBlock *b)
-{
- //DEBUG_ASSERTCRASH(m_owningBlob != NULL && b->m_owningBlob != NULL, ("must be called on blob block"));
- // don't check the 'b' block -- we need to call this before 'b' is fully initialized.
- DEBUG_ASSERTCRASH(m_owningBlob != NULL, ("must be called on blob block"));
- this->m_nextBlock = b;
-#ifdef MPSB_DLINK
- if (b) {
- b->m_prevBlock = this;
- }
-#endif
-}
-
-/**
- return the next raw block in this dma. this call assumes that the block
- in question does NOT belong to a blob, and will assert if not.
-*/
-inline MemoryPoolSingleBlock *MemoryPoolSingleBlock::getNextRawBlock()
-{
- DEBUG_ASSERTCRASH(m_owningBlob == NULL, ("must be called on raw block"));
- return m_nextBlock;
-}
-
-/**
- set the next raw block in this dma. this call assumes that the blocks
- in question do NOT belong to a blob, and will assert if not.
-*/
-inline void MemoryPoolSingleBlock::setNextRawBlock(MemoryPoolSingleBlock *b)
-{
- DEBUG_ASSERTCRASH(m_owningBlob == NULL && (!b || b->m_owningBlob == NULL), ("must be called on raw block"));
- m_nextBlock = b;
-#ifdef MPSB_DLINK
- if (b)
- b->m_prevBlock = this;
-#endif
-}
-
-#ifdef MEMORYPOOL_DEBUG
-inline void MemoryPoolSingleBlock::debugIgnoreLeaksForThisBlock()
-{
- //USE_PERF_TIMER(MemoryPoolDebugging) not worth it
- m_debugFlags |= IGNORE_LEAKS;
-}
-/**
- accessor
-*/
-inline const char *MemoryPoolSingleBlock::debugGetLiteralTagString()
-{
- //USE_PERF_TIMER(MemoryPoolDebugging) not worth it
- return m_debugLiteralTagString;
-}
-#endif
-
-#ifdef MEMORYPOOL_DEBUG
-/**
- accessor
-*/
-inline Int MemoryPoolSingleBlock::debugGetLogicalSize()
-{
- //USE_PERF_TIMER(MemoryPoolDebugging) not worth it
- return m_logicalSize;
-}
-#endif
-
-#ifdef MEMORYPOOL_DEBUG
-/**
- accessor
-*/
-inline Int MemoryPoolSingleBlock::debugGetWastedSize()
-{
- //USE_PERF_TIMER(MemoryPoolDebugging) not worth it
- return m_wastedSize;
-}
-#endif
-
-#ifdef MEMORYPOOL_DEBUG
-inline void MemoryPoolSingleBlock::debugSetWastedSize(Int w)
-{
- //USE_PERF_TIMER(MemoryPoolDebugging) not worth it
- m_wastedSize = w;
-}
-#endif
-
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- accessor
-*/
-inline BlockCheckpointInfo *MemoryPoolSingleBlock::debugGetCheckpointInfo()
-{
- return m_checkpointInfo;
-}
-#endif
-
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- set the checkpoint info for this block.
-*/
-inline void MemoryPoolSingleBlock::debugSetCheckpointInfo(BlockCheckpointInfo *bi)
-{
- DEBUG_ASSERTCRASH(m_checkpointInfo == NULL, ("should be null"));
- m_checkpointInfo = bi;
-}
-#endif
-
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- sets the checkpointinfo to null, but does NOT free it... the checkpointinfo
- is expected to be freed elsewhere.
-*/
-inline void MemoryPoolSingleBlock::debugResetCheckpoint()
-{
- m_checkpointInfo = NULL;
-}
-#endif
-
-// ----------------------------------------------------------------------------
-/// accessor
-inline MemoryPoolBlob *MemoryPoolBlob::getNextInList() { return m_nextBlob; }
-/// accessor
-inline Bool MemoryPoolBlob::hasAnyFreeBlocks() { return m_firstFreeBlock != NULL; }
-/// accessor
-inline MemoryPool *MemoryPoolBlob::getOwningPool() { return m_owningPool; }
-/// accessor
-inline Int MemoryPoolBlob::getFreeBlockCount() { return getTotalBlockCount() - getUsedBlockCount(); }
-/// accessor
-inline Int MemoryPoolBlob::getUsedBlockCount() { return m_usedBlocksInBlob; }
-/// accessor
-inline Int MemoryPoolBlob::getTotalBlockCount() { return m_totalBlocksInBlob; }
-
-//-----------------------------------------------------------------------------
-// METHODS for BlockCheckpointInfo
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/// return true iff this checkpointinfo should be included in a checkpointreport with the given parameters.
-Bool BlockCheckpointInfo::shouldBeInReport(Int flags, Int startCheckpoint, Int endCheckpoint)
-{
- Bool allocFlagsOK = false;
- Bool freedFlagsOK = false;
-
- if (m_allocCheckpoint < startCheckpoint && (flags & _REPORT_CP_ALLOCATED_BEFORE))
- allocFlagsOK = true;
- if (m_allocCheckpoint >= startCheckpoint && m_allocCheckpoint < endCheckpoint && (flags & _REPORT_CP_ALLOCATED_BETWEEN))
- allocFlagsOK = true;
-
- if (m_freeCheckpoint == -1)
- {
- // block still exists! process this only if we want 'em.
- freedFlagsOK = (flags & _REPORT_CP_FREED_NEVER) ? true : false;
- }
- else
- {
- if (m_freeCheckpoint < startCheckpoint && (flags & _REPORT_CP_FREED_BEFORE))
- freedFlagsOK = true;
- if (m_freeCheckpoint >= startCheckpoint && m_freeCheckpoint < endCheckpoint && (flags & _REPORT_CP_FREED_BETWEEN))
- freedFlagsOK = true;
- }
-
- // the block must match both the 'alloc' and 'free' criteria to get a report
- return allocFlagsOK && freedFlagsOK;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/// print a checkpointreport for the given checkpointinfo. if checkpointinfo is null, print column headers.
-/*static*/ void BlockCheckpointInfo::doBlockCheckpointReport(BlockCheckpointInfo *bi,
- const char *poolName, Int flags, Int startCheckpoint, Int endCheckpoint )
-{
- const char *PREPEND = "BLOCKINFO"; // allows grepping more easily
-
- if (!bi)
- {
- DEBUG_LOG(("%s,%32s,%6s,%6s,%6s,%s",PREPEND,"POOLNAME","BLKSZ","ALLOC","FREED","BLOCKNAME"));
- }
- else
- {
- DEBUG_ASSERTCRASH(startCheckpoint >= 0 && startCheckpoint <= endCheckpoint, ("bad checkpoints"));
- DEBUG_ASSERTCRASH((flags & _REPORT_CP_ALLOCATED_DONTCARE) != 0, ("bad flags: must set at least one alloc flag"));
- DEBUG_ASSERTCRASH((flags & _REPORT_CP_FREED_DONTCARE) != 0, ("bad flags: must set at least one freed flag"));
-
- if (bi->shouldBeInReport(flags, startCheckpoint, endCheckpoint))
- {
- DEBUG_LOG(("%s,%32s,%6d,%6d,%6d,%s",PREPEND,poolName,bi->m_blockSize,bi->m_allocCheckpoint,bi->m_freeCheckpoint,bi->m_debugLiteralTagString));
- #ifdef MEMORYPOOL_STACKTRACE
- if (flags & REPORT_CP_STACKTRACE)
- {
- ::doStackDump(bi->m_stacktrace, min(MEMORYPOOL_STACKTRACE_SIZE, theStackTraceDepth ));
- }
- #endif
- }
- }
-}
-#endif
-
-// ----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/// free an entire list of checkpointinfos.
-/*static*/ void BlockCheckpointInfo::freeList(BlockCheckpointInfo **pHead)
-{
- BlockCheckpointInfo *p = *pHead;
- while (p)
- {
- BlockCheckpointInfo *n = p->m_next;
- ::sysFree((void *)p);
- p = n;
- }
- *pHead = NULL;
-}
-#endif
-
-// ----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- allocate a new checkpointinfo with the given tag/checkpoint/size, add it to the
- linked list, and return the checkpointinfo. (note that this will NOT throw an exception;
- if there is not enough memory to allocate a new checkpointinfo, it will quietly return null.)
-*/
-/*static*/ BlockCheckpointInfo *BlockCheckpointInfo::addToList(
- BlockCheckpointInfo **pHead,
- const char *debugLiteralTagString,
- Int allocCheckpoint,
- Int blockSize
-)
-{
- DEBUG_ASSERTCRASH(debugLiteralTagString != FREE_SINGLEBLOCK_TAG_STRING, ("bad tag string"));
-
- BlockCheckpointInfo *freed = NULL;
- try {
- freed = (BlockCheckpointInfo *)::sysAllocate(sizeof(BlockCheckpointInfo));
- } catch (...) {
- freed = NULL;
- }
- if (freed)
- {
- DEBUG_ASSERTCRASH(debugLiteralTagString != NULL, ("null tagstrings are not allowed"));
- freed->m_debugLiteralTagString = debugLiteralTagString;
- freed->m_allocCheckpoint = allocCheckpoint;
- freed->m_freeCheckpoint = -1;
- freed->m_blockSize = blockSize;
- freed->m_next = *pHead;
- *pHead = freed;
- }
- return freed;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-// METHODS for MemoryPoolSingleBlock
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-/**
- fill in a block's fields. this is usually done only just after a block is allocated,
- but might also be done at other points in debug mode.
-*/
-void MemoryPoolSingleBlock::initBlock(Int logicalSize, MemoryPoolBlob *owningBlob,
- MemoryPoolFactory *owningFactory DECLARE_LITERALSTRING_ARG2)
-{
- // Note that while it is OK for owningBlob to be null, it is NEVER ok
- // for owningFactory to be null.
- DEBUG_ASSERTCRASH(owningFactory, ("null factory"));
-
-#ifdef MEMORYPOOL_DEBUG
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
- m_magicCookie = SINGLEBLOCK_MAGIC_COOKIE;
- m_debugFlags = 0;
- if (!theMainInitFlag)
- debugIgnoreLeaksForThisBlock();
- DEBUG_ASSERTCRASH(debugLiteralTagString != NULL, ("null tagstrings are not allowed"));
- m_debugLiteralTagString = debugLiteralTagString;
- m_logicalSize = logicalSize;
- m_wastedSize = 0;
-
-#ifdef MEMORYPOOL_SINGLEBLOCK_GETS_STACKTRACE
- if (theStackTraceDepth > 0 && (!TheGlobalData || TheGlobalData->m_checkForLeaks))
- {
- memset(m_stacktrace, 0, MEMORYPOOL_STACKTRACE_SIZE_BYTES);
- ::FillStackAddresses(m_stacktrace, min(MEMORYPOOL_STACKTRACE_SIZE, theStackTraceDepth), MEMORYPOOL_STACKTRACE_SKIP_SIZE);
- }
- else
- {
- m_stacktrace[0] = NULL;
- }
-#endif
-}
-#endif // MEMORYPOOL_DEBUG
-#ifdef MEMORYPOOL_CHECKPOINTING
- m_checkpointInfo = NULL;
-#endif
-
- m_nextBlock = NULL;
-#ifdef MPSB_DLINK
- m_prevBlock = NULL;
-#endif
- m_owningBlob = owningBlob; // could be NULL
-
-#ifdef MEMORYPOOL_BOUNDINGWALL
- m_wallPattern = theBoundingWallPattern++;
- debugFillInWalls();
-#endif
-}
-
-//-----------------------------------------------------------------------------
-/**
- given a 'public' ptr to a block (ie, the ptr returned by the MemoryPool::allocateBlock),
- recover the ptr to the MemoryPoolSingleBlock, so we can access the hidden fields.
-*/
-/* static */ MemoryPoolSingleBlock *MemoryPoolSingleBlock::recoverBlockFromUserData(void* pUserData)
-{
- DEBUG_ASSERTCRASH(pUserData, ("null pUserData"));
- if (!pUserData)
- return NULL;
- char* p = ((char*)pUserData) - sizeof(MemoryPoolSingleBlock);
- #ifdef MEMORYPOOL_BOUNDINGWALL
- p -= WALLSIZE;
- #endif
- MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)p;
-// yes, verify the block in this case for plain debug mode (not intense-verify mode)
-#ifdef MEMORYPOOL_DEBUG
- block->debugVerifyBlock();
-#endif
- return block;
-}
-
-//-----------------------------------------------------------------------------
-/**
- allocate and initialize a single block. this should only used by DynamicMemoryAllocator
- when allocating an extraordinarily large block.
-*/
-/*static*/ MemoryPoolSingleBlock *MemoryPoolSingleBlock::rawAllocateSingleBlock(
- MemoryPoolSingleBlock **pRawListHead,
- Int logicalSize,
- MemoryPoolFactory *owningFactory
- DECLARE_LITERALSTRING_ARG2)
-{
- MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)::sysAllocateDoNotZero(calcRawBlockSize(logicalSize));
- block->initBlock(logicalSize, NULL, owningFactory PASS_LITERALSTRING_ARG2);
- block->setNextRawBlock(*pRawListHead);
- *pRawListHead = block;
- return block;
-}
-
-//-----------------------------------------------------------------------------
-/**
- remove the block from the list, which is presumed to be a list of raw blocks.
- generally, only the DynamicMemoryAllocator should call this.
-*/
-void MemoryPoolSingleBlock::removeBlockFromList(MemoryPoolSingleBlock **pHead)
-{
- DEBUG_ASSERTCRASH(this->m_owningBlob == NULL, ("this function should only be used on raw blocks"));
-#ifdef MPSB_DLINK
- DEBUG_ASSERTCRASH(this->m_nextBlock == NULL || this->m_nextBlock->m_owningBlob == NULL, ("this function should only be used on raw blocks"));
- if (this->m_prevBlock)
- {
- DEBUG_ASSERTCRASH(this->m_prevBlock->m_owningBlob == NULL, ("this function should only be used on raw blocks"));
- DEBUG_ASSERTCRASH(*pHead != this, ("bad linkage"));
- this->m_prevBlock->m_nextBlock = this->m_nextBlock;
- }
- else
- {
- DEBUG_ASSERTCRASH(*pHead == this, ("bad linkage"));
- *pHead = this->m_nextBlock;
- }
-
- if (this->m_nextBlock)
- {
- DEBUG_ASSERTCRASH(this->m_nextBlock->m_owningBlob == NULL, ("this function should only be used on raw blocks"));
- this->m_nextBlock->m_prevBlock = this->m_prevBlock;
- }
-#else
- // this isn't very efficient, and may need upgrading... but to do so
- // would require adding a back link, so I'd rather do some testing
- // first to see if it's really a speed issue in practice. (the only place
- // this is used is when freeing 'raw' blocks allocated via the DMA).
- MemoryPoolSingleBlock *prev = NULL;
- for (MemoryPoolSingleBlock *cur = *pHead; cur; cur = cur->m_nextBlock)
- {
- DEBUG_ASSERTCRASH(cur->m_owningBlob == NULL, ("this function should only be used on raw blocks"));
- if (cur == this)
- {
- if (prev)
- {
- prev->m_nextBlock = this->m_nextBlock;
- }
- else
- {
- *pHead = this->m_nextBlock;
- }
- break;
- }
- prev = cur;
- }
-#endif
-}
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-Int MemoryPoolSingleBlock::debugSingleBlockReportLeak(const char* owner)
-{
- //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
-
- // if allocated before main... just ignore the leak.
- if (m_debugFlags & IGNORE_LEAKS)
- return 0;
-
- // it's free, ergo, not leaked.
- if (m_debugLiteralTagString == FREE_SINGLEBLOCK_TAG_STRING)
- return 0;
-
- if (strcmp(m_debugLiteralTagString, "STR_AsciiString::ensureUniqueBufferOfSize") == 0)
- {
- /** @todo srj -- we leak a bunch of these for some reason (probably due to leaking Win32LocalFile)
- so just ignore 'em for now... figure out later. */
- }
- else if (strstr(m_debugLiteralTagString, "Win32LocalFileSystem.cpp") != NULL)
- {
- /** @todo srj -- we leak a bunch of these for some reason
- so just ignore 'em for now... figure out later. */
- }
- else
- {
- DEBUG_LOG(("Leaked a block of size %d, tagstring %s, from pool/dma %s",m_logicalSize,m_debugLiteralTagString,owner));
- }
-
- #ifdef MEMORYPOOL_SINGLEBLOCK_GETS_STACKTRACE
- if (!TheGlobalData || TheGlobalData->m_checkForLeaks)
- ::doStackDump(m_stacktrace, min(MEMORYPOOL_STACKTRACE_SIZE, theStackTraceDepth));
- #endif
-
- return 1;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- Verify internal consistency of this block.
-*/
-void MemoryPoolSingleBlock::debugVerifyBlock()
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- DEBUG_ASSERTCRASH(this, ("null this"));
- DEBUG_ASSERTCRASH(m_magicCookie == SINGLEBLOCK_MAGIC_COOKIE, ("wrong cookie"));
- DEBUG_ASSERTCRASH(m_debugLiteralTagString != NULL, ("bad tagstring"));
- /// @todo Put this check back in after the AI memory usage is under control (MSB)
- //DEBUG_ASSERTCRASH(m_logicalSize>0 && m_logicalSize < 0x00ffffff, ("unlikely value for m_logicalSize"));
- DEBUG_ASSERTCRASH(m_nextBlock == NULL
- || memcmp(&m_nextBlock->m_owningBlob, &s_initFillerValue, sizeof(s_initFillerValue)) == 0
- || m_nextBlock->m_owningBlob == m_owningBlob, ("owning blob mismatch..."));
-#ifdef MPSB_DLINK
- DEBUG_ASSERTCRASH(m_prevBlock == NULL
- || memcmp(&m_prevBlock->m_owningBlob, &s_initFillerValue, sizeof(s_initFillerValue)) == 0
- || m_prevBlock->m_owningBlob == m_owningBlob, ("owning blob mismatch..."));
-#endif
- debugCheckUnderrun();
- debugCheckOverrun();
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- Fill block with bogus values and mark other internal fields for debugging purposes.
-*/
-void MemoryPoolSingleBlock::debugMarkBlockAsFree()
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- ::memset32(getUserDataNoDbg(), GARBAGE_FILL_VALUE, m_logicalSize);
- m_debugLiteralTagString = FREE_SINGLEBLOCK_TAG_STRING;
- #ifdef MEMORYPOOL_INTENSE_VERIFY
- debugVerifyBlock();
- #endif
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- Returns true iff someone overwrote part of the first bounding wall
- (ie, tromped on memory just before the block)
-*/
-Bool MemoryPoolSingleBlock::debugCheckUnderrun()
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
-#ifdef MEMORYPOOL_BOUNDINGWALL
- Int *p = (Int*)(((char*)getUserDataNoDbg()) - WALLSIZE);
- for (Int i = 0; i < WALLCOUNT; i++, p++)
- {
- if (*p != m_wallPattern+i)
- {
- DEBUG_CRASH(("memory underrun for block \"%s\" (expected %08x, got %08x)",m_debugLiteralTagString,m_wallPattern+i,*p));
- return true;
- }
- }
-#endif
- return false;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- Returns true iff someone overwrote part of the second bounding wall
- (ie, tromped on memory just after the block)
-*/
-Bool MemoryPoolSingleBlock::debugCheckOverrun()
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
-#ifdef MEMORYPOOL_BOUNDINGWALL
- Int *p = (Int*)(((char*)getUserDataNoDbg()) + m_logicalSize);
- for (Int i = 0; i < WALLCOUNT; i++, p++)
- {
- if (*p != m_wallPattern-i)
- {
- DEBUG_CRASH(("memory overrun for block \"%s\" (expected %08x, got %08x)",m_debugLiteralTagString,m_wallPattern+i,*p));
- return true;
- }
- }
-#endif
- return false;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_BOUNDINGWALL
-/**
- Fill in the proper values for this block's bounding walls.
-*/
-void MemoryPoolSingleBlock::debugFillInWalls()
-{
- Int *p;
- Int i;
-
- p = (Int*)(((char*)getUserDataNoDbg()) - WALLSIZE);
- for (i = 0; i < WALLCOUNT; i++)
- *p++ = m_wallPattern+i;
-
- p = (Int*)(((char*)getUserDataNoDbg()) + m_logicalSize);
- for (i = 0; i < WALLCOUNT; i++)
- *p++ = m_wallPattern-i;
-
- #ifdef MEMORYPOOL_INTENSE_VERIFY
- debugVerifyBlock();
- #endif
-}
-#endif
-
-
-//-----------------------------------------------------------------------------
-// METHODS for MemoryPoolBlob
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-/**
- fill in safe default values.
-*/
-MemoryPoolBlob::MemoryPoolBlob() :
- m_owningPool(NULL),
- m_nextBlob(NULL),
- m_prevBlob(NULL),
- m_firstFreeBlock(NULL),
- m_usedBlocksInBlob(0),
- m_totalBlocksInBlob(0),
- m_blockData(NULL)
-{
-}
-
-//-----------------------------------------------------------------------------
-/**
- throw away the blob. free the block data, if any.
-*/
-MemoryPoolBlob::~MemoryPoolBlob()
-{
- ::sysFree((void *)m_blockData);
-}
-
-//-----------------------------------------------------------------------------
-/**
- initialize a Blob; this is called just after the blob is allocated.
- allocate space for the blocks in this blob and initialize all those blocks.
-*/
-void MemoryPoolBlob::initBlob(MemoryPool *owningPool, Int allocationCount)
-{
- DEBUG_ASSERTCRASH(m_blockData == NULL, ("unlikely init call"));
-
- m_owningPool = owningPool;
- m_totalBlocksInBlob = allocationCount;
- m_usedBlocksInBlob = 0;
-
- Int rawBlockSize = MemoryPoolSingleBlock::calcRawBlockSize(m_owningPool->getAllocationSize());
- m_blockData = (char *)::sysAllocate(rawBlockSize * m_totalBlocksInBlob); // throws on failure
-
- // set up the list of free blocks in the blob (namely, all of 'em)
- MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)m_blockData;
- MemoryPoolSingleBlock *next;
- for (Int i = m_totalBlocksInBlob-1; i >= 0; i--)
- {
- next = (MemoryPoolSingleBlock *)(((char *)block) + rawBlockSize);
-#ifdef MEMORYPOOL_DEBUG
- block->initBlock(m_owningPool->getAllocationSize(), this, owningPool->getOwningFactory(), FREE_SINGLEBLOCK_TAG_STRING);
-#else
- block->initBlock(m_owningPool->getAllocationSize(), this, owningPool->getOwningFactory());
-#endif
- block->setNextFreeBlock((i > 0) ? next : NULL);
-#ifdef MEMORYPOOL_DEBUG
- block->debugMarkBlockAsFree();
-#endif
- block = next;
- }
- m_firstFreeBlock = (MemoryPoolSingleBlock *)m_blockData;
-
-#ifdef MEMORYPOOL_INTENSE_VERIFY
- debugMemoryVerifyBlob();
-#endif
-}
-
-//-----------------------------------------------------------------------------
-/**
- add this blob to a given pool's list-of-blobs
-*/
-void MemoryPoolBlob::addBlobToList(MemoryPoolBlob **ppHead, MemoryPoolBlob **ppTail)
-{
- m_prevBlob = *ppTail;
- m_nextBlob = NULL;
-
- if (*ppTail != NULL)
- (*ppTail)->m_nextBlob = this;
-
- if (*ppHead == NULL)
- *ppHead = this;
-
- *ppTail = this;
-}
-
-//-----------------------------------------------------------------------------
-/**
- remove this blob from a given pool's list-of-blobs
-*/
-void MemoryPoolBlob::removeBlobFromList(MemoryPoolBlob **ppHead, MemoryPoolBlob **ppTail)
-{
- if (*ppHead == this)
- *ppHead = this->m_nextBlob;
- else
- this->m_prevBlob->m_nextBlob = this->m_nextBlob;
-
- if (*ppTail == this)
- *ppTail = this->m_prevBlob;
- else
- this->m_nextBlob->m_prevBlob = this->m_prevBlob;
-}
-
-//-----------------------------------------------------------------------------
-/**
- grab a free block from this blob, mark it as taken, and return it.
- this method assumes that there is at least one free block in the blob!
-*/
-MemoryPoolSingleBlock *MemoryPoolBlob::allocateSingleBlock(DECLARE_LITERALSTRING_ARG1)
-{
- DEBUG_ASSERTCRASH(m_firstFreeBlock, ("no free blocks available in MemoryPoolBlob"));
-
- MemoryPoolSingleBlock *block = m_firstFreeBlock;
- m_firstFreeBlock = block->getNextFreeBlock();
- ++m_usedBlocksInBlob;
-
-#ifdef MEMORYPOOL_INTENSE_VERIFY
- block->debugVerifyBlock();
-#endif
-#ifdef MEMORYPOOL_DEBUG
- // this is debug-only because it only serves to update the debugLiteralTagString.
- block->initBlock(m_owningPool->getAllocationSize(), this, m_owningPool->getOwningFactory(), debugLiteralTagString);
-#endif
-#ifdef MEMORYPOOL_INTENSE_VERIFY
- debugMemoryVerifyBlob();
-#endif
-
-// don't need to zero this out... the caller will do that, if necessary
-// memset(block->getUserData(), 0, m_owningPool->getAllocationSize());
-
- return block;
-}
-
-//-----------------------------------------------------------------------------
-/**
- make this block available for future allocations. it is assumed that the block
- belongs to this blob, and is not already free.
-*/
-void MemoryPoolBlob::freeSingleBlock(MemoryPoolSingleBlock *block)
-{
- DEBUG_ASSERTCRASH(block->getOwningBlob() == this, ("block does not belong to this blob"));
-
- block->setNextFreeBlock(m_firstFreeBlock);
- m_firstFreeBlock = block;
- --m_usedBlocksInBlob;
-
-#ifdef MEMORYPOOL_INTENSE_VERIFY
- block->debugVerifyBlock();
-#endif
-#ifdef MEMORYPOOL_DEBUG
- block->debugMarkBlockAsFree();
-#endif
-#ifdef MEMORYPOOL_INTENSE_VERIFY
- debugMemoryVerifyBlob();
-#endif
-
-}
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- Perform internal consistency checking on this blob and all its blocks.
-*/
-void MemoryPoolBlob::debugMemoryVerifyBlob()
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- DEBUG_ASSERTCRASH(m_owningPool != NULL, ("bad owner"));
- DEBUG_ASSERTCRASH(m_usedBlocksInBlob >= 0 && m_usedBlocksInBlob <= m_totalBlocksInBlob, ("unlikely m_usedBlocksInBlob"));
- DEBUG_ASSERTCRASH(m_totalBlocksInBlob > 0, ("unlikely m_totalBlocksInBlob"));
-
- Int rawBlockSize = MemoryPoolSingleBlock::calcRawBlockSize(m_owningPool->getAllocationSize());
- char *blockData = m_blockData;
- for (Int i = m_totalBlocksInBlob-1; i >= 0; i--, blockData += rawBlockSize)
- {
- MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)blockData;
- block->debugVerifyBlock();
- }
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-Int MemoryPoolBlob::debugBlobReportLeaks(const char* owner)
-{
- //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
-
- Int any = 0;
- Int rawBlockSize = MemoryPoolSingleBlock::calcRawBlockSize(m_owningPool->getAllocationSize());
- char *blockData = m_blockData;
- for (Int i = m_totalBlocksInBlob-1; i >= 0; i--, blockData += rawBlockSize)
- {
- MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)blockData;
- any += block->debugSingleBlockReportLeak(owner);
- }
- return any;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- return true iff this block belongs to this blob.
-*/
-Bool MemoryPoolBlob::debugIsBlockInBlob(void *pBlockPtr)
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
- Int rawBlockSize = MemoryPoolSingleBlock::calcRawBlockSize(m_owningPool->getAllocationSize());
- char *blockData = m_blockData;
- for (Int i = m_totalBlocksInBlob-1; i >= 0; i--)
- {
- if ((char *)block == blockData)
- return true;
- blockData += rawBlockSize;
- }
- return false;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- set all the checkpointinfos to null for all the blocks in this blob.
- this does NOT free the checkpointinfos; that is presumed to happen elsewhere.
-*/
-void MemoryPoolBlob::debugResetCheckpoints()
-{
- Int rawBlockSize = MemoryPoolSingleBlock::calcRawBlockSize(m_owningPool->getAllocationSize());
- char *blockData = m_blockData;
- for (Int i = m_totalBlocksInBlob-1; i >= 0; i--, blockData += rawBlockSize)
- {
- MemoryPoolSingleBlock *block = (MemoryPoolSingleBlock *)blockData;
- block->debugResetCheckpoint();
- }
-}
-#endif
-
-//-----------------------------------------------------------------------------
-// METHODS for Checkpointable
-//-----------------------------------------------------------------------------
-
-#ifdef MEMORYPOOL_CHECKPOINTING
-//-----------------------------------------------------------------------------
-/**
- init fields of Checkpointable to safe values.
-*/
-Checkpointable::Checkpointable() :
- m_firstCheckpointInfo(NULL),
- m_cpiEverFailed(false)
-{
-}
-#endif
-
-#ifdef MEMORYPOOL_CHECKPOINTING
-//-----------------------------------------------------------------------------
-/**
- destroy the object. discard any remaining checkpointinfo.
-*/
-Checkpointable::~Checkpointable()
-{
- BlockCheckpointInfo::freeList(&m_firstCheckpointInfo);
- m_firstCheckpointInfo = NULL;
- m_cpiEverFailed = false;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- create a new checkpointinfo and fill it in appropriately. this does NOT
- throw an exception on failure; it quietly returns null if there is not
- enough memory, and sets a flag to indicate our checkpointinfo is not complete.
-*/
-BlockCheckpointInfo *Checkpointable::debugAddCheckpointInfo(
- const char *debugLiteralTagString,
- Int allocCheckpoint,
- Int blockSize
-)
-{
-
- BlockCheckpointInfo *bi = BlockCheckpointInfo::addToList(&m_firstCheckpointInfo, debugLiteralTagString,
- allocCheckpoint, blockSize);
-
- if (bi)
- {
-#ifdef MEMORYPOOL_STACKTRACE
- void **stacktrace = bi->getStacktraceInfo();
- if (theStackTraceDepth > 0 && !TheGlobalData || TheGlobalData->m_checkForLeaks)
- {
- memset(stacktrace, 0, MEMORYPOOL_STACKTRACE_SIZE_BYTES);
- ::FillStackAddresses(stacktrace, min(MEMORYPOOL_STACKTRACE_SIZE, theStackTraceDepth), MEMORYPOOL_STACKTRACE_SKIP_SIZE);
- }
- else
- {
- stacktrace[0] = NULL;
- }
-#endif
- }
- else
- {
- m_cpiEverFailed = true;
- }
-
- return bi;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- print a report on the checkpointinfos belonging to this pool/dma.
-*/
-void Checkpointable::debugCheckpointReport( Int flags, Int startCheckpoint, Int endCheckpoint, const char *poolName )
-{
- DEBUG_ASSERTCRASH(startCheckpoint >= 0 && startCheckpoint <= endCheckpoint, ("bad checkpoints"));
- DEBUG_ASSERTCRASH((flags & _REPORT_CP_ALLOCATED_DONTCARE) != 0, ("bad flags: must set at least one alloc flag"));
- DEBUG_ASSERTCRASH((flags & _REPORT_CP_FREED_DONTCARE) != 0, ("bad flags: must set at least one freed flag"));
-
- if (m_cpiEverFailed)
- {
- DEBUG_LOG((" *** WARNING *** info on freed blocks may be inaccurate or incomplete!"));
- }
-
- for (BlockCheckpointInfo *bi = m_firstCheckpointInfo; bi; bi = bi->getNext())
- {
- BlockCheckpointInfo::doBlockCheckpointReport( bi, poolName, flags, startCheckpoint, endCheckpoint );
- }
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- throw away all the checkpointinfos. this frees the memory, but blocks might still
- refer to the discarded infos; you must zero those elsewhere.
-*/
-void Checkpointable::debugResetCheckpoints()
-{
- BlockCheckpointInfo::freeList(&m_firstCheckpointInfo);
-}
-#endif
-
-//-----------------------------------------------------------------------------
-// METHODS for MemoryPool
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-/**
- init to safe values.
-*/
-MemoryPool::MemoryPool() :
- m_factory(NULL),
- m_nextPoolInFactory(NULL),
- m_poolName(""),
- m_allocationSize(0),
- m_initialAllocationCount(0),
- m_overflowAllocationCount(0),
- m_usedBlocksInPool(0),
- m_totalBlocksInPool(0),
- m_peakUsedBlocksInPool(0),
- m_firstBlob(NULL),
- m_lastBlob(NULL),
- m_firstBlobWithFreeBlocks(NULL)
-{
-}
-
-//-----------------------------------------------------------------------------
-/**
- initialize the memory pool with the given parameters. allocate the initial
- set of blocks.
-*/
-void MemoryPool::init(MemoryPoolFactory *factory, const char *poolName, Int allocationSize, Int initialAllocationCount, Int overflowAllocationCount)
-{
- m_factory = factory;
- m_poolName = poolName;
- m_allocationSize = ::roundUpMemBound(allocationSize); // round up to four-byte boundary
- m_initialAllocationCount = initialAllocationCount;
- m_overflowAllocationCount = overflowAllocationCount;
- m_usedBlocksInPool = 0;
- m_totalBlocksInPool = 0;
- m_peakUsedBlocksInPool = 0;
- m_firstBlob = NULL;
- m_lastBlob = NULL;
- m_firstBlobWithFreeBlocks = NULL;
-
- // go ahead and init the initial block here (will throw on failure)
- createBlob(m_initialAllocationCount);
-}
-
-//-----------------------------------------------------------------------------
-/**
- throw away the pool, and all blocks/blobs associated with it.
-*/
-MemoryPool::~MemoryPool()
-{
- // toss everything. we could do this slightly more efficiently,
- // but not really worth the extra code to do so.
- while (m_firstBlob)
- {
- freeBlob(m_firstBlob);
- }
-}
-
-//-----------------------------------------------------------------------------
-/**
- create a new blob for this pool. if you set up good values for initialAllocationCount,
- this should rarely (if ever) be called (though during development it will be called
- frequently).
-*/
-MemoryPoolBlob* MemoryPool::createBlob(Int allocationCount)
-{
- DEBUG_ASSERTCRASH(allocationCount > 0 && allocationCount%MEM_BOUND_ALIGNMENT==0, ("bad allocationCount (must be >0 and evenly divisible by %d)",MEM_BOUND_ALIGNMENT));
-
- MemoryPoolBlob* blob = new (::sysAllocate(sizeof(MemoryPoolBlob))) MemoryPoolBlob; // will throw on failure
-
- blob->initBlob(this, allocationCount); // will throw on failure
-
- blob->addBlobToList(&m_firstBlob, &m_lastBlob);
-
- DEBUG_ASSERTCRASH(m_firstBlobWithFreeBlocks == NULL, ("DO NOT IGNORE. Please call John McD - x36872 (m_firstBlobWithFreeBlocks != NULL)"));
- m_firstBlobWithFreeBlocks = blob;
-
- // bookkeeping
- m_totalBlocksInPool += allocationCount;
-
-#ifdef MEMORYPOOL_DEBUG
- m_factory->adjustTotals("", 0, allocationCount*getAllocationSize());
-#endif
-
- return blob;
-}
-
-//-----------------------------------------------------------------------------
-/**
- throw away a given blob, and all its blocks. it's assumed that the blob belongs
- to this pool.
-*/
-Int MemoryPool::freeBlob(MemoryPoolBlob* blob)
-{
- DEBUG_ASSERTCRASH(blob, ("null blob"));
- DEBUG_ASSERTCRASH(blob->getOwningPool() == this, ("blob does not belong to this pool"));
-
- // save these for later...
- Int totalBlocksInBlob = blob->getTotalBlockCount();
- Int usedBlocksInBlob = blob->getUsedBlockCount();
- DEBUG_ASSERTCRASH(usedBlocksInBlob == 0, ("freeing a nonempty blob (%d)",usedBlocksInBlob));
-
- // this is really just an estimate... will be too small in debug mode.
- Int amtFreed = totalBlocksInBlob * getAllocationSize() + sizeof(MemoryPoolBlob);
-
- // de-link it from our list
- blob->removeBlobFromList(&m_firstBlob, &m_lastBlob);
-
- // ensure that the 'first free' blob is still a valid blob.
- // (doesn't need to actually have free blocks, just be a valid blob)
- if (m_firstBlobWithFreeBlocks == blob)
- m_firstBlobWithFreeBlocks = m_firstBlob;
-
- // this is evil... since there is no 'placement delete' we must do this the hard way
- // and call the dtor directly. ordinarily this is heinous, but in this case we'll
- // make an exception.
- blob->~MemoryPoolBlob();
- ::sysFree((void *)blob);
-
- // finally... bookkeeping
- m_usedBlocksInPool -= usedBlocksInBlob;
- m_totalBlocksInPool -= totalBlocksInBlob;
-
-#ifdef MEMORYPOOL_DEBUG
- m_factory->adjustTotals("", -usedBlocksInBlob*getAllocationSize(), -totalBlocksInBlob*getAllocationSize());
-#endif
-
- return amtFreed;
-}
-
-//-----------------------------------------------------------------------------
-/**
- allocate a block from this pool and return it, but don't bother zeroing
- out the block. if unable to allocate, throw ERROR_OUT_OF_MEMORY. this
- function will never return null.
-*/
-void* MemoryPool::allocateBlockDoNotZeroImplementation(DECLARE_LITERALSTRING_ARG1)
-{
- ScopedCriticalSection scopedCriticalSection(TheMemoryPoolCriticalSection);
-
- if (m_firstBlobWithFreeBlocks != NULL && !m_firstBlobWithFreeBlocks->hasAnyFreeBlocks())
- {
- // hmm... the current 'free' blob has nothing available. look and see if there
- // are any other existing blobs with freespace.
- MemoryPoolBlob *blob = m_firstBlob;
- for (; blob != NULL; blob = blob->getNextInList())
- {
- if (blob->hasAnyFreeBlocks())
- break;
- }
-
- // note that if we walk thru the list without finding anything, this will
- // reset m_firstBlobWithFreeBlocks to null and fall thru.
- m_firstBlobWithFreeBlocks = blob;
- }
-
- // OK, if we are here then we have no blobs with freespace... darn.
- // allocate an overflow block.
- if (m_firstBlobWithFreeBlocks == NULL)
- {
- if (m_overflowAllocationCount == 0)
- {
- throw ERROR_OUT_OF_MEMORY; // this pool is not allowed to grow
- }
- else
- {
- createBlob(m_overflowAllocationCount); // throws on failure
- }
- }
-
- MemoryPoolBlob *blob = m_firstBlobWithFreeBlocks;
-
- DEBUG_ASSERTCRASH(blob, ("no blob with free blocks available in MemoryPool::allocate"));
-
- MemoryPoolSingleBlock *block = blob->allocateSingleBlock(PASS_LITERALSTRING_ARG1);
- DEBUG_ASSERTCRASH(block, ("should not fail here"));
-
-#ifdef MEMORYPOOL_CHECKPOINTING
- BlockCheckpointInfo *bi = debugAddCheckpointInfo(block->debugGetLiteralTagString(), m_factory->getCurCheckpoint(), getAllocationSize());
- if (bi)
- block->debugSetCheckpointInfo(bi);
-#endif
-
- // bookkeeping
- ++m_usedBlocksInPool;
- if (m_peakUsedBlocksInPool < m_usedBlocksInPool)
- m_peakUsedBlocksInPool = m_usedBlocksInPool;
-
-#ifdef MEMORYPOOL_DEBUG
- m_factory->adjustTotals(debugLiteralTagString, 1*getAllocationSize(), 0);
- #ifdef USE_FILLER_VALUE
- {
- USE_PERF_TIMER(MemoryPoolInitFilling)
- ::memset32(block->getUserData(), s_initFillerValue, getAllocationSize());
- }
- #endif
-#endif
-
- return block->getUserData();
-}
-
-//-----------------------------------------------------------------------------
-/**
- allocate a block from this pool and return it, and zero out the contents
- of the block. if unable to allocate, throw ERROR_OUT_OF_MEMORY. this
- function will never return null.
-*/
-void* MemoryPool::allocateBlockImplementation(DECLARE_LITERALSTRING_ARG1)
-{
- void* p = allocateBlockDoNotZeroImplementation(PASS_LITERALSTRING_ARG1); // throws on failure
- memset(p, 0, getAllocationSize());
- return p;
-}
-
-//-----------------------------------------------------------------------------
-/**
- free a block allocated by this pool. it's ok to pass null.
-*/
-void MemoryPool::freeBlock(void* pBlockPtr)
-{
- if (!pBlockPtr)
- return; // my, that was easy
-
- ScopedCriticalSection scopedCriticalSection(TheMemoryPoolCriticalSection);
-
- MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
- MemoryPoolBlob *blob = block->getOwningBlob();
-#ifdef MEMORYPOOL_DEBUG
- const char* tagString = block->debugGetLiteralTagString();
-#endif
-
- DEBUG_ASSERTCRASH(blob && blob->getOwningPool() == this, ("block does not belong to this pool"));
-
-#ifdef MEMORYPOOL_CHECKPOINTING
- BlockCheckpointInfo *bi = block->debugGetCheckpointInfo();
- DEBUG_ASSERTCRASH(bi, ("hmm, no checkpoint info"));
- if (bi)
- bi->debugSetFreepoint(m_factory->getCurCheckpoint());
-#endif
-
- blob->freeSingleBlock(block);
-
- // if we want to free the blobs as they become empty, do that here.
- // normally we don't bother, but just in case this is ever desired, here's how you'd do it...
- //
- // if (blob->m_usedBlocksInBlob == 0)
- // {
- // freeBlob(blob);
- // return;
- //}
-
- if (!m_firstBlobWithFreeBlocks)
- m_firstBlobWithFreeBlocks = blob;
-
- // bookkeeping
- --m_usedBlocksInPool;
-
-#ifdef MEMORYPOOL_DEBUG
- m_factory->adjustTotals(tagString, -1*getAllocationSize(), 0);
-#endif
-}
-
-//-----------------------------------------------------------------------------
-Int MemoryPool::countBlobsInPool()
-{
- Int blobs = 0;
- for (MemoryPoolBlob* blob = m_firstBlob; blob;)
- {
- ++blobs;
- blob = blob->getNextInList();
- }
- return blobs;
-}
-
-//-----------------------------------------------------------------------------
-/**
- if the pool has any blobs that are completely unused, they are released back to the
- operating system. this will rarely, if ever, be called, but may be useful
- in odd situations.
-*/
-Int MemoryPool::releaseEmpties()
-{
- ScopedCriticalSection scopedCriticalSection(TheMemoryPoolCriticalSection);
-
- Int released = 0;
-
- for (MemoryPoolBlob* blob = m_firstBlob; blob;)
- {
- MemoryPoolBlob* pNext = blob->getNextInList();
- if (blob->getUsedBlockCount() == 0)
- released += freeBlob(blob);
- blob = pNext;
- }
- return released;
-}
-
-
-//-----------------------------------------------------------------------------
-/**
- throw away everything in the pool, but keep the pool itself valid.
-*/
-void MemoryPool::reset()
-{
- ScopedCriticalSection scopedCriticalSection(TheMemoryPoolCriticalSection);
-
- // toss everything. we could do this slightly more efficiently,
- // but not really worth the extra code to do so.
- while (m_firstBlob)
- {
- freeBlob(m_firstBlob);
- }
- m_firstBlob = NULL;
- m_lastBlob = NULL;
- m_firstBlobWithFreeBlocks = NULL;
-
- init(m_factory, m_poolName, m_allocationSize, m_initialAllocationCount, m_overflowAllocationCount); // will throw on failure
-
-}
-
-//-----------------------------------------------------------------------------
-/**
- add this pool to the factory's list-of-pools.
-*/
-void MemoryPool::addToList(MemoryPool **pHead)
-{
- this->m_nextPoolInFactory = *pHead;
- *pHead = this;
-}
-
-//-----------------------------------------------------------------------------
-/**
- remove this pool from the factory's list-of-pools.
-*/
-void MemoryPool::removeFromList(MemoryPool **pHead)
-{
- // this isn't very efficient, but then, we rarely remove pools...
- // usually only at shutdown. so don't bother optimizing.
- MemoryPool *prev = NULL;
- for (MemoryPool *cur = *pHead; cur; cur = cur->m_nextPoolInFactory)
- {
- if (cur == this)
- {
- if (prev)
- {
- prev->m_nextPoolInFactory = this->m_nextPoolInFactory;
- }
- else
- {
- *pHead = this->m_nextPoolInFactory;
- }
- break;
- }
- prev = cur;
- }
-}
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- print a report about per-pool allocation statistics to the debug log.
- if the pool is null, print column headers.
-*/
-/*static*/ void MemoryPool::debugPoolInfoReport( MemoryPool *pool, FILE *fp )
-{
- //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
-
- const char *PREPEND = "POOLINFO"; // allows grepping more easily
-
- if (!pool)
- {
- DEBUG_LOG(("%s,%32s,%6s,%6s,%6s,%6s,%6s,%6s",PREPEND,"POOLNAME","BLKSZ","INIT","OVRFL","USED","TOTAL","PEAK"));
- if( fp )
- fprintf( fp, "%s,%32s,%6s,%6s,%6s,%6s,%6s,%6s\n",PREPEND,"POOLNAME","BLKSZ","INIT","OVRFL","USED","TOTAL","PEAK" );
- }
- else
- {
- DEBUG_LOG(("%s,%32s,%6d,%6d,%6d,%6d,%6d,%6d",PREPEND,
- pool->m_poolName,pool->m_allocationSize,pool->m_initialAllocationCount,pool->m_overflowAllocationCount,
- pool->m_usedBlocksInPool,pool->m_totalBlocksInPool,pool->m_peakUsedBlocksInPool));
- if( fp )
- {
- fprintf( fp, "%s,%32s,%6d,%6d,%6d,%6d,%6d,%6d\n",PREPEND,
- pool->m_poolName,pool->m_allocationSize,pool->m_initialAllocationCount,pool->m_overflowAllocationCount,
- pool->m_usedBlocksInPool,pool->m_totalBlocksInPool,pool->m_peakUsedBlocksInPool );
- }
- }
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-Int MemoryPool::debugPoolReportLeaks( const char* owner )
-{
- //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
-
- Int any = 0;
- for (MemoryPoolBlob* blob = m_firstBlob; blob; blob = blob->getNextInList())
- {
- any += blob->debugBlobReportLeaks(owner);
- }
- return any;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- perform internal consistency checking on the memory pool.
-*/
-void MemoryPool::debugMemoryVerifyPool()
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- Int used = 0;
- Int total = 0;
- for (MemoryPoolBlob* blob = m_firstBlob; blob; blob = blob->getNextInList())
- {
- blob->debugMemoryVerifyBlob();
- used += blob->getUsedBlockCount();
- total += blob->getTotalBlockCount();
- }
- DEBUG_ASSERTCRASH(m_usedBlocksInPool == used, ("used mismatch %d %d",m_usedBlocksInPool,used));
- DEBUG_ASSERTCRASH(m_totalBlocksInPool == total, ("total mismatch %d %d",m_totalBlocksInPool,total));
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- return true iff the block is a valid block in this pool.
-*/
-Bool MemoryPool::debugIsBlockInPool(void *pBlockPtr)
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- if (!pBlockPtr)
- return false;
-
-#ifdef MEMORYPOOL_INTENSE_VERIFY
- debugMemoryVerifyPool();
-#endif
-
- Bool check1 = false, check2 = false;
-
- MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
- MemoryPoolBlob *ownerBlob = block->getOwningBlob();
- for (MemoryPoolBlob* blob = m_firstBlob; blob; blob = blob->getNextInList())
- {
- if (blob->debugIsBlockInBlob(pBlockPtr))
- check1 = true;
-
- if (blob == ownerBlob)
- check2 = true;
- }
-
- DEBUG_ASSERTCRASH(check1 == check2, ("mismatch checks in debugIsBlockInPool"));
-
- return check1 && check2;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- return the tagstring for the block. this will never return null; if
- the block is null or invalid, "FREE_SINGLEBLOCK_TAG_STRING" will be returned.
- it is assumed that the block was allocated by this pool.
-*/
-const char *MemoryPool::debugGetBlockTagString(void *pBlockPtr)
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- if (!pBlockPtr)
- return FREE_SINGLEBLOCK_TAG_STRING;
-
-#ifdef MEMORYPOOL_INTENSE_VERIFY
- debugMemoryVerifyPool();
-#endif
- if (!debugIsBlockInPool(pBlockPtr))
- {
- DEBUG_CRASH(("block is not in this pool"));
- return FREE_SINGLEBLOCK_TAG_STRING;
- }
- MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
- return block->debugGetLiteralTagString();
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- free all checkpointinfo for this pool, and reset all ptrs to checkpointinfo.
-*/
-void MemoryPool::debugResetCheckpoints()
-{
- Checkpointable::debugResetCheckpoints();
- for (MemoryPoolBlob* blob = m_firstBlob; blob; blob = blob->getNextInList())
- {
- blob->debugResetCheckpoints();
- }
-}
-#endif
-
-//-----------------------------------------------------------------------------
-// METHODS for DynamicMemoryAllocator
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-/**
- init the DMA to safe values.
-*/
-DynamicMemoryAllocator::DynamicMemoryAllocator() :
- m_factory(NULL),
- m_nextDmaInFactory(NULL),
- m_numPools(0),
- m_usedBlocksInDma(0),
- m_rawBlocks(NULL)
-{
- for (Int i = 0; i < MAX_DYNAMICMEMORYALLOCATOR_SUBPOOLS; i++)
- m_pools[i] = 0;
-}
-
-//-----------------------------------------------------------------------------
-/**
- Initialize the dma and its subpools.
-*/
-void DynamicMemoryAllocator::init(MemoryPoolFactory *factory, Int numSubPools, const PoolInitRec pParms[])
-{
- const PoolInitRec defaultDMA[7] =
- {
- { "dmaPool_16", 16, 64, 64 },
- { "dmaPool_32", 32, 64, 64 },
- { "dmaPool_64", 64, 64, 64 },
- { "dmaPool_128", 128, 64, 64 },
- { "dmaPool_256", 256, 64, 64 },
- { "dmaPool_512", 512, 64, 64 },
- { "dmaPool_1024", 1024, 64, 64 }
- };
-
- if (numSubPools == 0 || pParms == NULL)
- {
- // use the defaults...
- numSubPools = 7;
- pParms = defaultDMA;
- }
-
-
- m_factory = factory;
- m_numPools = numSubPools;
- if (m_numPools > MAX_DYNAMICMEMORYALLOCATOR_SUBPOOLS)
- m_numPools = MAX_DYNAMICMEMORYALLOCATOR_SUBPOOLS;
- m_usedBlocksInDma = 0;
- for (Int i = 0; i < m_numPools; i++)
- {
- DEBUG_ASSERTCRASH(i == 0 || pParms[i].allocationSize > pParms[i-1].allocationSize, ("alloc size must increase monotonically for DMA"));
- m_pools[i] = m_factory->createMemoryPool(&pParms[i]);
- }
-}
-
-//-----------------------------------------------------------------------------
-/**
- destroy the dma and its subpools.
-*/
-DynamicMemoryAllocator::~DynamicMemoryAllocator()
-{
- DEBUG_ASSERTCRASH(m_usedBlocksInDma == 0, ("destroying a nonempty dma"));
-
- /// @todo this may cause double-destruction of the subpools -- test & fix
- for (Int i = 0; i < m_numPools; i++)
- {
- m_factory->destroyMemoryPool(m_pools[i]);
- m_pools[i] = NULL;
- }
-
- while (m_rawBlocks)
- {
- freeBytes(m_rawBlocks->getUserData());
- }
-}
-
-//-----------------------------------------------------------------------------
-/**
- find the best-fitting subpool in this dma for a given allocation size.
- if no subpool can satisfy the size, return null.
-*/
-MemoryPool *DynamicMemoryAllocator::findPoolForSize(Int allocSize)
-{
- for (Int i = 0; i < m_numPools; i++)
- {
- DEBUG_ASSERTCRASH(m_pools[i], ("null pool"));
- if (allocSize <= m_pools[i]->getAllocationSize())
- return m_pools[i];
- }
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-/**
- add this DMA to the factory's list of dmas.
-*/
-void DynamicMemoryAllocator::addToList(DynamicMemoryAllocator **pHead)
-{
- this->m_nextDmaInFactory = *pHead;
- *pHead = this;
-}
-
-//-----------------------------------------------------------------------------
-/**
- remove this DMA from the factory's list of dmas.
-*/
-void DynamicMemoryAllocator::removeFromList(DynamicMemoryAllocator **pHead)
-{
- // this isn't very efficient, but then, we rarely remove these...
- // usually only at shutdown. so don't bother optimizing.
- DynamicMemoryAllocator *prev = NULL;
- for (DynamicMemoryAllocator *cur = *pHead; cur; cur = cur->m_nextDmaInFactory)
- {
- if (cur == this)
- {
- if (prev)
- {
- prev->m_nextDmaInFactory = this->m_nextDmaInFactory;
- }
- else
- {
- *pHead = this->m_nextDmaInFactory;
- }
- break;
- }
- prev = cur;
- }
-}
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-void DynamicMemoryAllocator::debugIgnoreLeaksForThisBlock(void* pBlockPtr)
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- if (!pBlockPtr)
- return;
-
-#ifdef MEMORYPOOL_CHECK_BLOCK_OWNERSHIP
- DEBUG_ASSERTCRASH(debugIsBlockInDma(pBlockPtr), ("block is not in this dma"));
-#endif
-
- MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
- if (block->getOwningBlob())
- {
-#ifdef MEMORYPOOL_DEBUG
- DEBUG_ASSERTCRASH(findPoolForSize(block->debugGetLogicalSize()) == block->getOwningBlob()->getOwningPool(), ("pool mismatch"));
-#endif
- block->debugIgnoreLeaksForThisBlock();
- }
- else
- {
- DEBUG_CRASH(("cannot currently ignore leaks for raw blocks (allocation too large)"));
- }
-}
-#endif
-
-//-----------------------------------------------------------------------------
-/**
- allocate a chunk-o-bytes from this DMA and return it, but don't bother zeroing
- out the block. if unable to allocate, throw ERROR_OUT_OF_MEMORY. this
- function will never return null.
-*/
-void *DynamicMemoryAllocator::allocateBytesDoNotZeroImplementation(Int numBytes DECLARE_LITERALSTRING_ARG2)
-{
- ScopedCriticalSection scopedCriticalSection(TheDmaCriticalSection);
-
- void *result = NULL;
-
-#ifdef MEMORYPOOL_DEBUG
- DEBUG_ASSERTCRASH(debugLiteralTagString != NULL, ("bad tagstring"));
- Int waste = 0;
-#endif
-
- MemoryPool *pool = findPoolForSize(numBytes);
- if (pool != NULL)
- {
- result = pool->allocateBlockDoNotZeroImplementation(PASS_LITERALSTRING_ARG1);
-#ifdef MEMORYPOOL_DEBUG
- {
- USE_PERF_TIMER(MemoryPoolDebugging)
- waste = pool->getAllocationSize() - numBytes;
- MemoryPoolSingleBlock *wblock = MemoryPoolSingleBlock::recoverBlockFromUserData(result);
- wblock->debugSetWastedSize(waste);
-#ifdef INTENSE_DMA_BOOKKEEPING
- if (doingIntenseDMA == 0)
-#endif
- {
- theWastedDMA += (waste);
- if (thePeakWastedDMA < theWastedDMA)
- thePeakWastedDMA = theWastedDMA;
- }
- }
-#endif // MEMORYPOOL_DEBUG
- }
- else
- {
- // too big for our pools -- just go right to the metal.
- MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::rawAllocateSingleBlock(&m_rawBlocks, numBytes, m_factory PASS_LITERALSTRING_ARG2);
-
-#ifdef MEMORYPOOL_CHECKPOINTING
- BlockCheckpointInfo *bi = debugAddCheckpointInfo(block->debugGetLiteralTagString(), m_factory->getCurCheckpoint(), numBytes);
- if (bi)
- block->debugSetCheckpointInfo(bi);
-#endif
-
- result = block->getUserData();
-
-#ifdef MEMORYPOOL_DEBUG
- m_factory->adjustTotals(debugLiteralTagString, numBytes, numBytes);
- theTotalLargeBlocks += numBytes;
- if (thePeakLargeBlocks < theTotalLargeBlocks)
- thePeakLargeBlocks = theTotalLargeBlocks;
-#endif
- }
-
-#ifdef MEMORYPOOL_DEBUG
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
- theTotalDMA += numBytes;
- if (thePeakDMA < theTotalDMA)
- thePeakDMA = theTotalDMA;
-#ifdef INTENSE_DMA_BOOKKEEPING
- if (isMemoryManagerOfficiallyInited() && doingIntenseDMA == 0)
- {
- ++doingIntenseDMA;
- UsedNPeak& up = TheUsedNPeakMap[debugLiteralTagString];
- up.used += numBytes;
- if (up.peak < up.used)
- up.peak = up.used;
- up.waste += waste;
- if (up.peakwaste < up.waste)
- up.peakwaste = up.waste;
- --doingIntenseDMA;
- }
-#endif
-}
-#endif // MEMORYPOOL_DEBUG
-
- ++m_usedBlocksInDma;
- DEBUG_ASSERTCRASH(m_usedBlocksInDma >= 0, ("negative count for m_usedBlocksInDma"));
-#ifdef MEMORYPOOL_DEBUG
- #ifdef USE_FILLER_VALUE
- {
- USE_PERF_TIMER(MemoryPoolInitFilling)
- ::memset32(result, s_initFillerValue, numBytes);
- }
- #endif
-#endif
- return result;
-}
-
-//-----------------------------------------------------------------------------
-/**
- allocate a chunk-o-bytes from this DMA and return it, and zero out the contents first.
- if unable to allocate, throw ERROR_OUT_OF_MEMORY.
- this function will never return null.
-*/
-void *DynamicMemoryAllocator::allocateBytesImplementation(Int numBytes DECLARE_LITERALSTRING_ARG2)
-{
- void* p = allocateBytesDoNotZeroImplementation(numBytes PASS_LITERALSTRING_ARG2); // throws on failure
- memset(p, 0, numBytes);
- return p;
-}
-
-//-----------------------------------------------------------------------------
-/**
- free a chunk-o-bytes allocated by this dma. it's ok to pass null.
-*/
-void DynamicMemoryAllocator::freeBytes(void* pBlockPtr)
-{
- if (!pBlockPtr)
- return;
-
- ScopedCriticalSection scopedCriticalSection(TheDmaCriticalSection);
-
-#ifdef MEMORYPOOL_CHECK_BLOCK_OWNERSHIP
- DEBUG_ASSERTCRASH(debugIsBlockInDma(pBlockPtr), ("block is not in this dma"));
-#endif
-
- MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
-#ifdef MEMORYPOOL_DEBUG
- Int waste = 0, used = 0;
-#ifdef INTENSE_DMA_BOOKKEEPING
- const char* tagString;
-#endif
- {
- USE_PERF_TIMER(MemoryPoolDebugging)
- waste = 0;
- used = block->debugGetLogicalSize();
- theTotalDMA -= used;
- if (thePeakDMA < theTotalDMA)
- thePeakDMA = theTotalDMA;
- #ifdef INTENSE_DMA_BOOKKEEPING
- tagString = block->debugGetLiteralTagString();
- #endif
- }
-#endif // MEMORYPOOL_DEBUG
-
- if (block->getOwningBlob())
- {
-#ifdef MEMORYPOOL_DEBUG
- {
- USE_PERF_TIMER(MemoryPoolDebugging)
- DEBUG_ASSERTCRASH(findPoolForSize(used) == block->getOwningBlob()->getOwningPool(), ("pool mismatch"));
- #ifdef INTENSE_DMA_BOOKKEEPING
- if (doingIntenseDMA == 0)
- #endif
- {
- waste = block->debugGetWastedSize();
- theWastedDMA -= waste;
- if (thePeakWastedDMA < theWastedDMA)
- thePeakWastedDMA = theWastedDMA;
- }
- }
-#endif // MEMORYPOOL_DEBUG
- block->getOwningBlob()->getOwningPool()->freeBlock(pBlockPtr);
- }
- else
- {
- // was allocated via sysAllocate.
-#ifdef MEMORYPOOL_CHECKPOINTING
- BlockCheckpointInfo *bi = block->debugGetCheckpointInfo();
- DEBUG_ASSERTCRASH(bi, ("hmm, no checkpoint info"));
- if (bi)
- bi->debugSetFreepoint(m_factory->getCurCheckpoint());
-#endif
-
-#ifdef MEMORYPOOL_DEBUG
- m_factory->adjustTotals(block->debugGetLiteralTagString(), -used, -used);
- theTotalLargeBlocks -= used;
- if (thePeakLargeBlocks < theTotalLargeBlocks)
- thePeakLargeBlocks = theTotalLargeBlocks;
- block->debugMarkBlockAsFree();
-#endif
-
- block->removeBlockFromList(&m_rawBlocks);
-
- ::sysFree((void *)block);
-
- }
- --m_usedBlocksInDma;
- DEBUG_ASSERTCRASH(m_usedBlocksInDma >= 0, ("negative count for m_usedBlocksInDma"));
-
-#ifdef INTENSE_DMA_BOOKKEEPING
- if (isMemoryManagerOfficiallyInited() && doingIntenseDMA == 0)
- {
- ++doingIntenseDMA;
- UsedNPeak& up = TheUsedNPeakMap[tagString];
- up.used -= used;
- if (up.peak < up.used)
- up.peak = up.used;
- up.waste -= waste;
- if (up.peakwaste < up.waste)
- up.peakwaste = up.waste;
- --doingIntenseDMA;
- }
-#endif
-
-}
-
-//-----------------------------------------------------------------------------
-Int DynamicMemoryAllocator::getActualAllocationSize(Int numBytes)
-{
- MemoryPool *pool = findPoolForSize(numBytes);
- return pool ? pool->getAllocationSize() : numBytes;
-}
-
-//-----------------------------------------------------------------------------
-/**
- throw away everything in the DMA, but keep the DMA itself valid.
-*/
-void DynamicMemoryAllocator::reset()
-{
- for (Int i = 0; i < m_numPools; i++)
- {
- if (m_pools[i])
- {
- m_pools[i]->reset();
- }
- }
-
- while (m_rawBlocks)
- freeBytes(m_rawBlocks->getUserData());
-
- m_usedBlocksInDma = 0;
-}
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- return true iff the given pool is a subpool of this dma.
-*/
-Bool DynamicMemoryAllocator::debugIsPoolInDma(MemoryPool *pool)
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- if (!pool)
- return false;
-
- for (Int i = 0; i < m_numPools; i++)
- {
- if (m_pools[i] == pool)
- return true;
- }
-
- return false;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- return true iff the block was allocated by this dma
- (either from a subpool or as a raw block).
-*/
-Bool DynamicMemoryAllocator::debugIsBlockInDma(void *pBlockPtr)
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- if (!pBlockPtr)
- return false;
-
- MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
- if (block->getOwningBlob())
- {
- MemoryPool *pool = block->getOwningBlob()->getOwningPool();
- return pool && pool->debugIsBlockInPool(pBlockPtr) && debugIsPoolInDma(pool);
- }
- else
- {
- for (MemoryPoolSingleBlock *b = m_rawBlocks; b; b = b->getNextRawBlock())
- {
- if (b == block)
- return true;
- }
- return false;
- }
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- return the tagstring for the block. this will never return null; if
- the block is null or invalid, "FREE_SINGLEBLOCK_TAG_STRING" will be returned.
- it is assumed that the block was allocated by this dma.
-*/
-const char *DynamicMemoryAllocator::debugGetBlockTagString(void *pBlockPtr)
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- if (!pBlockPtr)
- return FREE_SINGLEBLOCK_TAG_STRING;
-
- if (!debugIsBlockInDma(pBlockPtr))
- {
- DEBUG_CRASH(("block is not in this dma"));
- return FREE_SINGLEBLOCK_TAG_STRING;
- }
- MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
- return block->debugGetLiteralTagString();
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- perform internal consistency checking on this DMA.
-*/
-void DynamicMemoryAllocator::debugMemoryVerifyDma()
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- for (MemoryPoolSingleBlock *b = m_rawBlocks; b; b = b->getNextRawBlock())
- {
- b->debugVerifyBlock();
- }
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- free all checkpointinfo for this dma, and reset all ptrs to checkpointinfo.
-*/
-void DynamicMemoryAllocator::debugResetCheckpoints()
-{
- Checkpointable::debugResetCheckpoints();
- for (MemoryPoolSingleBlock *b = m_rawBlocks; b; b = b->getNextRawBlock())
- {
- b->debugResetCheckpoint();
- }
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- calculate the total number of raw blocks allocated by this dma,
- and the total number of bytes (logical) used by those raw blocks.
-*/
-Int DynamicMemoryAllocator::debugCalcRawBlockBytes(Int *numBlocks)
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- if (numBlocks)
- *numBlocks = 0;
- Int bytes = 0;
- for (MemoryPoolSingleBlock *b = m_rawBlocks; b; b = b->getNextRawBlock())
- {
- if (numBlocks)
- *numBlocks += 1;
- bytes += b->debugGetLogicalSize();
- }
- return bytes;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-Int DynamicMemoryAllocator::debugDmaReportLeaks()
-{
- //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
-
- Int any = false;
- for (MemoryPoolSingleBlock *b = m_rawBlocks; b; b = b->getNextRawBlock())
- {
- any += b->debugSingleBlockReportLeak("(DMA)");
- }
- return any;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- print a report about raw block allocations to the debug log.
-*/
-void DynamicMemoryAllocator::debugDmaInfoReport( FILE *fp )
-{
- //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
-
- const char *PREPEND = "POOLINFO"; // allows grepping more easily
-
- Int numBlocks;
- Int bytes = debugCalcRawBlockBytes(&numBlocks);
- DEBUG_LOG(("%s,Total Raw Blocks = %d",PREPEND,numBlocks));
- DEBUG_LOG(("%s,Total Raw Block Bytes = %d",PREPEND,bytes));
- DEBUG_LOG(("%s,Average Raw Block Size = %d",PREPEND,numBlocks?bytes/numBlocks:0));
- DEBUG_LOG(("%s,Raw Blocks:",PREPEND));
- if( fp )
- {
- fprintf( fp, "%s,Total Raw Blocks = %d\n",PREPEND,numBlocks );
- fprintf( fp, "%s,Total Raw Block Bytes = %d\n",PREPEND,bytes );
- fprintf( fp, "%s,Average Raw Block Size = %d\n",PREPEND,numBlocks?bytes/numBlocks:0 );
- fprintf( fp, "%s,Raw Blocks:\n",PREPEND );
- }
- for (MemoryPoolSingleBlock *b = m_rawBlocks; b; b = b->getNextRawBlock())
- {
- DEBUG_LOG(("%s, Blocksize=%d",PREPEND,b->debugGetLogicalSize()));
- //if( fp )
- //{
- // fprintf( fp, "%s, Blocksize=%d\n",PREPEND,b->debugGetLogicalSize() );
- //}
- }
-
-}
-#endif
-
-//-----------------------------------------------------------------------------
-// METHODS for MemoryPoolFactory
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-/**
- init the factory to safe values.
-*/
-MemoryPoolFactory::MemoryPoolFactory() :
- m_firstPoolInFactory(NULL),
- m_firstDmaInFactory(NULL)
-#ifdef MEMORYPOOL_CHECKPOINTING
- , m_curCheckpoint(0)
-#endif
-#ifdef MEMORYPOOL_DEBUG
- , m_usedBytes(0)
- , m_physBytes(0)
- , m_peakUsedBytes(0)
- , m_peakPhysBytes(0)
-#endif
-{
-#ifdef MEMORYPOOL_DEBUG
- for (int i = 0; i < MAX_SPECIAL_USED; ++i)
- {
- m_usedBytesSpecial[i] = 0;
- m_usedBytesSpecialPeak[i] = 0;
- m_physBytesSpecial[i] = 0;
- m_physBytesSpecialPeak[i] = 0;
- }
- #ifdef USE_FILLER_VALUE
- calcFillerValue(GameClientRandomValue(0, MAX_INIT_FILLER_COUNT-1));
- #endif
-#endif
-}
-//-----------------------------------------------------------------------------
-/**
- initialize the factory.
-*/
-void MemoryPoolFactory::init()
-{
- // my, that was easy
-}
-
-//-----------------------------------------------------------------------------
-/**
- destroy the factory, and all its pools and dmas.
-*/
-MemoryPoolFactory::~MemoryPoolFactory()
-{
- while (m_firstPoolInFactory)
- {
- destroyMemoryPool(m_firstPoolInFactory);
- }
-
- while (m_firstDmaInFactory)
- {
- destroyDynamicMemoryAllocator(m_firstDmaInFactory);
- }
-}
-
-//-----------------------------------------------------------------------------
-/**
- create a new memory pool.
-*/
-MemoryPool *MemoryPoolFactory::createMemoryPool(const PoolInitRec *parms)
-{
- return createMemoryPool(parms->poolName, parms->allocationSize, parms->initialAllocationCount, parms->overflowAllocationCount);
-}
-
-//-----------------------------------------------------------------------------
-/**
- create a new memory pool. (alternate argument list)
-*/
-MemoryPool *MemoryPoolFactory::createMemoryPool(const char *poolName, Int allocationSize, Int initialAllocationCount, Int overflowAllocationCount)
-{
- MemoryPool *pool = findMemoryPool(poolName);
- if (pool)
- {
- DEBUG_ASSERTCRASH(allocationSize == pool->getAllocationSize(), ("pool size mismatch"));
- return pool;
- }
-
- userMemoryAdjustPoolSize(poolName, initialAllocationCount, overflowAllocationCount);
-
- if (initialAllocationCount <= 0 || overflowAllocationCount < 0)
- {
- DEBUG_CRASH(("illegal pool size: %d %d",initialAllocationCount,overflowAllocationCount));
- throw ERROR_OUT_OF_MEMORY;
- }
-
- pool = new (::sysAllocate(sizeof(MemoryPool))) MemoryPool; // will throw on failure
- pool->init(this, poolName, allocationSize, initialAllocationCount, overflowAllocationCount); // will throw on failure
-
- pool->addToList(&m_firstPoolInFactory);
-
- return pool;
-}
-
-//-----------------------------------------------------------------------------
-/**
- find a memory pool with the given name; return null if no such pool exists,
- return null. note that this function isn't particularly fast (it just does
- a linear search), so you should probably cache the result.
-*/
-MemoryPool *MemoryPoolFactory::findMemoryPool(const char *poolName)
-{
- MemoryPool *pool = m_firstPoolInFactory;
- for (; pool; pool = pool->getNextPoolInList())
- {
- if (!strcmp(poolName, pool->getPoolName()))
- {
- DEBUG_ASSERTCRASH(poolName == pool->getPoolName(), ("hmm, ptrs should probably match here"));
- return pool;
- }
- }
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-/**
- destroy the given memory pool. you normally will never need to call this directly.
-*/
-void MemoryPoolFactory::destroyMemoryPool(MemoryPool *pMemoryPool)
-{
- if (!pMemoryPool)
- return;
-
- DEBUG_ASSERTCRASH(pMemoryPool->getUsedBlockCount() == 0, ("destroying a nonempty pool"));
-
- pMemoryPool->removeFromList(&m_firstPoolInFactory);
-
- // this is evil... since there is no 'placement delete' we must do this the hard way
- // and call the dtor directly. ordinarily this is heinous, but in this case we'll
- // make an exception.
- pMemoryPool->~MemoryPool();
- ::sysFree((void *)pMemoryPool);
-}
-
-//-----------------------------------------------------------------------------
-/**
- create a new dynamicMemoryAllocator. You normally will never need to call this directly.
-*/
-DynamicMemoryAllocator *MemoryPoolFactory::createDynamicMemoryAllocator(Int numSubPools, const PoolInitRec pParms[])
-{
- DynamicMemoryAllocator *dma;
-
- dma = new (::sysAllocate(sizeof(DynamicMemoryAllocator))) DynamicMemoryAllocator; // will throw on failure
- dma->init(this, numSubPools, pParms); // will throw on failure
-
- dma->addToList(&m_firstDmaInFactory);
-
- return dma;
-}
-
-//-----------------------------------------------------------------------------
-/**
- destroy the given dynamicMemoryAllocator. You normally will never need to call this directly.
-*/
-void MemoryPoolFactory::destroyDynamicMemoryAllocator(DynamicMemoryAllocator *dma)
-{
- if (!dma)
- return;
-
- dma->removeFromList(&m_firstDmaInFactory);
-
- // this is evil... since there is no 'placement delete' we must do this the hard way
- // and call the dtor directly. ordinarily this is heinous, but in this case we'll
- // make an exception.
- dma->~DynamicMemoryAllocator();
- ::sysFree((void *)dma);
-}
-
-//-----------------------------------------------------------------------------
-/**
- throw away everything in all pools/dmas owned by this factory, but keep the factory
- and pools/dmas themselves valid.
-*/
-void MemoryPoolFactory::reset()
-{
-#ifdef MEMORYPOOL_CHECKPOINTING
- debugResetCheckpoints();
-#endif
-
- for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
- {
- pool->reset();
- }
- for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
- {
- dma->reset();
- }
-
-#ifdef MEMORYPOOL_DEBUG
- m_usedBytes = 0;
- m_physBytes = 0;
- m_peakUsedBytes = 0;
- m_peakPhysBytes = 0;
- for (int i = 0; i < MAX_SPECIAL_USED; ++i)
- {
- m_usedBytesSpecial[i] = 0;
- m_usedBytesSpecialPeak[i] = 0;
- m_physBytesSpecial[i] = 0;
- m_physBytesSpecialPeak[i] = 0;
- }
- #ifdef USE_FILLER_VALUE
- calcFillerValue(GameClientRandomValue(0, MAX_INIT_FILLER_COUNT-1));
- #endif
-#endif
-}
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-static const char* s_specialPrefixes[MAX_SPECIAL_USED] =
-{
- "Misc", // the catchall for stuff that doesn't match others
- "W3D_",
- "W3A_",
- "STL_",
- "STR_",
- NULL
-};
-
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- perform bookkeeping on memory usage statistics.
-*/
-void MemoryPoolFactory::adjustTotals(const char* tagString, Int usedDelta, Int physDelta)
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- m_usedBytes += usedDelta;
- m_physBytes += physDelta;
- if (m_peakUsedBytes < m_usedBytes)
- m_peakUsedBytes = m_usedBytes;
- if (m_peakPhysBytes < m_physBytes)
- m_peakPhysBytes = m_physBytes;
-
- int found = 0; // if no matches found, goes into slot zero
- for (int i = 1; i < MAX_SPECIAL_USED; ++i) // start at 1, not zero
- {
- if (s_specialPrefixes[i] == NULL)
- break;
-
- if (strncmp(tagString, s_specialPrefixes[i], strlen(s_specialPrefixes[i])) == 0)
- {
- found = i;
- break;
- }
- }
- m_usedBytesSpecial[found] += usedDelta;
- m_physBytesSpecial[found] += physDelta;
- if (m_usedBytesSpecialPeak[found] < m_usedBytesSpecial[found])
- m_usedBytesSpecialPeak[found] = m_usedBytesSpecial[found];
- if (m_physBytesSpecialPeak[found] < m_physBytesSpecial[found])
- m_physBytesSpecialPeak[found] = m_physBytesSpecial[found];
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-void MemoryPoolFactory::debugSetInitFillerIndex(Int index)
-{
- #ifdef USE_FILLER_VALUE
- if (index < 0 || index >= MAX_INIT_FILLER_COUNT)
- index = GameClientRandomValue(0, MAX_INIT_FILLER_COUNT-1);
- calcFillerValue(index);
- #endif
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- perform internal consistency checking on the factory, and all of its
- pools and dmas.
-*/
-void MemoryPoolFactory::debugMemoryVerify()
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- Int used = 0, phys = 0;
-
- for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
- {
- pool->debugMemoryVerifyPool();
- used += pool->getUsedBlockCount()*pool->getAllocationSize();
- phys += pool->getTotalBlockCount()*pool->getAllocationSize();
- }
-
- for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
- {
- dma->debugMemoryVerifyDma();
- Int tmp = dma->debugCalcRawBlockBytes(NULL);
- used += tmp;
- phys += tmp;
- }
-
- DEBUG_ASSERTCRASH(used == m_usedBytes, ("used count mismatch"));
- DEBUG_ASSERTCRASH(phys == m_physBytes, ("phys count mismatch"));
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- return true iff the block was allocated by any of the pools/dmas owned
- by this factory.
-*/
-Bool MemoryPoolFactory::debugIsBlockInAnyPool(void *pBlock)
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
-#ifdef MEMORYPOOL_INTENSE_VERIFY
- debugMemoryVerify();
-#endif
- for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
- {
- if (pool->debugIsBlockInPool(pBlock))
- return true;
- }
-
- for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
- {
- if (dma->debugIsBlockInDma(pBlock))
- return true;
- }
-
- return false;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- return the tagstring for this block. this will never return null; if
- the block is null or invalid, "FREE_SINGLEBLOCK_TAG_STRING" will be returned.
- it is assumed that the block was allocated by this factory.
-*/
-const char *MemoryPoolFactory::debugGetBlockTagString(void *pBlockPtr)
-{
- USE_PERF_TIMER(MemoryPoolDebugging)
-
- if (!pBlockPtr)
- return FREE_SINGLEBLOCK_TAG_STRING;
-
-#ifdef MEMORYPOOL_INTENSE_VERIFY
- debugMemoryVerify();
-#endif
- if (!debugIsBlockInAnyPool(pBlockPtr))
- {
- DEBUG_CRASH(("block is not in this factory"));
- return FREE_SINGLEBLOCK_TAG_STRING;
- }
- MemoryPoolSingleBlock *block = MemoryPoolSingleBlock::recoverBlockFromUserData(pBlockPtr);
- return block->debugGetLiteralTagString();
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- set a new checkpoint for all future blocks allocated/freed by this factory's pools/dmas.
-*/
-Int MemoryPoolFactory::debugSetCheckpoint()
-{
- return ++m_curCheckpoint;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_CHECKPOINTING
-/**
- throw away all checkpoint info for all pools/dmas.
-*/
-void MemoryPoolFactory::debugResetCheckpoints()
-{
- for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
- {
- pool->debugResetCheckpoints();
- }
- for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
- {
- dma->debugResetCheckpoints();
- }
- m_curCheckpoint = 0;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-void MemoryPoolFactory::memoryPoolUsageReport( const char* filename, FILE *appendToFileInstead )
-{
-#ifdef MEMORYPOOL_DEBUG
- //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
-
- FILE* perfStatsFile = NULL;
- Int totalNamedPoolPeak = 0;
-
- if( !appendToFileInstead )
- {
- char tmp[256];
- strcpy(tmp,filename);
- strcat(tmp,".csv");
- perfStatsFile = fopen(tmp, "w");
- }
- else
- {
- perfStatsFile = appendToFileInstead;
- }
-
- if (perfStatsFile == NULL)
- {
- DEBUG_CRASH(("could not open/create perf file %s -- is it open in another app?",filename));
- return;
- }
-
- Int lineIdx = 0;
- MemoryPool *pool = m_firstPoolInFactory;
-#ifdef INTENSE_DMA_BOOKKEEPING
- UsedNPeakMap::const_iterator it = TheUsedNPeakMap.begin();
-#endif
- for (;;)
- {
- Bool keepGoing = false;
- if (pool)
- {
- if (lineIdx == 0)
- {
- fprintf(perfStatsFile, "%s,%d","Unpooled Large Blocks (>1024 bytes)",thePeakLargeBlocks/1024);
- }
- else
- {
- Int sz = pool->getAllocationSize();
- Int initial = pool->getInitialBlockCount()*sz;
- Int peak = pool->getPeakBlockCount()*sz;
- Int waste = initial - peak;
- if (waste < 0) waste = 0;
- fprintf(perfStatsFile, "%s,%d,%d",pool->getPoolName(),peak/1024,waste/1024);
- totalNamedPoolPeak += peak;
- pool = pool->getNextPoolInList();
- }
- keepGoing = true;
- }
- else
- {
- fprintf(perfStatsFile, ",,");
- }
-
-#ifdef INTENSE_DMA_BOOKKEEPING
- if (it != TheUsedNPeakMap.end())
- {
- Int wastepct = (it->second.peakwaste * 100) / (it->second.peak + it->second.peakwaste);
- fprintf(perfStatsFile, ",,,,%s,%d,%d,%d",it->first,it->second.peak/1024,it->second.peakwaste/1024,wastepct);
- ++it;
- keepGoing = true;
- }
- else
- {
- fprintf(perfStatsFile, ",,,,,,,");
- }
-#endif
-
- if (lineIdx < MAX_SPECIAL_USED && s_specialPrefixes[lineIdx] != NULL)
- {
- fprintf(perfStatsFile, ",,,%s,%d",s_specialPrefixes[lineIdx],m_usedBytesSpecialPeak[lineIdx]/1024);
- keepGoing = true;
- }
-
- fprintf(perfStatsFile, "\n");
- ++lineIdx;
-
- if (!keepGoing)
- break;
- }
-
- fflush(perfStatsFile);
-
- if( !appendToFileInstead )
- {
- fclose(perfStatsFile);
- }
-#endif
-}
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_DEBUG
-/**
- send a memory reports (based on the flags/checkpoints) to the debug log.
-*/
-void MemoryPoolFactory::debugMemoryReport(Int flags, Int startCheckpoint, Int endCheckpoint, FILE *fp )
-{
- //USE_PERF_TIMER(MemoryPoolDebugging) skip end-of-run reporting stuff
-
-#ifdef ALLOW_DEBUG_UTILS
- Int oldFlags = DebugGetFlags();
- DebugSetFlags(oldFlags & ~DEBUG_FLAG_PREPEND_TIME);
-#endif
-
-#ifdef MEMORYPOOL_CHECKPOINTING
- Bool doBlockReport = (flags & _REPORT_CP_ALLOCATED_DONTCARE) != 0 && (flags & _REPORT_CP_FREED_DONTCARE) != 0;
- DEBUG_ASSERTCRASH(startCheckpoint >= 0 && startCheckpoint <= endCheckpoint && endCheckpoint <= m_curCheckpoint, ("bad checkpoints"));
- DEBUG_ASSERTCRASH(((flags & _REPORT_CP_ALLOCATED_DONTCARE) != 0) == ((flags & _REPORT_CP_FREED_DONTCARE) != 0), ("bad flags: must set at both alloc and free flag"));
-#endif
-
- debugMemoryVerify();
-
- if (flags & REPORT_FACTORYINFO)
- {
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("Begin Factory Info Report"));
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("Bytes in use (logical) = %d",m_usedBytes));
- DEBUG_LOG(("Bytes in use (physical) = %d",m_physBytes));
- DEBUG_LOG(("PEAK Bytes in use (logical) = %d",m_peakUsedBytes));
- DEBUG_LOG(("PEAK Bytes in use (physical) = %d",m_peakPhysBytes));
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("End Factory Info Report"));
- DEBUG_LOG(("------------------------------------------"));
- if( fp )
- {
- fprintf( fp, "------------------------------------------\n" );
- fprintf( fp, "Begin Factory Info Report\n" );
- fprintf( fp, "------------------------------------------\n" );
- fprintf( fp, "Bytes in use (logical) = %d\n",m_usedBytes );
- fprintf( fp, "Bytes in use (physical) = %d\n",m_physBytes );
- fprintf( fp, "PEAK Bytes in use (logical) = %d\n",m_peakUsedBytes );
- fprintf( fp, "PEAK Bytes in use (physical) = %d\n",m_peakPhysBytes );
- fprintf( fp, "------------------------------------------\n" );
- fprintf( fp, "End Factory Info Report\n" );
- fprintf( fp, "------------------------------------------\n" );
- }
- }
-
- if (flags & REPORT_POOLINFO)
- {
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("Begin Pool Info Report"));
- DEBUG_LOG(("------------------------------------------"));
- if( fp )
- {
- fprintf( fp, "------------------------------------------\n" );
- fprintf( fp, "Begin Pool Info Report\n" );
- fprintf( fp, "------------------------------------------\n" );
- }
- MemoryPool::debugPoolInfoReport( NULL, fp );
- for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
- {
- MemoryPool::debugPoolInfoReport( pool, fp );
- }
- for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
- {
- dma->debugDmaInfoReport( fp );
- }
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("End Pool Info Report"));
- DEBUG_LOG(("------------------------------------------"));
- if( fp )
- {
- fprintf( fp, "------------------------------------------\n" );
- fprintf( fp, "End Pool Info Report\n" );
- fprintf( fp, "------------------------------------------\n" );
- }
- }
-
- if (flags & REPORT_POOL_OVERFLOW)
- {
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("Begin Pool Overflow Report"));
- DEBUG_LOG(("------------------------------------------"));
- MemoryPool *pool = m_firstPoolInFactory;
- for (; pool; pool = pool->getNextPoolInList())
- {
- if (pool->getPeakBlockCount() > pool->getInitialBlockCount())
- {
- DEBUG_LOG(("*** Pool %s overflowed initial allocation of %d (peak allocation was %d)",pool->getPoolName(),pool->getInitialBlockCount(),pool->getPeakBlockCount()));
- }
- }
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("End Pool Overflow Report"));
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("Begin Pool Underflow Report"));
- DEBUG_LOG(("------------------------------------------"));
- for (pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
- {
- Int peak = pool->getPeakBlockCount()*pool->getAllocationSize();
- Int initial = pool->getInitialBlockCount()*pool->getAllocationSize();
- if (peak < initial/2 && (initial - peak) > 4096)
- {
- DEBUG_LOG(("*** Pool %s used less than half its initial allocation of %d (peak allocation was %d, wasted %dk)",
- pool->getPoolName(),pool->getInitialBlockCount(),pool->getPeakBlockCount(),(initial - peak)/1024));
- }
- }
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("End Pool Underflow Report"));
- DEBUG_LOG(("------------------------------------------"));
- }
-
- if( flags & REPORT_SIMPLE_LEAKS )
- {
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("Begin Simple Leak Report"));
- DEBUG_LOG(("------------------------------------------"));
- Int any = 0;
- for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
- {
- any += pool->debugPoolReportLeaks( pool->getPoolName() );
- }
- for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
- {
- any += dma->debugDmaReportLeaks();
- }
- DEBUG_ASSERTCRASH(!any, ("There were %d memory leaks. Please fix them.",any));
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("End Simple Leak Report"));
- DEBUG_LOG(("------------------------------------------"));
- }
-
-#ifdef MEMORYPOOL_CHECKPOINTING
- if (doBlockReport)
- {
- const char* nm = (this == TheMemoryPoolFactory) ? "TheMemoryPoolFactory" : "*** UNKNOWN *** MemoryPoolFactory";
-
- DEBUG_LOG_RAW(("\n"));
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("Begin Block Report for %s", nm));
- DEBUG_LOG(("------------------------------------------"));
- char buf[256] = "";
- if (flags & _REPORT_CP_ALLOCATED_BEFORE) strcat(buf, "AllocBefore ");
- if (flags & _REPORT_CP_ALLOCATED_BETWEEN) strcat(buf, "AllocBetween ");
- if (flags & _REPORT_CP_FREED_BEFORE) strcat(buf, "FreedBefore ");
- if (flags & _REPORT_CP_FREED_BETWEEN) strcat(buf, "FreedBetween ");
- if (flags & _REPORT_CP_FREED_NEVER) strcat(buf, "StillExisting ");
- DEBUG_LOG(("Options: Between checkpoints %d and %d, report on (%s)",startCheckpoint,endCheckpoint,buf));
- DEBUG_LOG(("------------------------------------------"));
-
- BlockCheckpointInfo::doBlockCheckpointReport( NULL, "", 0, 0, 0 );
- for (MemoryPool *pool = m_firstPoolInFactory; pool; pool = pool->getNextPoolInList())
- {
- pool->debugCheckpointReport(flags, startCheckpoint, endCheckpoint, pool->getPoolName());
- }
- for (DynamicMemoryAllocator *dma = m_firstDmaInFactory; dma; dma = dma->getNextDmaInList())
- {
- dma->debugCheckpointReport(flags, startCheckpoint, endCheckpoint, "(Oversized)");
- }
-
- DEBUG_LOG(("------------------------------------------"));
- DEBUG_LOG(("End Block Report for %s", nm));
- DEBUG_LOG(("------------------------------------------"));
- }
-#endif
-
-#ifdef ALLOW_DEBUG_UTILS
- DebugSetFlags(oldFlags);
-#endif
-}
-#endif
-
-//-----------------------------------------------------------------------------
-// GLOBAL FUNCTIONS
-//-----------------------------------------------------------------------------
-
-static int theLinkTester = 0;
-
-//-----------------------------------------------------------------------------
-void* STLSpecialAlloc::allocate(size_t __n)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator new"));
- return TheDynamicMemoryAllocator->allocateBytes(__n, "STL_");
-}
-
-//-----------------------------------------------------------------------------
-void STLSpecialAlloc::deallocate(void* __p, size_t)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator new"));
- TheDynamicMemoryAllocator->freeBytes(__p);
-}
-
-//-----------------------------------------------------------------------------
-/**
- overload for global operator new; send requests to TheDynamicMemoryAllocator.
-*/
-void *operator new(size_t size)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator new"));
- return TheDynamicMemoryAllocator->allocateBytes(size, "global operator new");
-}
-
-//-----------------------------------------------------------------------------
-/**
- overload for global operator new[]; send requests to TheDynamicMemoryAllocator.
-*/
-void *operator new[](size_t size)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator new"));
- return TheDynamicMemoryAllocator->allocateBytes(size, "global operator new[]");
-}
-
-//-----------------------------------------------------------------------------
-/**
- overload for global operator delete; send requests to TheDynamicMemoryAllocator.
-*/
-void operator delete(void *p)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator delete"));
- TheDynamicMemoryAllocator->freeBytes(p);
-}
-
-//-----------------------------------------------------------------------------
-/**
- overload for global operator delete[]; send requests to TheDynamicMemoryAllocator.
-*/
-void operator delete[](void *p)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator delete"));
- TheDynamicMemoryAllocator->freeBytes(p);
-}
-
-//-----------------------------------------------------------------------------
-/**
- overload for global operator new (MFC debug version); send requests to TheDynamicMemoryAllocator.
-*/
-void* operator new(size_t size, const char * fname, int)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator new"));
-#ifdef MEMORYPOOL_DEBUG
- return TheDynamicMemoryAllocator->allocateBytesImplementation(size, fname);
-#else
- return TheDynamicMemoryAllocator->allocateBytesImplementation(size);
-#endif
-}
-
-//-----------------------------------------------------------------------------
-/**
- overload for global operator delete (MFC debug version); send requests to TheDynamicMemoryAllocator.
-*/
-void operator delete(void * p, const char *, int)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator delete"));
- TheDynamicMemoryAllocator->freeBytes(p);
-}
-
-//-----------------------------------------------------------------------------
-/**
- overload for global operator new (MFC debug version); send requests to TheDynamicMemoryAllocator.
-*/
-void* operator new[](size_t size, const char * fname, int)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator new"));
-#ifdef MEMORYPOOL_DEBUG
- return TheDynamicMemoryAllocator->allocateBytesImplementation(size, fname);
-#else
- return TheDynamicMemoryAllocator->allocateBytesImplementation(size);
-#endif
-}
-
-//-----------------------------------------------------------------------------
-/**
- overload for global operator delete (MFC debug version); send requests to TheDynamicMemoryAllocator.
-*/
-void operator delete[](void * p, const char *, int)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager before calling global operator delete"));
- TheDynamicMemoryAllocator->freeBytes(p);
-}
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_OVERRIDE_MALLOC
-void *calloc(size_t a, size_t b)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager"));
- return TheDynamicMemoryAllocator->allocateBytes(a * b, "calloc");
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_OVERRIDE_MALLOC
-void free(void * p)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager"));
- TheDynamicMemoryAllocator->freeBytes(p);
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_OVERRIDE_MALLOC
-void *malloc(size_t a)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- DEBUG_ASSERTCRASH(TheDynamicMemoryAllocator != NULL, ("must init memory manager"));
- return TheDynamicMemoryAllocator->allocateBytesDoNotZero(a, "malloc");
-}
-#endif
-
-//-----------------------------------------------------------------------------
-#ifdef MEMORYPOOL_OVERRIDE_MALLOC
-void *realloc(void *p, size_t s)
-{
- DEBUG_CRASH(("realloc is evil. do not call it."));
- throw ERROR_OUT_OF_MEMORY;
-}
-#endif
-
-//-----------------------------------------------------------------------------
-/**
- Initialize the memory manager, and create TheMemoryPoolFactory and TheDynamicMemoryAllocator.
-*/
-void initMemoryManager()
-{
- if (TheMemoryPoolFactory == NULL)
- {
- Int numSubPools;
- const PoolInitRec *pParms;
- userMemoryManagerGetDmaParms(&numSubPools, &pParms);
- TheMemoryPoolFactory = new (::sysAllocate(sizeof(MemoryPoolFactory))) MemoryPoolFactory; // will throw on failure
- TheMemoryPoolFactory->init(); // will throw on failure
- TheDynamicMemoryAllocator = TheMemoryPoolFactory->createDynamicMemoryAllocator(numSubPools, pParms); // will throw on failure
- userMemoryManagerInitPools();
- thePreMainInitFlag = false;
-
- DEBUG_INIT(DEBUG_FLAGS_DEFAULT);
- DEBUG_LOG(("*** Initialized the Memory Manager"));
- }
- else
- {
- if (thePreMainInitFlag)
- {
- // quietly ignore the call
- }
- else
- {
- DEBUG_CRASH(("Memory Manager is already initialized"));
- }
- }
-
- char* linktest;
-
- theLinkTester = 0;
-
- linktest = new char;
- delete linktest;
-
- linktest = new char[8];
- delete [] linktest;
-
- linktest = new char('\0');
- delete linktest;
-
-#ifdef MEMORYPOOL_OVERRIDE_MALLOC
- linktest = (char*)malloc(1);
- free(linktest);
-
- linktest = (char*)calloc(1,1);
- free(linktest);
-#endif
-
-#ifdef MEMORYPOOL_OVERRIDE_MALLOC
- if (theLinkTester != 10)
-#else
- if (theLinkTester != 6)
-#endif
- {
- DEBUG_CRASH(("Wrong operator new/delete linked in! Fix this..."));
- }
-
- theMainInitFlag = true;
-
-}
-
-//-----------------------------------------------------------------------------
-Bool isMemoryManagerOfficiallyInited()
-{
- return theMainInitFlag;
-}
-
-//-----------------------------------------------------------------------------
-/**
- Initialize the memory manager, and create TheMemoryPoolFactory and TheDynamicMemoryAllocator.
- This is only called if memory is allocated prior to the normal call to initMemoryManager
- (generally via a static C++ ctor).
-*/
-static void preMainInitMemoryManager()
-{
- if (TheMemoryPoolFactory == NULL)
- {
-
- Int numSubPools;
- const PoolInitRec *pParms;
- userMemoryManagerGetDmaParms(&numSubPools, &pParms);
- TheMemoryPoolFactory = new (::sysAllocate(sizeof(MemoryPoolFactory))) MemoryPoolFactory; // will throw on failure
- TheMemoryPoolFactory->init(); // will throw on failure
-
- TheDynamicMemoryAllocator = TheMemoryPoolFactory->createDynamicMemoryAllocator(numSubPools, pParms); // will throw on failure
- userMemoryManagerInitPools();
- thePreMainInitFlag = true;
-
- DEBUG_INIT(DEBUG_FLAGS_DEFAULT);
- DEBUG_LOG(("*** Initialized the Memory Manager prior to main!"));
- }
-}
-
-//-----------------------------------------------------------------------------
-/**
- shutdown the memory manager and discard all memory. Note: if preMainInitMemoryManager()
- was called prior to initMemoryManager(), this call will do nothing.
-*/
-void shutdownMemoryManager()
-{
- if (thePreMainInitFlag)
- {
- #ifdef MEMORYPOOL_DEBUG
- DEBUG_LOG(("*** Memory Manager was inited prior to main -- skipping shutdown!"));
- #endif
- }
- else
- {
- if (TheDynamicMemoryAllocator)
- {
- DEBUG_ASSERTCRASH(TheMemoryPoolFactory, ("hmm, no factory"));
- if (TheMemoryPoolFactory)
- TheMemoryPoolFactory->destroyDynamicMemoryAllocator(TheDynamicMemoryAllocator);
- TheDynamicMemoryAllocator = NULL;
- }
-
- if (TheMemoryPoolFactory)
- {
- // this is evil... since there is no 'placement delete' we must do this the hard way
- // and call the dtor directly. ordinarily this is heinous, but in this case we'll
- // make an exception.
- TheMemoryPoolFactory->~MemoryPoolFactory();
- ::sysFree((void *)TheMemoryPoolFactory);
- TheMemoryPoolFactory = NULL;
- }
-
- #ifdef MEMORYPOOL_DEBUG
- DEBUG_LOG(("Peak system allocation was %d bytes",thePeakSystemAllocationInBytes));
- DEBUG_LOG(("Wasted DMA space (peak) was %d bytes",thePeakWastedDMA));
- DEBUG_ASSERTCRASH(theTotalSystemAllocationInBytes == 0, ("Leaked a total of %d raw bytes", theTotalSystemAllocationInBytes));
- #endif
- }
-
- theMainInitFlag = false;
-
- DEBUG_SHUTDOWN();
-}
-
-//-----------------------------------------------------------------------------
-void* createW3DMemPool(const char *poolName, int allocationSize)
-{
- ++theLinkTester;
- preMainInitMemoryManager();
- MemoryPool* pool = TheMemoryPoolFactory->createMemoryPool(poolName, allocationSize, 0, 0);
- DEBUG_ASSERTCRASH(pool && pool->getAllocationSize() == allocationSize, ("bad w3d pool"));
- return pool;
-}
-
-//-----------------------------------------------------------------------------
-void* allocateFromW3DMemPool(void* pool, int allocationSize)
-{
- DEBUG_ASSERTCRASH(pool, ("pool is null"));
- DEBUG_ASSERTCRASH(pool && ((MemoryPool*)pool)->getAllocationSize() == allocationSize, ("bad w3d pool size %s",((MemoryPool*)pool)->getPoolName()));
- return ((MemoryPool*)pool)->allocateBlock("allocateFromW3DMemPool");
-}
-
-//-----------------------------------------------------------------------------
-void* allocateFromW3DMemPool(void* pool, int allocationSize, const char* msg, int unused)
-{
- DEBUG_ASSERTCRASH(pool, ("pool is null"));
- DEBUG_ASSERTCRASH(pool && ((MemoryPool*)pool)->getAllocationSize() == allocationSize, ("bad w3d pool size %s",((MemoryPool*)pool)->getPoolName()));
- return ((MemoryPool*)pool)->allocateBlock(msg);
-}
-
-//-----------------------------------------------------------------------------
-void freeFromW3DMemPool(void* pool, void* p)
-{
- DEBUG_ASSERTCRASH(pool, ("pool is null"));
- ((MemoryPool*)pool)->freeBlock(p);
-}
diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt
index d947c86b0ad..5546c7bc915 100644
--- a/GeneralsMD/Code/GameEngine/CMakeLists.txt
+++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt
@@ -45,7 +45,7 @@ set(GAMEENGINE_SRC
# Include/Common/GameDefines.h
Include/Common/GameEngine.h
Include/Common/GameLOD.h
- Include/Common/GameMemory.h
+# Include/Common/GameMemory.h
# Include/Common/GameMusic.h
# Include/Common/GameSounds.h
Include/Common/GameSpyMiscPreferences.h
@@ -1138,14 +1138,16 @@ set(GAMEENGINE_SRC
if(RTS_GAMEMEMORY_ENABLE)
# Uses the original Game Memory implementation.
list(APPEND GAMEENGINE_SRC
- Source/Common/System/GameMemory.cpp
- Source/Common/System/MemoryInit.cpp
+# Source/Common/System/GameMemory.cpp
+# Source/Common/System/GameMemoryInitDMA_GeneralsMD.inl
+# Source/Common/System/GameMemoryInitPools_GeneralsMD.inl
+# Source/Common/System/MemoryInit.cpp
)
else()
# Uses the null implementation when disabled.
list(APPEND GAMEENGINE_SRC
- Source/Common/System/GameMemoryNull.cpp
- Include/Common/GameMemoryNull.h
+# Source/Common/System/GameMemoryNull.cpp
+# Include/Common/GameMemoryNull.h
)
endif()
diff --git a/GeneralsMD/Code/GameEngine/Include/Common/GameMemoryNull.h b/GeneralsMD/Code/GameEngine/Include/Common/GameMemoryNull.h
deleted file mode 100644
index bf0ee87bc3d..00000000000
--- a/GeneralsMD/Code/GameEngine/Include/Common/GameMemoryNull.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
-** Command & Conquer Generals Zero Hour(tm)
-** Copyright 2025 TheSuperHackers
-**
-** This program is free software: you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation, either version 3 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program. If not, see .
-*/
-
-#pragma once
-
-#define allocateBytes(ARGCOUNT,ARGLITERAL) allocateBytesImplementation(ARGCOUNT)
-#define allocateBytesDoNotZero(ARGCOUNT,ARGLITERAL) allocateBytesDoNotZeroImplementation(ARGCOUNT)
-#define newInstanceDesc(ARGCLASS,ARGLITERAL) new ARGCLASS
-#define newInstance(ARGCLASS) new ARGCLASS
-#define MSGNEW(MSG) new
-#define NEW new
-
-
-/**
- The DynamicMemoryAllocator class is used to handle unpredictably-sized
- allocation requests.
-*/
-class DynamicMemoryAllocator
-{
-public:
-
- /// allocate bytes from this pool. (don't call directly; use allocateBytes() macro)
- void *allocateBytesImplementation(Int numBytes);
-
- /// like allocateBytesImplementation, but zeroes the memory before returning
- void *allocateBytesDoNotZeroImplementation(Int numBytes);
-
-#ifdef MEMORYPOOL_DEBUG
- void debugIgnoreLeaksForThisBlock(void* pBlockPtr);
-#endif
-
- /// free the bytes. (assumes allocated by this dma.)
- void freeBytes(void* pMem);
-
- /**
- return the actual number of bytes that would be allocated
- if you tried to allocate the given size.
- */
- Int getActualAllocationSize(Int numBytes);
-};
-
-
-/**
- The class that manages all the MemoryPools and DynamicMemoryAllocators.
- Usually you will create exactly one of these (TheMemoryPoolFactory)
- and use it for everything.
-*/
-class MemoryPoolFactory
-{
-public:
-
- void memoryPoolUsageReport( const char* filename, FILE *appendToFileInstead = NULL );
-
-#ifdef MEMORYPOOL_DEBUG
-
- void debugMemoryReport(Int flags, Int startCheckpoint, Int endCheckpoint, FILE *fp = NULL );
- void debugSetInitFillerIndex(Int index);
-
-#endif
-};
-
-
-#define MEMORY_POOL_GLUE_WITHOUT_GCMP(ARGCLASS) \
-protected: \
- virtual ~ARGCLASS(); \
-public: /* include this line at the end to reset visibility to 'public' */
-
-
-#define MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(ARGCLASS, ARGPOOLNAME) \
- MEMORY_POOL_GLUE_WITHOUT_GCMP(ARGCLASS)
-
-
-// this is the version for an Abstract Base Class, which will never be instantiated...
-#define MEMORY_POOL_GLUE_ABC(ARGCLASS) \
-protected: \
- virtual ~ARGCLASS(); \
-public: /* include this line at the end to reset visibility to 'public' */
-
-
-/**
- This class is provided as a simple and safe way to integrate C++ object allocation
- into MemoryPool usage. To use it, you must have your class inherit from
- MemoryPoolObject, then put the macro MEMORY_POOL_GLUE(MyClassName, "MyPoolName")
- at the start of your class definition. (This does not create the pool itself -- you
- must create that manually using MemoryPoolFactory::createMemoryPool)
-*/
-class MemoryPoolObject
-{
-protected:
-
- /** ensure that all destructors are virtual */
- virtual ~MemoryPoolObject() { }
-
-public:
-
- static void deleteInstanceInternal(MemoryPoolObject* mpo)
- {
- delete mpo;
- }
-};
-
-inline void deleteInstance(MemoryPoolObject* mpo)
-{
- MemoryPoolObject::deleteInstanceInternal(mpo);
-}
-
-
-/**
- Initialize the memory manager. Construct a new MemoryPoolFactory and
- DynamicMemoryAllocator and store 'em in the singletons of the relevant
- names.
-*/
-extern void initMemoryManager();
-
-/**
- return true if initMemoryManager() has been called.
- return false if only preMainInitMemoryManager() has been called.
-*/
-extern Bool isMemoryManagerOfficiallyInited();
-
-/**
- Shut down the memory manager. Throw away TheMemoryPoolFactory and
- TheDynamicMemoryAllocator.
-*/
-extern void shutdownMemoryManager();
-
-extern MemoryPoolFactory *TheMemoryPoolFactory;
-extern DynamicMemoryAllocator *TheDynamicMemoryAllocator;
-
-
-// TheSuperHackers @info
-// The new operator overloads will zero all memory after allocation.
-// This replicates the behavior of the original Game Memory implementation and is necessary to avoid crashing the game,
-// where data is not properly zero initialized. Disable these operators when fixing those issues.
-#ifndef DISABLE_GAMEMEMORY_NEW_OPERATORS
-
-extern void * __cdecl operator new(size_t size);
-extern void __cdecl operator delete(void *p);
-
-extern void * __cdecl operator new[](size_t size);
-extern void __cdecl operator delete[](void *p);
-
-// additional overloads to account for VC/MFC funky versions
-extern void* __cdecl operator new(size_t size, const char *, int);
-extern void __cdecl operator delete(void *p, const char *, int);
-
-extern void* __cdecl operator new[](size_t size, const char *, int);
-extern void __cdecl operator delete[](void *p, const char *, int);
-
-#endif
diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/GameMemoryNull.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/GameMemoryNull.cpp
deleted file mode 100644
index 8520a77de9b..00000000000
--- a/GeneralsMD/Code/GameEngine/Source/Common/System/GameMemoryNull.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
-** Command & Conquer Generals Zero Hour(tm)
-** Copyright 2025 TheSuperHackers
-**
-** This program is free software: you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation, either version 3 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program. If not, see .
-*/
-
-#include "PreRTS.h"
-
-#include
-
-#include "Common/GameMemoryNull.h"
-
-static Bool theMainInitFlag = false;
-
-// ----------------------------------------------------------------------------
-// PUBLIC DATA
-// ----------------------------------------------------------------------------
-
-MemoryPoolFactory *TheMemoryPoolFactory = NULL;
-DynamicMemoryAllocator *TheDynamicMemoryAllocator = NULL;
-
-//-----------------------------------------------------------------------------
-// METHODS for DynamicMemoryAllocator
-//-----------------------------------------------------------------------------
-
-/**
- allocate a chunk-o-bytes from this DMA and return it, but don't bother zeroing
- out the block. if unable to allocate, throw ERROR_OUT_OF_MEMORY. this
- function will never return null.
-
- added code to make sure we're on a DWord boundary, throw exception if not
-*/
-void *DynamicMemoryAllocator::allocateBytesDoNotZeroImplementation(Int numBytes)
-{
- void *p = malloc(numBytes);
- if (p == NULL)
- throw ERROR_OUT_OF_MEMORY;
- return p;
-}
-
-/**
- allocate a chunk-o-bytes from this DMA and return it, and zero out the contents first.
- if unable to allocate, throw ERROR_OUT_OF_MEMORY.
- this function will never return null.
-*/
-void *DynamicMemoryAllocator::allocateBytesImplementation(Int numBytes)
-{
- void* p = allocateBytesDoNotZeroImplementation(numBytes); // throws on failure
- memset(p, 0, numBytes);
- return p;
-}
-
-/**
- free a chunk-o-bytes allocated by this dma. it's ok to pass null.
-*/
-void DynamicMemoryAllocator::freeBytes(void* pBlockPtr)
-{
- free(pBlockPtr);
-}
-
-Int DynamicMemoryAllocator::getActualAllocationSize(Int numBytes)
-{
- return numBytes;
-}
-
-#ifdef MEMORYPOOL_DEBUG
-void DynamicMemoryAllocator::debugIgnoreLeaksForThisBlock(void* pBlockPtr)
-{
-}
-#endif
-
-//-----------------------------------------------------------------------------
-// METHODS for MemoryPoolFactory
-//-----------------------------------------------------------------------------
-
-void MemoryPoolFactory::memoryPoolUsageReport( const char* filename, FILE *appendToFileInstead )
-{
-}
-
-#ifdef MEMORYPOOL_DEBUG
-void MemoryPoolFactory::debugMemoryReport(Int flags, Int startCheckpoint, Int endCheckpoint, FILE *fp )
-{
-}
-void MemoryPoolFactory::debugSetInitFillerIndex(Int index)
-{
-}
-#endif
-
-//-----------------------------------------------------------------------------
-// GLOBAL FUNCTIONS
-//-----------------------------------------------------------------------------
-
-/**
- Initialize the memory manager, and create TheMemoryPoolFactory and TheDynamicMemoryAllocator.
-*/
-void initMemoryManager()
-{
- if (TheMemoryPoolFactory == NULL && TheDynamicMemoryAllocator == NULL)
- {
- TheMemoryPoolFactory = new (malloc(sizeof MemoryPoolFactory)) MemoryPoolFactory;
- TheDynamicMemoryAllocator = new (malloc(sizeof DynamicMemoryAllocator)) DynamicMemoryAllocator;
-
- DEBUG_INIT(DEBUG_FLAGS_DEFAULT);
- DEBUG_LOG(("*** Initialized the Null Memory Manager"));
- }
- else
- {
- DEBUG_CRASH(("Null Memory Manager is already initialized"));
- }
-
- theMainInitFlag = true;
-}
-
-//-----------------------------------------------------------------------------
-Bool isMemoryManagerOfficiallyInited()
-{
- return theMainInitFlag;
-}
-
-//-----------------------------------------------------------------------------
-/**
- shutdown the memory manager and discard all memory. Note: if preMainInitMemoryManager()
- was called prior to initMemoryManager(), this call will do nothing.
-*/
-void shutdownMemoryManager()
-{
- if (TheDynamicMemoryAllocator != NULL)
- {
- TheDynamicMemoryAllocator->~DynamicMemoryAllocator();
- free((void *)TheDynamicMemoryAllocator);
- TheDynamicMemoryAllocator = NULL;
- }
-
- if (TheMemoryPoolFactory != NULL)
- {
- TheMemoryPoolFactory->~MemoryPoolFactory();
- free((void *)TheMemoryPoolFactory);
- TheMemoryPoolFactory = NULL;
- }
-
- theMainInitFlag = false;
-
- DEBUG_SHUTDOWN();
-}
-
-
-#ifndef DISABLE_GAMEMEMORY_NEW_OPERATORS
-
-extern void * __cdecl operator new(size_t size)
-{
- void *p = malloc(size);
- if (p == NULL)
- throw ERROR_OUT_OF_MEMORY;
- memset(p, 0, size);
- return p;
-}
-
-extern void __cdecl operator delete(void *p)
-{
- free(p);
-}
-
-extern void * __cdecl operator new[](size_t size)
-{
- void *p = malloc(size);
- if (p == NULL)
- throw ERROR_OUT_OF_MEMORY;
- memset(p, 0, size);
- return p;
-}
-
-extern void __cdecl operator delete[](void *p)
-{
- free(p);
-}
-
-// additional overloads to account for VC/MFC funky versions
-extern void* __cdecl operator new(size_t size, const char *, int)
-{
- void *p = malloc(size);
- if (p == NULL)
- throw ERROR_OUT_OF_MEMORY;
- memset(p, 0, size);
- return p;
-}
-
-extern void __cdecl operator delete(void *p, const char *, int)
-{
- free(p);
-}
-
-extern void* __cdecl operator new[](size_t size, const char *, int)
-{
- void *p = malloc(size);
- if (p == NULL)
- throw ERROR_OUT_OF_MEMORY;
- memset(p, 0, size);
- return p;
-}
-
-extern void __cdecl operator delete[](void *p, const char *, int)
-{
- free(p);
-}
-
-#endif
diff --git a/scripts/cpp/unify_move_files.py b/scripts/cpp/unify_move_files.py
index 9d34e5fb985..d43aa334965 100644
--- a/scripts/cpp/unify_move_files.py
+++ b/scripts/cpp/unify_move_files.py
@@ -156,6 +156,16 @@ def main():
#unify_move_file(Game.ZEROHOUR, "GameEngineDevice/Source/VideoDevice/FFmpeg/FFmpegFile.cpp", Game.CORE, "GameEngineDevice/Source/VideoDevice/FFmpeg/FFmpegFile.cpp")
#unify_move_file(Game.ZEROHOUR, "GameEngineDevice/Source/VideoDevice/FFmpeg/FFmpegVideoPlayer.cpp", Game.CORE, "GameEngineDevice/Source/VideoDevice/FFmpeg/FFmpegVideoPlayer.cpp")
+ #unify_file(Game.ZEROHOUR, "GameEngine/Include/Common/GameMemory.h", Game.CORE, "GameEngine/Include/Common/GameMemory.h")
+ #unify_file(Game.ZEROHOUR, "GameEngine/Include/Common/GameMemoryNull.h", Game.CORE, "GameEngine/Include/Common/GameMemoryNull.h")
+ #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/GameMemory.cpp", Game.CORE, "GameEngine/Source/Common/System/GameMemory.cpp")
+ #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/GameMemoryNull.cpp", Game.CORE, "GameEngine/Source/Common/System/GameMemoryNull.cpp")
+ #unify_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/MemoryInit.cpp", Game.CORE, "GameEngine/Source/Common/System/GameMemoryInit.cpp")
+ #unify_move_file(Game.GENERALS, "GameEngine/Source/Common/System/GameMemoryInitDMA_Generals.inl", Game.CORE, "GameEngine/Source/Common/System/GameMemoryInitDMA_Generals.inl")
+ #unify_move_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/GameMemoryInitDMA_GeneralsMD.inl", Game.CORE, "GameEngine/Source/Common/System/GameMemoryInitDMA_GeneralsMD.inl")
+ #unify_move_file(Game.GENERALS, "GameEngine/Source/Common/System/GameMemoryInitPools_Generals.inl", Game.CORE, "GameEngine/Source/Common/System/GameMemoryInitPools_Generals.inl")
+ #unify_move_file(Game.ZEROHOUR, "GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl", Game.CORE, "GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl")
+
return