On 6/30/07, The Watermelon <[EMAIL PROTECTED]> wrote:
1.Fixed some problems with aiChoose* functions,the griditeration didnt check
whether the units from iteration tiles is 'died' or not.
Good!
2.Changed assert (psDroid->numWeaps < MAX_DROIDWEAPS) to (psDroid->numWeaps
<= MAX_DROIDWEAPS),because the numWeaps is equal to
MAX_DROIDWEAPS(MAX_DROIDWEAPS is used to check against array index)
I do not understand this one.
I have committed parts of the patch to make it easier to handle, and
the remaining part is attached. Otherwise there should be no changes.
- Per
Index: src/base.h
===================================================================
--- src/base.h (revision 1637)
+++ src/base.h (working copy)
@@ -54,7 +54,8 @@
UWORD x,y,z; /* Object's location */ \
float direction; /* Object's direction +ve rotation about y axis*/ \
SWORD pitch; /* Object's pitch +ve nose up*/ \
- SWORD roll /* Object's roll +ve left up, right down */
+ SWORD roll; /* Object's roll +ve left up, right down */ \
+ SWORD refCount /* Object's reference count, for safe deallocation */
#define BASE_ELEMENTS2(pointerType) \
SCREEN_DISP_DATA sDisplay; /* screen coordinate details */ \
Index: src/structure.h
===================================================================
--- src/structure.h (revision 1637)
+++ src/structure.h (working copy)
@@ -28,6 +28,7 @@
#include "objectdef.h"
#include "structuredef.h"
+#include "objmem.h"
// how long to wait between CALL_STRUCT_ATTACKED's - plus how long to flash on radar for
#define ATTACK_CB_PAUSE 5000
@@ -396,10 +397,21 @@
selected - returns TRUE if valid*/
extern BOOL lasSatStructSelected(STRUCTURE *psStruct);
-static inline void setStructureTarget(STRUCTURE *psBuilding, BASE_OBJECT *psNewTarget, UWORD idx)
+#define setStructureTarget(x,y,z) _setStructureTarget(x,y,z, __FILE__, __LINE__)
+
+static inline void _setStructureTarget(STRUCTURE *psBuilding, BASE_OBJECT *psNewTarget, UWORD idx, char *file, int line)
{
assert(idx < STRUCT_MAXWEAPS);
- psBuilding->psTarget[idx] = psNewTarget;
+ if (psBuilding->psTarget[idx] != NULL)
+ {
+ decrRefCount(psBuilding->psTarget[idx], file, line);
+ psBuilding->psTarget[idx] = NULL;
+ }
+ if (psNewTarget != NULL)
+ {
+ psBuilding->psTarget[idx] = psNewTarget;
+ incrRefCount(psNewTarget, file, line);
+ }
}
#define CHECK_STRUCTURE(object) \
@@ -416,6 +428,7 @@
assert(object->turretRotation[i] <= 360); \
if (object->psTarget[i]) \
{ \
+ assert(object->psTarget[i]->refCount > 0); \
CHECK_OBJECT(object->psTarget[i]); \
} \
} \
Index: src/projectile.h
===================================================================
--- src/projectile.h (revision 1637)
+++ src/projectile.h (working copy)
@@ -126,19 +126,50 @@
// Watermelon:naybor related functions
extern void projGetNaybors(PROJ_OBJECT *psObj);
-static inline void setProjectileDestination(PROJ_OBJECT *psProj, BASE_OBJECT *psObj)
+#define setProjectileDestination(x,y) _setProjectileDestination(x,y, __FILE__, __LINE__)
+#define setProjectileSource(x,y) _setProjectileSource(x,y, __FILE__, __LINE__)
+#define setProjectileDamaged(x,y) _setProjectileDamaged(x,y, __FILE__, __LINE__)
+
+static inline void _setProjectileDestination(PROJ_OBJECT *psProj, BASE_OBJECT *psObj, char *file, int line)
{
- psProj->psDest = psObj;
+ if (psProj->psDest != NULL)
+ {
+ decrRefCount(psProj->psDest, file, line);
+ psProj->psDest = NULL;
+ }
+ if (psObj != NULL)
+ {
+ psProj->psDest = psObj;
+ incrRefCount(psObj, file, line);
+ }
}
-static inline void setProjectileSource(PROJ_OBJECT *psProj, BASE_OBJECT *psObj)
+static inline void _setProjectileSource(PROJ_OBJECT *psProj, BASE_OBJECT *psObj, char *file, int line)
{
- psProj->psSource = psObj;
+ if (psProj->psSource != NULL)
+ {
+ decrRefCount(psProj->psSource, file, line);
+ psProj->psSource = NULL;
+ }
+ if (psObj != NULL)
+ {
+ psProj->psSource = psObj;
+ incrRefCount(psObj, file, line);
+ }
}
-static inline void setProjectileDamaged(PROJ_OBJECT *psProj, BASE_OBJECT *psObj)
+static inline void _setProjectileDamaged(PROJ_OBJECT *psProj, BASE_OBJECT *psObj, char *file, int line)
{
- psProj->psDamaged = psObj;
+ if (psProj->psDamaged != NULL)
+ {
+ decrRefCount(psProj->psDamaged, file, line);
+ psProj->psDamaged = NULL;
+ }
+ if (psObj != NULL)
+ {
+ psProj->psDamaged = psObj;
+ incrRefCount(psObj, file, line);
+ }
}
/* assert if projectile is bad */
@@ -153,6 +184,9 @@
if (object->psDest) CHECK_OBJECT(object->psDest); \
if (object->psSource) CHECK_OBJECT(object->psSource); \
if (object->psDamaged) CHECK_OBJECT(object->psDamaged); \
+ assert(!object->psDest || object->psDest->refCount > 0); \
+ assert(!object->psSource || object->psSource->refCount > 0); \
+ assert(!object->psDamaged || object->psDamaged->refCount > 0); \
} while (0)
Index: src/objmem.c
===================================================================
--- src/objmem.c (revision 1637)
+++ src/objmem.c (working copy)
@@ -21,7 +21,27 @@
* ObjMem.c
*
* Object memory management functions.
+ *
+ * It works like this:
*
+ * Dead objects are moved from the general lists to the destroyed lists for a while
+ * until they are released for good. This ensures that pointer references remain
+ * valid. Then we need a way to check that the objects are ready for release:
+ *
+ * Old version (Pumpkin solution): Each object has a 'died' field which records the time
+ * frame it tied. At the end of the next turn, it is deleted. During the next turn, all
+ * objects are supposed to be iterated through by an update function that checks this
+ * 'died' field and change all references to dead objects. This way no object should point
+ * to the memory of a released object.
+ *
+ * The new version (Ressurection project solution): Each object has a reference count,
+ * and each time some object points at this object, we increase the reference count,
+ * and each time another object stops pointing at it, the counter is decreased. The
+ * object is not released from memory until its reference counter is zero.
+ *
+ * Debug builds currently only use the new way, while release builds use both for
+ * maximum safety (err on the memory usage side rather than on the crash game side).
+ *
*/
#include <string.h>
@@ -106,7 +126,8 @@
free(psObj);
}
-/* General housekeeping for the object system */
+/* General housekeeping for the object system. We use both old and new systems for
+ * non-debug builds for maximum safety! */
void objmemUpdate(void)
{
BASE_OBJECT *psCurr, *psNext, *psPrev;
@@ -122,11 +143,12 @@
scrvUpdateBasePointers();
}
- /* Go through the destroyed objects list looking for objects that
- were destroyed before this turn */
-
/* First remove the objects from the start of the list */
- while (psDestroyedObj != NULL && psDestroyedObj->died != gameTime)
+ while (psDestroyedObj != NULL && psDestroyedObj->refCount == 0
+#ifndef DEBUG
+ && pDestroyed->died != gameTime
+#endif
+ )
{
psNext = psDestroyedObj->psNext;
objmemDestroy(psDestroyedObj);
@@ -138,17 +160,9 @@
for(psCurr = psPrev = psDestroyedObj; psCurr != NULL; psCurr = psNext)
{
psNext = psCurr->psNext;
- if (psCurr->died != gameTime)
+ if (gameTime == psDestroyedObj->died)
{
- objmemDestroy(psCurr);
-
- /*set the linked list up - you will never be deleting the top
- of the list, so don't have to check*/
- psPrev->psNext = psNext;
- }
- else
- {
- // do the object died callback
+ // do the object died callback now
psCBObjDestroyed = psCurr;
eventFireCallbackTrigger((TRIGGER_TYPE)CALL_OBJ_DESTROYED);
switch (psCurr->type)
@@ -169,6 +183,18 @@
psPrev = psCurr;
}
+ if (psDestroyedObj->refCount == 0
+#ifndef DEBUG
+ && pDestroyed->died != gameTime
+#endif
+ )
+ {
+ objmemDestroy(psCurr);
+
+ /*set the linked list up - you will never be deleting the top
+ of the list because of the above hack, so don't have to check*/
+ psPrev->psNext = psNext;
+ }
}
}
@@ -218,6 +244,7 @@
objID++;
newObject->player = (UBYTE)player;
newObject->died = 0;
+ newObject->refCount = 0;
return newObject;
}
Index: src/order.c
===================================================================
--- src/order.c (revision 1637)
+++ src/order.c (working copy)
@@ -2810,15 +2810,14 @@
else
{
psDroid->asOrderList[psDroid->listSize].order = psOrder->order;
- //psDroid->asOrderList[psDroid->listSize].psObj = psOrder->psObj;
- if (psOrder->order == DORDER_BUILD || psOrder->order == DORDER_LINEBUILD)
- {
- setDroidOrderTarget(psDroid, (void *)psOrder->psStats, psDroid->listSize);
+ if (psOrder->order == DORDER_BUILD || psOrder->order == DORDER_LINEBUILD)
+ {
+ setDroidOrderTarget(psDroid, (void *)psOrder->psStats, psDroid->listSize, OT_STATS);
}
- else
- {
- setDroidOrderTarget(psDroid, (void *)psOrder->psObj[0], psDroid->listSize);
- }
+ else
+ {
+ setDroidOrderTarget(psDroid, (void *)psOrder->psObj[0], psDroid->listSize, OT_BASE_OBJECT);
+ }
psDroid->asOrderList[psDroid->listSize].x = (UWORD)psOrder->x;
psDroid->asOrderList[psDroid->listSize].y = (UWORD)psOrder->y;
psDroid->asOrderList[psDroid->listSize].x2 = (UWORD)psOrder->x2;
Index: src/objmem.h
===================================================================
--- src/objmem.h (revision 1637)
+++ src/objmem.h (working copy)
@@ -27,6 +27,7 @@
#define _objmem_h
#include "objectdef.h"
+#include "base.h"
//the died flag for a droid is set to this when it gets added to the non-current list
#define NOT_CURRENT_LIST 1
@@ -117,5 +118,25 @@
#ifdef DEBUG
extern void checkFactoryFlags(void);
#endif
+
+#define incrRefCount(x, file, line) _incrRefCount(x, file, line, __FUNCTION__)
+#define decrRefCount(x, file, line) _decrRefCount(x, file, line, __FUNCTION__)
+
+// using void to silence warnings
+static inline void _incrRefCount(void *psObj, char *file, int line, const char *function)
+{
+ ((BASE_OBJECT *)psObj)->refCount++;
+ debug(LOG_MEMORY, "refCount %s from %s:%d %p ++ for a total of %hd",
+ function, file, line, psObj, ((BASE_OBJECT *)psObj)->refCount);
+}
+
+static inline void _decrRefCount(void *psObj, char *file, int line, const char *function)
+{
+ assert(((BASE_OBJECT *)psObj)->refCount > 0);
+ ((BASE_OBJECT *)psObj)->refCount--;
+ debug(LOG_MEMORY, "refCount %s from %s:%d %p -- for a total of %hd",
+ function, file, line, psObj, ((BASE_OBJECT *)psObj)->refCount);
+}
+
#endif
Index: src/order.h
===================================================================
--- src/order.h (revision 1637)
+++ src/order.h (working copy)
@@ -128,6 +128,13 @@
DSS_VTOLPROD_END = 0x10000000,
} SECONDARY_STATE;
+/* different types of order target object in order list */
+typedef enum _order_target_type {
+ OT_BASE_OBJECT, //BASE_OBJECT target
+ OT_STATS, //STATS target
+ OT_MAX_TYPES, //number of target types
+} ORDER_TARGET_TYPE;
+
// masks for the secondary order state
#define DSS_ARANGE_MASK 0x000003
#define DSS_REPLEV_MASK 0x00000c
@@ -251,16 +258,34 @@
// clear all targets (but not action targets)
void clearDroidTargets(DROID *psDroid);
-static inline void setDroidOrderTarget(DROID *psDroid, void *psNewObject, SDWORD idx)
+#define setDroidOrderTarget(x,y,z,a) _setDroidOrderTarget(x,y,z,a, __FILE__, __LINE__)
+#define removeDroidOrderTarget(x,y) _removeDroidOrderTarget(x,y, __FILE__, __LINE__)
+
+static inline void _setDroidOrderTarget(DROID *psDroid, void *psNewObject, SDWORD idx, ORDER_TARGET_TYPE type, char *file, int line)
{
- assert(idx >= 0 && idx < ORDER_LIST_MAX);
- psDroid->asOrderList[idx].psOrderTarget = psNewObject;
+ assert(idx >= 0 && idx < ORDER_LIST_MAX && type < OT_MAX_TYPES);
+ if (psNewObject != NULL)
+ {
+ psDroid->asOrderList[idx].psOrderTarget = psNewObject;
+ psDroid->asOrderList[idx].type = type;
+ if (type == OT_BASE_OBJECT)
+ {
+ incrRefCount((BASE_OBJECT*)psDroid->asOrderList[idx].psOrderTarget, file, line);
+ }
+ }
}
-static inline void removeDroidOrderTarget(DROID *psDroid, SDWORD idx)
+static inline void _removeDroidOrderTarget(DROID *psDroid, SDWORD idx, char *file, int line)
{
assert(idx >= 0 && idx < ORDER_LIST_MAX);
- psDroid->asOrderList[idx].psOrderTarget = NULL;
+ if (psDroid->asOrderList[idx].psOrderTarget != NULL)
+ {
+ if (psDroid->asOrderList[idx].type == OT_BASE_OBJECT)
+ {
+ decrRefCount((BASE_OBJECT*)psDroid->asOrderList[idx].psOrderTarget, file, line);
+ }
+ psDroid->asOrderList[idx].psOrderTarget = NULL;
+ }
}
#endif
Index: src/droid.h
===================================================================
--- src/droid.h (revision 1637)
+++ src/droid.h (working copy)
@@ -27,6 +27,7 @@
#define _droid_h
#include "objectdef.h"
+#include "objmem.h"
#include "lib/gamelib/gtime.h"
#define OFF_SCREEN 9999 // world->screen check - alex
@@ -386,36 +387,97 @@
/*returns TRUE if droid type is one of the Cyborg types*/
extern BOOL cyborgDroid(DROID *psDroid);
-/** helper functions for future refcount patch **/
+#define setDroidTarget(x,y,z) _setDroidTarget(x,y,z, __FILE__, __LINE__)
+#define setDroidActionTarget(x,y,z) _setDroidActionTarget(x,y,z, __FILE__, __LINE__)
+#define setDroidBase(x,y) _setDroidBase(x,y, __FILE__, __LINE__)
+#define setSaveDroidTarget(x,y,z) _setSaveDroidTarget(x,y,z, __FILE__, __LINE__)
+#define setSaveDroidActionTarget(x,y,z) _setSaveDroidActionTarget(x,y,z, __FILE__, __LINE__)
+#define setSaveDroidBase(x,y) _setSaveDroidBase(x,y, __FILE__, __LINE__)
-static inline void setDroidTarget(DROID *psDroid, BASE_OBJECT *psNewTarget, UWORD idx)
+static inline void _setDroidTarget(DROID *psDroid, BASE_OBJECT *psNewTarget, UWORD idx, char *file, int line)
{
- psDroid->psTarget[idx] = psNewTarget;
+ assert(idx < DROID_MAXWEAPS);
+ if (psDroid->psTarget[idx] != NULL)
+ {
+ decrRefCount(psDroid->psTarget[idx], file, line);
+ psDroid->psTarget[idx] = NULL;
+ }
+ if (psNewTarget != NULL)
+ {
+ psDroid->psTarget[idx] = psNewTarget;
+ incrRefCount(psNewTarget, file, line);
+ }
}
-static inline void setDroidActionTarget(DROID *psDroid, BASE_OBJECT *psNewTarget, UWORD idx)
+static inline void _setDroidActionTarget(DROID *psDroid, BASE_OBJECT *psNewTarget, UWORD idx, char *file, int line)
{
- psDroid->psActionTarget[idx] = psNewTarget;
+ assert(idx < DROID_MAXWEAPS);
+ if (psDroid->psActionTarget[idx] != NULL)
+ {
+ decrRefCount(psDroid->psActionTarget[idx], file, line);
+ psDroid->psActionTarget[idx] = NULL;
+ }
+ if (psNewTarget != NULL)
+ {
+ psDroid->psActionTarget[idx] = psNewTarget;
+ incrRefCount(psNewTarget, file, line);
+ }
}
-static inline void setDroidBase(DROID *psDroid, STRUCTURE *psNewBase)
+static inline void _setDroidBase(DROID *psDroid, STRUCTURE *psNewBase, char *file, int line)
{
- psDroid->psBaseStruct = psNewBase;
+ if (psDroid->psBaseStruct != NULL)
+ {
+ decrRefCount(psDroid->psBaseStruct, file, line);
+ psDroid->psBaseStruct = NULL;
+ }
+ if (psNewBase != NULL)
+ {
+ psDroid->psBaseStruct = psNewBase;
+ incrRefCount(psNewBase, file, line);
+ }
}
-static inline void setSaveDroidTarget(DROID *psSaveDroid, BASE_OBJECT *psNewTarget, UWORD idx)
+//save equivalent of setDroid* functions
+static inline void _setSaveDroidTarget(DROID *psSaveDroid, BASE_OBJECT *psNewTarget, UWORD idx, char *file, int line)
{
- psSaveDroid->psTarget[idx] = psNewTarget;
+ assert(idx < DROID_MAXWEAPS);
+ if (psNewTarget != NULL)
+ {
+ psSaveDroid->psTarget[idx] = psNewTarget;
+ incrRefCount(psNewTarget, file, line);
+ }
+ else
+ {
+ psSaveDroid->psTarget[idx] = NULL;
+ }
}
-static inline void setSaveDroidActionTarget(DROID *psSaveDroid, BASE_OBJECT *psNewTarget, UWORD idx)
+static inline void _setSaveDroidActionTarget(DROID *psSaveDroid, BASE_OBJECT *psNewTarget, UWORD idx, char *file, int line)
{
- psSaveDroid->psActionTarget[idx] = psNewTarget;
+ assert(idx < DROID_MAXWEAPS);
+ if (psNewTarget != NULL)
+ {
+ psSaveDroid->psActionTarget[idx] = psNewTarget;
+ incrRefCount(psNewTarget, file, line);
+ }
+ else
+ {
+ psSaveDroid->psActionTarget[idx] = NULL;
+ }
}
-static inline void setSaveDroidBase(DROID *psSaveDroid, STRUCTURE *psNewBase)
+static inline void _setSaveDroidBase(DROID *psSaveDroid, STRUCTURE *psNewBase, char *file, int line)
{
- psSaveDroid->psBaseStruct = psNewBase;
+ if (psNewBase != NULL)
+ {
+ psSaveDroid->psBaseStruct = psNewBase;
+ incrRefCount(psNewBase, file, line);
+ }
+ else
+ {
+ psSaveDroid->psBaseStruct = NULL;
+ }
}
/* assert if droid is bad */
@@ -429,19 +491,25 @@
assert(droid->type == OBJ_DROID); \
\
assert(droid->direction <= 360.0f && droid->direction >= 0.0f); \
- assert(droid->numWeaps < DROID_MAXWEAPS); \
+ assert(droid->numWeaps <= DROID_MAXWEAPS); \
assert(droid->listSize < ORDER_LIST_MAX); \
assert(droid->player < MAX_PLAYERS); \
\
for (i = 0; i < DROID_MAXWEAPS; ++i) \
+ { \
assert(droid->turretRotation[i] <= 360); \
-\
- for (i = 0; i < DROID_MAXWEAPS; ++i) \
assert(droid->asWeaps[i].lastFired <= gameTime); \
-\
- for (i = 0; i < DROID_MAXWEAPS; ++i) \
+ if (droid->psTarget[i]) \
+ { \
+ assert(droid->psTarget[i]->refCount > 0); \
+ CHECK_OBJECT(droid->psTarget[i]); \
+ } \
if (droid->psActionTarget[i]) \
- assert(droid->psActionTarget[i]->direction >= 0.0f); \
+ { \
+ assert(droid->psActionTarget[i]->refCount > 0); \
+ CHECK_OBJECT(droid->psActionTarget[i]); \
+ } \
+ } \
} while (0)
#endif
Index: src/droiddef.h
===================================================================
--- src/droiddef.h (revision 1637)
+++ src/droiddef.h (working copy)
@@ -91,6 +91,7 @@
typedef struct _order_list
{
SDWORD order;
+ UBYTE type; //type of order target object
void *psOrderTarget; //this needs to cope with objects and stats
UWORD x, y, x2, y2; //line build requires two sets of coords
} ORDER_LIST;
_______________________________________________
Warzone-dev mailing list
[email protected]
https://mail.gna.org/listinfo/warzone-dev