Any chance for engine to use request context callback (if set) to collect all cached contexts (and release them right after), while informing application that it should NOT create new contexts if pool is empty? Alternatively, 3rd callback function could be added - context pool cleanup - which tells application that any and all cached contexts should be released, no questions asked.
What it would solve?
If application decides to keep context pool as engine's userdata, cleanup callback might never be called. Cached context(s) holds reference to engine → engine's destructor is not called → userdata cleanup callback is not called. In short, if context pool is userdata, it can't be cleaned inside userdata cleanup function :>
Additionally,`ShutdownAndRelease` promise of taking care of cleaning up as much as possible would be closer to reality.
Full scenario as old-style test:
#include "utils.h"
#include <list>
struct UserData
{
std::list<asIScriptContext*> ContextPool;
};
bool engineData = false;
void CallbackEngineUserData(asIScriptEngine* engine)
{
UserData* data = static_cast<UserData*>(engine->SetUserData(nullptr, 0));
for(asIScriptContext* ctx : data->ContextPool)
{
ctx->Release();
}
data->ContextPool.clear();
delete data;
engineData = true;
}
asIScriptContext* CallbackContextRequest(asIScriptEngine* engine, void*)
{
asIScriptContext* context = nullptr;
UserData* engineData = static_cast<UserData*>( engine->GetUserData() );
if( engineData->ContextPool.empty() )
context = engine->CreateContext();
else
{
context = engineData->ContextPool.front();
engineData->ContextPool.pop_front();
}
return context;
}
void CallbackContextReturn(asIScriptEngine* engine, asIScriptContext* context, void*)
{
UserData* engineData = static_cast<UserData*>(engine->GetUserData());
context->Unprepare();
engineData->ContextPool.push_back( context );
}
bool TestContextPoolAsUserData()
{
asIScriptEngine* engine = asCreateScriptEngine();
engine->SetContextCallbacks(CallbackContextRequest, CallbackContextReturn, nullptr);
engine->SetEngineUserDataCleanupCallback(CallbackEngineUserData);
engine->SetUserData(new UserData);
asIScriptContext* ctx = engine->RequestContext();
engine->ReturnContext(ctx);
engine->ShutDownAndRelease();
// validate
if(!engineData)
{
PRINTF("TestContextPoolAsUserData: context pool leak\n");
return true; // true = fail
}
return false;
}