Skip to content

Commit

Permalink
Optimize: Separate thinkers into lists by their function in P_Thinker…
Browse files Browse the repository at this point in the history
…Add. Iterate over only those thinkers whose function matches, or all if not specified in P_IterateThinkers.
  • Loading branch information
danij committed Mar 26, 2009
1 parent 7afaee9 commit 3d19e8b
Show file tree
Hide file tree
Showing 15 changed files with 238 additions and 118 deletions.
246 changes: 185 additions & 61 deletions doomsday/engine/portable/src/p_think.c
Expand Up @@ -52,13 +52,146 @@ unsigned short iddealer = 0;

// PRIVATE DATA DEFINITIONS ------------------------------------------------

static thinker_t thinkerCap; // The head and tail of the thinker list.
static size_t numThinkerLists;
static thinker_t* thinkerCaps; // The head and tail of the thinker lists.
static boolean inited = false;

// CODE --------------------------------------------------------------------

boolean P_IsMobjThinker(think_t thinker)
static void linkThinkerToList(thinker_t* th, thinker_t* list)
{
if(thinker == gx.MobjThinker)
// Link the thinker to the thinker list.
list->prev->next = th;
th->next = list;
th->prev = list->prev;
list->prev = th;
}

static void unlinkThinkerFromList(thinker_t* th)
{
th->next->prev = th->prev;
th->prev->next = th->next;
}

static void initThinkerList(thinker_t* list)
{
list->prev = list->next = list;
}

static thinker_t* listForThinkFunc(think_t func, boolean canCreate)
{
size_t i;

for(i = 0; i < numThinkerLists; ++i)
{
thinker_t* list = &thinkerCaps[i];

if(list->function == func)
return list;
}

if(!canCreate)
return NULL;

// A new thinker type.
{
thinker_t* list;
thinker_t* newLists =
Z_Calloc(sizeof(thinker_t) * ++numThinkerLists, PU_STATIC, 0);

if(thinkerCaps)
{
for(i = 0; i < numThinkerLists-1; ++i)
{
thinker_t* dst = &newLists[i];
const thinker_t* src = &thinkerCaps[i];

memcpy(dst, src, sizeof(thinker_t));
if(dst->next != dst->prev)
{
dst->next->prev = dst;
dst->prev->next = dst;
}
else
{
dst->next = dst->prev = dst;
}
}

Z_Free(thinkerCaps);
}

thinkerCaps = newLists;
list = &thinkerCaps[numThinkerLists-1];

initThinkerList(list);
list->function = func;
// Set the list sentinel to instasis (safety measure).
list->inStasis = true;

return list;
}
}

static boolean runThinker(thinker_t* th, void* context)
{
// Thinker cannot think when in stasis.
if(!th->inStasis)
{
if(th->function == (think_t) -1)
{
// Time to remove it.
unlinkThinkerFromList(th);

if(th->id)
{ // Its a mobj.
P_MobjRecycle((mobj_t*) th);
}
else
{
Z_Free(th);
}
}
else if(th->function)
{
th->function(th);
}
}

return true; // Continue iteration.
}

static boolean iterateThinkers(thinker_t* list,
boolean (*callback) (thinker_t*, void*),
void* context)
{
boolean result = true;

if(list)
{
thinker_t* th, *next;

th = list->next;
while(th != list && th)
{
#ifdef FAKE_MEMORY_ZONE
assert(th->next != NULL);
assert(th->prev != NULL);
#endif

next = th->next;
if((result = callback(th, context)) == 0)
break;
th = next;
}
}

return result;
}

boolean P_IsMobjThinker(think_t func)
{
if(func && func == gx.MobjThinker)
return true;

return false;
Expand Down Expand Up @@ -95,6 +228,30 @@ thid_t P_NewMobjID(void)
return iddealer;
}

void P_InitThinkers(void)
{
if(!inited)
{
numThinkerLists = 0;
thinkerCaps = NULL;
}
else
{
size_t i;

for(i = 0; i < numThinkerLists; ++i)
initThinkerList(&thinkerCaps[i]);
}

P_ClearMobjIDs();
inited = true;
}

boolean P_ThinkerListInited(void)
{
return inited;
}

/**
* Iterate the list of thinkers making a callback for each.
*
Expand All @@ -104,85 +261,49 @@ thid_t P_NewMobjID(void)
* until a callback returns a zero value.
* @param context Is passed to the callback function.
*/
boolean P_IterateThinkers(think_t type,
boolean (*callback) (thinker_t* thinker, void*),
boolean P_IterateThinkers(think_t func,
boolean (*callback) (thinker_t*, void*),
void* context)
{
if(!inited)
return true;

if(func)
return iterateThinkers(listForThinkFunc(func, false), callback,
context);

{
boolean result = true;
thinker_t* th, *next;
size_t i;

th = thinkerCap.next;
while(th != &thinkerCap && th)
for(i = 0; i < numThinkerLists; ++i)
{
#ifdef FAKE_MEMORY_ZONE
assert(th->next != NULL);
assert(th->prev != NULL);
#endif
thinker_t* list = &thinkerCaps[i];

next = th->next;
if(!(type && th->function && th->function != type))
if((result = callback(th, context)) == 0)
break;
th = next;
if((result = iterateThinkers(list, callback, context)) == 0)
break;
}

return result;
}

static boolean runThinker(thinker_t* th, void* context)
{
// Thinker cannot think when in stasis.
if(!th->inStasis)
{
if(th->function == (think_t) -1)
{
// Time to remove it.
th->next->prev = th->prev;
th->prev->next = th->next;
if(th->id)
{ // Its a mobj.
P_MobjRecycle((mobj_t*) th);
}
else
{
Z_Free(th);
}
}
else if(th->function)
{
th->function(th);
}
}

return true; // Continue iteration.
}

void P_RunThinkers(void)
{
P_IterateThinkers(NULL, runThinker, NULL);
}

void P_InitThinkers(void)
{
thinkerCap.prev = thinkerCap.next = &thinkerCap;
P_ClearMobjIDs();
}

boolean P_ThinkerListInited(void)
{
return (thinkerCap.next)? true : false;
}

/**
* Adds a new thinker at the end of the list.
*/
void P_ThinkerAdd(thinker_t* th)
{
// Link the thinker to the thinker list.
thinkerCap.prev->next = th;
th->next = &thinkerCap;
th->prev = thinkerCap.prev;
thinkerCap.prev = th;
if(!th)
return;

if(!th->function)
{
Con_Error("P_ThinkerAdd: Invalid thinker function.");
}

// Will it need an ID?
if(P_IsMobjThinker(th->function))
Expand All @@ -195,6 +316,9 @@ void P_ThinkerAdd(thinker_t* th)
// Zero is not a valid ID.
th->id = 0;
}

// Link the thinker to the thinker list.
linkThinkerToList(th, listForThinkFunc(th->function, true));
}

/**
Expand Down
11 changes: 4 additions & 7 deletions doomsday/plugins/common/src/p_door.c
Expand Up @@ -327,12 +327,11 @@ static int EV_DoDoor2(int tag, float speed, int topwait, doortype_e type)
// new door thinker
rtn = 1;
door = Z_Calloc(sizeof(*door), PU_MAP, 0);
door->thinker.function = T_Door;
P_ThinkerAdd(&door->thinker);
xsec->specialData = door;

door->thinker.function = T_Door;
door->sector = sec;

door->type = type;
door->topWait = topwait;
door->speed = speed;
Expand Down Expand Up @@ -736,9 +735,9 @@ boolean EV_VerticalDoor(linedef_t* line, mobj_t* mo)

// New door thinker.
door = Z_Calloc(sizeof(*door), PU_MAP, 0);
door->thinker.function = T_Door;
P_ThinkerAdd(&door->thinker);
xsec->specialData = door;
door->thinker.function = T_Door;
door->sector = sec;
door->state = DS_UP;

Expand Down Expand Up @@ -858,13 +857,12 @@ void P_SpawnDoorCloseIn30(sector_t *sec)
door_t *door;

door = Z_Calloc(sizeof(*door), PU_MAP, 0);

door->thinker.function = T_Door;
P_ThinkerAdd(&door->thinker);

P_ToXSector(sec)->specialData = door;
P_ToXSector(sec)->special = 0;

door->thinker.function = T_Door;
door->sector = sec;
door->state = DS_WAIT;
door->type = DT_NORMAL;
Expand All @@ -877,13 +875,12 @@ void P_SpawnDoorRaiseIn5Mins(sector_t *sec)
door_t *door;

door = Z_Calloc(sizeof(*door), PU_MAP, 0);

door->thinker.function = T_Door;
P_ThinkerAdd(&door->thinker);

P_ToXSector(sec)->specialData = door;
P_ToXSector(sec)->special = 0;

door->thinker.function = T_Door;
door->sector = sec;
door->state = DS_INITIALWAIT;
door->type = DT_RAISEIN5MINS;
Expand Down
5 changes: 3 additions & 2 deletions doomsday/plugins/common/src/p_floor.c
Expand Up @@ -982,9 +982,10 @@ int EV_BuildStairs(linedef_t* line, stair_e type)
// New floor thinker.
rtn = 1;
floor = Z_Calloc(sizeof(*floor), PU_MAP, 0);
floor->thinker.function = T_MoveFloor;
P_ThinkerAdd(&floor->thinker);

xsec->specialData = floor;
floor->thinker.function = T_MoveFloor;
floor->state = FS_UP;
floor->sector = sec;
switch(type)
Expand Down Expand Up @@ -1097,9 +1098,9 @@ static void processStairSector(sector_t *sec, int type, float height,
height += stairData.stepDelta;

floor = Z_Calloc(sizeof(*floor), PU_MAP, 0);
floor->thinker.function = T_MoveFloor;
P_ThinkerAdd(&floor->thinker);
P_ToXSector(sec)->specialData = floor;
floor->thinker.function = T_MoveFloor;
floor->type = FT_RAISEBUILDSTEP;
floor->state = (stairData.direction == -1? FS_DOWN : FS_UP);
floor->sector = sec;
Expand Down
1 change: 1 addition & 0 deletions doomsday/plugins/common/src/p_plat.c
Expand Up @@ -269,6 +269,7 @@ static int doPlat(linedef_t *line, int tag, plattype_e type, int amount)

// Find lowest & highest floors around sector
rtn = 1;

plat = Z_Calloc(sizeof(*plat), PU_MAP, 0);
plat->thinker.function = T_PlatRaise;
P_ThinkerAdd(&plat->thinker);
Expand Down
1 change: 0 additions & 1 deletion doomsday/plugins/common/src/p_switch.c
Expand Up @@ -314,7 +314,6 @@ void P_SpawnMaterialChanger(sidedef_t* side, sidedefsurfaceid_t ssurfaceID,

mchanger = Z_Calloc(sizeof(*mchanger), PU_MAP, 0);
mchanger->thinker.function = T_MaterialChanger;

P_ThinkerAdd(&mchanger->thinker);

mchanger->side = side;
Expand Down

0 comments on commit 3d19e8b

Please sign in to comment.