Switch to re-entrant lists in ForwardSys and CForward.

This commit is contained in:
David Anderson 2015-09-19 00:17:54 -07:00
parent d0843ab997
commit 88a47ff681
2 changed files with 28 additions and 98 deletions

View File

@ -33,6 +33,7 @@
#include "common_logic.h" #include "common_logic.h"
#include <bridge/include/IScriptManager.h> #include <bridge/include/IScriptManager.h>
#include <amtl/am-string.h> #include <amtl/am-string.h>
#include <ReentrantList.h>
using namespace ke; using namespace ke;
@ -86,27 +87,22 @@ IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType
void CForwardManager::OnPluginLoaded(IPlugin *plugin) void CForwardManager::OnPluginLoaded(IPlugin *plugin)
{ {
/* Attach any globally managed forwards */ /* Attach any globally managed forwards */
for (auto iter=m_managed.begin(); iter!=m_managed.end(); iter++) for (ForwardIter iter(m_managed); !iter.done(); iter.next()) {
{
CForward *fwd = (*iter); CForward *fwd = (*iter);
IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName()); IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
if (pFunc) if (pFunc)
{
fwd->AddFunction(pFunc); fwd->AddFunction(pFunc);
}
} }
} }
void CForwardManager::OnPluginUnloaded(IPlugin *plugin) void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
{ {
for (auto iter=m_managed.begin(); iter!=m_managed.end(); iter++) for (ForwardIter iter(m_managed); !iter.done(); iter.next()) {
{
CForward *fwd = (*iter); CForward *fwd = (*iter);
fwd->RemoveFunctionsOfPlugin(plugin); fwd->RemoveFunctionsOfPlugin(plugin);
} }
for (auto iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++) for (ForwardIter iter(m_unmanaged); !iter.done(); iter.next()) {
{
CForward *fwd = (*iter); CForward *fwd = (*iter);
fwd->RemoveFunctionsOfPlugin(plugin); fwd->RemoveFunctionsOfPlugin(plugin);
} }
@ -114,7 +110,7 @@ void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng) IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
{ {
for (auto iter=m_managed.begin(); iter!=m_managed.end(); iter++) { for (ForwardIter iter(m_managed); !iter.done(); iter.next()) {
CForward *fwd = (*iter); CForward *fwd = (*iter);
if (strcmp(fwd->GetForwardName(), name) == 0) { if (strcmp(fwd->GetForwardName(), name) == 0) {
if (ifchng) if (ifchng)
@ -123,7 +119,7 @@ IForward *CForwardManager::FindForward(const char *name, IChangeableForward **if
} }
} }
for (auto iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++) { for (ForwardIter iter(m_unmanaged); !iter.done(); iter.next()) {
CForward *fwd = (*iter); CForward *fwd = (*iter);
if (strcmp(fwd->GetForwardName(), name) == 0) { if (strcmp(fwd->GetForwardName(), name) == 0) {
if (ifchng) if (ifchng)
@ -152,8 +148,7 @@ void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
return; return;
/* Attach any globally managed forwards */ /* Attach any globally managed forwards */
for (auto iter=m_managed.begin(); iter!=m_managed.end(); iter++) for (ForwardIter iter(m_managed); !iter.done(); iter.next()) {
{
CForward *fwd = (*iter); CForward *fwd = (*iter);
IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName()); IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
// Only add functions, if they aren't registered yet! // Only add functions, if they aren't registered yet!
@ -169,8 +164,7 @@ void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
*************************************/ *************************************/
CForward::CForward(ExecType et, const char *name, const ParamType *types, unsigned num_params) CForward::CForward(ExecType et, const char *name, const ParamType *types, unsigned num_params)
: m_IterGuard(nullptr), : m_numparams(0),
m_numparams(0),
m_varargs(0), m_varargs(0),
m_ExecType(et), m_ExecType(et),
m_curparam(0), m_curparam(0),
@ -239,7 +233,6 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
return err; return err;
} }
FuncIter iter = m_functions.begin();
cell_t cur_result = 0; cell_t cur_result = 0;
cell_t high_result = 0; cell_t high_result = 0;
cell_t low_result = 0; cell_t low_result = 0;
@ -252,9 +245,7 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
memcpy(temp_info, m_params, sizeof(m_params)); memcpy(temp_info, m_params, sizeof(m_params));
m_curparam = 0; m_curparam = 0;
FuncIteratorGuard guard(&m_IterGuard, &iter); for (FuncIter iter(m_functions); !iter.done(); iter.next())
while (iter != m_functions.end())
{ {
IPluginFunction *func = (*iter); IPluginFunction *func = (*iter);
@ -349,9 +340,6 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
} }
} }
} }
if (!guard.Triggered())
iter++;
} }
done: done:
@ -616,30 +604,24 @@ bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
bool CForward::RemoveFunction(IPluginFunction *func) bool CForward::RemoveFunction(IPluginFunction *func)
{ {
bool found = false; ReentrantList<IPluginFunction *> *lst;
LinkedList<IPluginFunction *> *lst;
if (func->IsRunnable()) if (func->IsRunnable())
lst = &m_functions; lst = &m_functions;
else else
lst = &m_paused; lst = &m_paused;
for (auto iter = lst->begin(); iter != lst->end(); iter++) bool found = false;
{ for (FuncIter iter(lst); !iter.done(); iter.next()) {
if ((*iter) == func) if (*iter == func) {
{ iter.remove();
m_IterGuard->FixIteratorChain(iter);
found = true; found = true;
lst->erase(iter);
break; break;
} }
} }
/* Cancel a call, if any */ /* Cancel a call, if any */
if (found || m_curparam) if (found || m_curparam)
{
func->Cancel(); func->Cancel();
}
return found; return found;
} }
@ -647,19 +629,13 @@ bool CForward::RemoveFunction(IPluginFunction *func)
unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin) unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
{ {
unsigned int removed = 0; unsigned int removed = 0;
IPluginContext *pContext = plugin->GetBaseContext(); for (FuncIter iter(m_functions); !iter.done(); iter.next()) {
for (auto iter=m_functions.begin(); iter!=m_functions.end();) IPluginFunction *func = *iter;
{ if (func->GetParentContext() == plugin->GetBaseContext()) {
IPluginFunction *func = (*iter); iter.remove();
if (func->GetParentContext() == pContext)
{
iter = m_functions.erase(iter);
removed++; removed++;
} else {
iter++;
} }
} }
return removed; return removed;
} }
@ -678,13 +654,13 @@ bool CForward::AddFunction(IPluginFunction *func)
bool CForward::IsFunctionRegistered(IPluginFunction *func) bool CForward::IsFunctionRegistered(IPluginFunction *func)
{ {
LinkedList<IPluginFunction *> *lst; ReentrantList<IPluginFunction *> *lst;
if (func->IsRunnable()) if (func->IsRunnable())
lst = &m_functions; lst = &m_functions;
else else
lst = &m_paused; lst = &m_paused;
for (auto iter = lst->begin(); iter != lst->end(); iter++) { for (FuncIter iter(lst); !iter.done(); iter.next()) {
if ((*iter) == func) if ((*iter) == func)
return true; return true;
} }

View File

@ -31,58 +31,14 @@
#include <IForwardSys.h> #include <IForwardSys.h>
#include <IPluginSys.h> #include <IPluginSys.h>
#include "common_logic.h" #include "common_logic.h"
#include <amtl/am-linkedlist.h>
#include "ISourceMod.h" #include "ISourceMod.h"
#include "ReentrantList.h"
typedef ke::LinkedList<IPluginFunction *>::iterator FuncIter; typedef ReentrantList<IPluginFunction *>::iterator FuncIter;
/* :TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX */ /* :TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX */
#define FORWARDS_NAME_MAX 64 #define FORWARDS_NAME_MAX 64
class FuncIteratorGuard
{
bool triggered;
FuncIteratorGuard **pprev;
FuncIter *iter;
FuncIteratorGuard *next;
public:
FuncIteratorGuard(FuncIteratorGuard **pprev, FuncIter *iter)
: triggered(false), pprev(pprev), iter(iter), next(*pprev)
{
*pprev = this;
}
~FuncIteratorGuard()
{
*pprev = next;
}
inline bool Triggered()
{
bool t = triggered;
triggered = false;
return t;
}
/**
* This should not read from |this| before the NULL check, because FwdSys
* can call (NULL)->FixIteratorChain().
*/
void FixIteratorChain(FuncIter &other)
{
FuncIteratorGuard *guard = this;
while (guard != NULL)
{
if (*guard->iter == other)
{
*(guard->iter) = ++(*(guard->iter));
guard->triggered = true;
}
guard = guard->next;
}
}
};
class CForward : public IChangeableForward class CForward : public IChangeableForward
{ {
public: //ICallable public: //ICallable
@ -124,12 +80,8 @@ private:
return err; return err;
} }
protected: protected:
/* :TODO: I want a caching list type here. mutable ReentrantList<IPluginFunction *> m_functions;
* Destroying these things and using new/delete for their members feels bad. mutable ReentrantList<IPluginFunction *> m_paused;
*/
mutable ke::LinkedList<IPluginFunction *> m_functions;
mutable ke::LinkedList<IPluginFunction *> m_paused;
FuncIteratorGuard *m_IterGuard;
/* Type and name information */ /* Type and name information */
FwdParamInfo m_params[SP_MAX_EXEC_PARAMS]; FwdParamInfo m_params[SP_MAX_EXEC_PARAMS];
@ -170,8 +122,10 @@ public: //IPluginsListener
public: //SMGlobalClass public: //SMGlobalClass
void OnSourceModAllInitialized(); void OnSourceModAllInitialized();
private: private:
ke::LinkedList<CForward *> m_managed; ReentrantList<CForward *> m_managed;
ke::LinkedList<CForward *> m_unmanaged; ReentrantList<CForward *> m_unmanaged;
typedef ReentrantList<CForward *>::iterator ForwardIter;
}; };
extern CForwardManager g_Forwards; extern CForwardManager g_Forwards;