Add support for building and running multiple instances of the same script.

git-svn-id: http://yate.null.ro/svn/yate/trunk@6542 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
oana 2022-02-09 10:59:28 +00:00
parent 169a579ea8
commit 71206f078c
5 changed files with 369 additions and 82 deletions

View File

@ -44,6 +44,16 @@
;keep_old_on_fail=no
[instances]
; Build multiple instances of specified scripts
; Each line has to be of the form
; name=number of instances
; The name must correspond with a [scripts] section entry
; Default value is one instance
; Examples:
; faxes=3
[scripts]
; Add one entry in this section for each script that is to be loaded on Yate startup
; Each line has to be on the form:

View File

@ -35,7 +35,7 @@ class JsContext : public JsObject, public ScriptMutex
{
YCLASS(JsContext,JsObject)
public:
inline JsContext()
inline JsContext(unsigned int instIdx = 0, unsigned int maxInst = 1)
: JsObject("Context",0), ScriptMutex(true,"JsContext"),
m_trackObjs(0), m_trackObjsMtx(false,"JsObjTrack")
{
@ -44,6 +44,7 @@ public:
params().addParam(new ExpFunction("parseInt"));
params().addParam(new ExpOperation(ExpOperation::nonInteger(),"NaN"));
m_objTrack = !!m_trackObjs;
setInstance(instIdx,maxInst);
DDebug(DebugAll,"JsContext::JsContext() [%p]",this);
}
virtual void destroyed();
@ -3217,7 +3218,11 @@ void JsRunner::traceCheck(const char* title)
traceStart(title);
return;
}
traceStart(title,ns->c_str());
String filename = ns->c_str();
if (context()->instanceIndex())
filename << "_" << context()->instanceIndex();
traceStart(title,filename);
if (m_stats) {
m_stats->ref();
context()->params().setParam(new ExpWrapper(m_stats,s_tracingObj));
@ -3844,18 +3849,19 @@ void JsParser::adjustPath(String& script, bool extraInc) const
}
// Create Javascript context
ScriptContext* JsParser::createContext() const
ScriptContext* JsParser::createContext(unsigned int instIdx, unsigned int maxInst) const
{
return new JsContext;
return new JsContext(instIdx,maxInst);
}
ScriptRun* JsParser::createRunner(ScriptCode* code, ScriptContext* context, const char* title) const
ScriptRun* JsParser::createRunner(ScriptCode* code, ScriptContext* context, const char* title,
unsigned int instIdx, unsigned int maxInst) const
{
if (!code)
return 0;
ScriptContext* ctxt = 0;
if (!context)
context = ctxt = createContext();
context = ctxt = createContext(instIdx,maxInst);
ScriptRun* runner = new JsRunner(code,context,title);
TelEngine::destruct(ctxt);
return runner;

View File

@ -77,18 +77,19 @@ void ScriptParser::setCode(ScriptCode* code)
TelEngine::destruct(tmp);
}
ScriptContext* ScriptParser::createContext() const
ScriptContext* ScriptParser::createContext(unsigned int instIdx, unsigned int maxInst) const
{
return new BasicContext;
}
ScriptRun* ScriptParser::createRunner(ScriptCode* code, ScriptContext* context, const char* title) const
ScriptRun* ScriptParser::createRunner(ScriptCode* code, ScriptContext* context, const char* title,
unsigned int instIdx, unsigned int maxInst) const
{
if (!code)
return 0;
ScriptContext* ctxt = 0;
if (!context)
context = ctxt = createContext();
context = ctxt = createContext(instIdx,maxInst);
ScriptRun* runner = new ScriptRun(code,context);
TelEngine::destruct(ctxt);
return runner;

View File

@ -1603,7 +1603,7 @@ public:
* @param name Name of the context
*/
inline explicit ScriptContext(const char* name = 0)
: m_params(name)
: m_params(name), m_instIdx(0), m_instCount(1)
{ }
/**
@ -1776,8 +1776,22 @@ public:
virtual ObjList* countAllocations()
{ return 0; }
virtual void setInstance(unsigned int idx, unsigned int count)
{
m_instIdx = idx;
m_instCount = count;
}
virtual unsigned int instanceIndex() const
{ return m_instIdx; }
virtual unsigned int instanceCount() const
{ return m_instCount; }
private:
NamedList m_params;
unsigned int m_instIdx; // instance index
unsigned int m_instCount; // total number of instances
};
/**
@ -2155,7 +2169,7 @@ public:
* Create a context adequate for the parsed code
* @return A new script context
*/
virtual ScriptContext* createContext() const;
virtual ScriptContext* createContext(unsigned int instIdx = 0, unsigned int maxInst = 1) const;
/**
* Create a runner adequate for a block of parsed code
@ -2164,7 +2178,8 @@ public:
* @param title An optional name for the runner
* @return A new script runner, NULL if code is NULL
*/
virtual ScriptRun* createRunner(ScriptCode* code, ScriptContext* context = 0, const char* title = 0) const;
virtual ScriptRun* createRunner(ScriptCode* code, ScriptContext* context = 0, const char* title = 0,
unsigned int instIdx = 0, unsigned int maxInst = 1) const;
/**
* Create a runner adequate for the parsed code
@ -2172,8 +2187,9 @@ public:
* @param title An optional name for the runner
* @return A new script runner, NULL if code is not yet parsed
*/
inline ScriptRun* createRunner(ScriptContext* context = 0, const char* title = 0) const
{ return createRunner(code(),context,title); }
inline ScriptRun* createRunner(ScriptContext* context = 0, const char* title = 0,
unsigned int instIdx = 0, unsigned int maxInst = 1) const
{ return createRunner(code(),context,title,instIdx,maxInst); }
/**
* Check if a script has a certain function or method
@ -3148,7 +3164,7 @@ public:
* Create a context adequate for Javascript code
* @return A new Javascript context
*/
virtual ScriptContext* createContext() const;
virtual ScriptContext* createContext(unsigned int instIdx = 0, unsigned int maxInst = 1) const;
/**
* Create a runner adequate for a block of parsed Javascript code
@ -3157,16 +3173,20 @@ public:
* @param title An optional name for the runner
* @return A new Javascript runner, NULL if code is NULL
*/
virtual ScriptRun* createRunner(ScriptCode* code, ScriptContext* context = 0, const char* title = 0) const;
virtual ScriptRun* createRunner(ScriptCode* code, ScriptContext* context = 0, const char* title = 0,
unsigned int instIdx = 0, unsigned int maxInst = 1) const;
/**
* Create a runner adequate for the parsed Javascript code
* @param context Javascript context, an empty one will be allocated if NULL
* @param title An optional name for the runner
* @param instIdx Javascript context instance
* @param maxInst Number of context instances
* @return A new Javascript runner, NULL if code is not yet parsed
*/
inline ScriptRun* createRunner(ScriptContext* context = 0, const char* title = 0) const
{ return createRunner(code(),context,title); }
inline ScriptRun* createRunner(ScriptContext* context = 0, const char* title = 0,
unsigned int instIdx = 0, unsigned int maxInst = 1) const
{ return createRunner(code(),context,title,instIdx,maxInst); }
/**
* Check if a script has a certain function or method

View File

@ -182,26 +182,65 @@ private:
RefPointer<JsMessage> m_message;
};
class JsGlobal;
class JsGlobalInstance : public RefObject
{
public:
JsGlobalInstance(JsGlobal* owner, unsigned int index);
~JsGlobalInstance();
unsigned int runMain();
inline ScriptContext* context()
{ return m_context; }
const String& toString() const
{ return m_name; }
private:
JsGlobal* m_owner;
RefPointer<ScriptContext> m_context;
String m_name;
unsigned int m_instance;
};
class JsGlobal : public NamedString
{
public:
JsGlobal(const char* scriptName, const char* fileName, bool relPath = true, bool fromCfg = true);
JsGlobal(const char* scriptName, const char* fileName, bool relPath = true,
bool fromCfg = true, unsigned int instances = 1);
virtual ~JsGlobal();
bool load();
bool fileChanged(const char* fileName) const;
bool updateInstances(unsigned int instances);
inline JsParser& parser()
{ return m_jsCode; }
inline ScriptContext* context()
{ return m_context; }
inline const String& fileName()
{ return m_file; }
inline unsigned int instances() const
{ return m_instanceCount; }
inline JsGlobalInstance* getInstance(unsigned int idx) const
{
String str = name();
if (idx)
str << "/" << idx;
JsGlobalInstance* inst = static_cast<JsGlobalInstance*>(m_instances[str]);
if (inst && inst->ref())
return inst;
return 0;
}
inline JsGlobalInstance* getInstance(const String& name) const
{
JsGlobalInstance* inst = static_cast<JsGlobalInstance*>(m_instances[name]);
if (inst && inst->ref())
return inst;
return 0;
}
bool runMain();
static void markUnused();
static void freeUnused();
static void reloadDynamic();
static bool initScript(const String& scriptName, const String& fileName, bool relPath = true, bool fromCfg = true);
static bool initScript(const String& scriptName, const String& fileName,
bool relPath = true, bool fromCfg = true, unsigned int instances = 0);
static bool reloadScript(const String& scriptName);
static void loadScripts(const NamedList* sect);
static void loadScripts(const NamedList* sect, const NamedList* instSect);
inline static ObjList& globals()
{ return s_globals; }
inline static void unloadAll()
@ -212,13 +251,14 @@ public:
private:
static bool buildNewScript(Lock& lck, ObjList* old, const String& scriptName,
const String& fileName, bool relPath, bool fromCfg, bool fromInit = false);
const String& fileName, bool relPath, bool fromCfg, bool fromInit = false, unsigned int instances = 0);
JsParser m_jsCode;
RefPointer<ScriptContext> m_context;
bool m_inUse;
bool m_confLoaded;
String m_file;
unsigned int m_instanceCount;
ObjList m_instances;
static ObjList s_globals;
};
@ -529,6 +569,8 @@ public:
params().addParam(new ExpFunction("htoa"));
params().addParam(new ExpFunction("btoh"));
params().addParam(new ExpFunction("htob"));
params().addParam(new ExpFunction("instanceIndex"));
params().addParam(new ExpFunction("instanceCount"));
addConstructor(params(),"Semaphore",new JsSemaphore(mtx));
addConstructor(params(),"HashList",new JsHashList(mtx));
addConstructor(params(),"URI",new JsURI(mtx));
@ -1249,6 +1291,24 @@ static int counterSort(GenObject* obj1, GenObject* obj2, void* context)
return c1 < c2 ? 1 : (c1 > c2 ? -1 : 0);
}
// Sort and dump a list of object counters
static void dumpAllocations(String& out, ObjList* counters, unsigned int count, ScriptCode* code)
{
if (!(counters && code))
return;
counters->sort(counterSort);
unsigned int i = 0;
for (ObjList* o = counters->skipNull(); o && i < count; o = o->skipNext(), i++) {
NamedCounter* c = static_cast<NamedCounter*>(o->get());
uint64_t line = c->toString().toUInt64();
String fn;
unsigned int fl = 0;
code->getFileLine(line,fn,fl,false);
out << "\r\n" << fn << ":" << fl << " " << c->count();
}
}
// Obtain a string with top object allocations from context ctx
static bool evalCtxtAllocations(String& retVal, unsigned int count, ScriptContext* ctx,
ScriptCode* code, const String& scrName)
@ -1262,17 +1322,8 @@ static bool evalCtxtAllocations(String& retVal, unsigned int count, ScriptContex
retVal << "Script '" << scrName << "' has no active object tracking\r\n";
return true;
}
objCounters->sort(counterSort);
String tmp;
unsigned int i = 0;
for (ObjList* o = objCounters->skipNull(); o && i < count; o = o->skipNext(), i++) {
NamedCounter* c = static_cast<NamedCounter*>(o->get());
uint64_t line = c->toString().toUInt64();
String fn;
unsigned int fl = 0;
code->getFileLine(line,fn,fl,false);
tmp << "\r\n" << fn << ":" << fl << " " << c->count();
}
dumpAllocations(tmp,objCounters,count,code);
if (!tmp)
retVal << "Script '" << scrName << "' has no active object tracking counters\r\n";
else
@ -1281,6 +1332,39 @@ static bool evalCtxtAllocations(String& retVal, unsigned int count, ScriptContex
return true;
}
// Obtain a string with top object allocations from all script instances contexts
static bool evalInstanceAllocations(String& retVal, unsigned int count, ObjList& list,
ScriptCode* code, const String& scrName)
{
if (!code) {
retVal << "Script '" << scrName << "' has no associated code\r\n";
return true;
}
ObjList objCounters;
for (ObjList* o = list.skipNull(); o; o = o->skipNext()) {
ObjList* l = static_cast<ObjList*>(o->get());
for (ObjList* j = l->skipNull(); j; j = j->skipNext()) {
NamedCounter* nInt = static_cast<NamedCounter*>(j->get());
NamedCounter* total = static_cast<NamedCounter*>(objCounters[nInt->toString()]);
if (total)
total->add(nInt->count());
else {
j->set(0,false);
objCounters.insert(nInt);
}
}
o->set(0);
}
String tmp;
dumpAllocations(tmp,&objCounters,count,code);
if (!tmp)
retVal << "Script '" << scrName << "' has no active object tracking counters\r\n";
else
retVal << "Top " << count << " object allocations for '" << scrName <<"':" << tmp << "\r\n";
return true;
}
// Utility: return a list of parameters to be used for replaceParams
static inline const NamedList* getReplaceParams(GenObject* gen)
{
@ -2350,6 +2434,18 @@ bool JsEngine::runNative(ObjList& stack, const ExpOperation& oper, GenObject* co
else
ExpEvaluator::pushOne(stack,new ExpOperation(false));
}
else if (oper.name() == YSTRING("instanceIndex")) {
ScriptRun* runner = YOBJECT(ScriptRun,context);
if (!(runner && runner->context()))
return false;
ExpEvaluator::pushOne(stack,new ExpOperation((int64_t)runner->context()->instanceIndex()));
}
else if (oper.name() == YSTRING("instanceCount")) {
ScriptRun* runner = YOBJECT(ScriptRun,context);
if (!(runner && runner->context()))
return false;
ExpEvaluator::pushOne(stack,new ExpOperation((int64_t)runner->context()->instanceCount()));
}
else
return JsObject::runNative(stack,oper,context);
return true;
@ -6121,14 +6217,56 @@ void JsAssist::msgPostExecute(const Message& msg, bool handled)
runFunction("onPostExecute",const_cast<Message&>(msg),&handled);
}
JsGlobalInstance::JsGlobalInstance(JsGlobal* owner, unsigned int index)
: m_owner(owner), m_instance(index)
{
m_name << owner->toString();
if (index)
m_name << "/" << index;
Debug(&__plugin,DebugInfo,"JsGlobalInstance::JsGlobalInstance(%p,%u) Created script instance '%s' [%p]",
m_owner,index,m_name.c_str(),this);
}
JsGlobalInstance::~JsGlobalInstance()
{
Debug(&__plugin,DebugInfo,"JsGlobalInstance::~JsGlobalInstance() '%s' destroyed [%p]",m_name.c_str(),this);
if (m_owner->parser().callable("onUnload")) {
ScriptRun* runner = m_owner->parser().createRunner(m_context,NATIVE_TITLE);
if (runner) {
ObjList args;
runner->call("onUnload",args);
TelEngine::destruct(runner);
}
}
if (m_context) {
Lock mylock(m_context->mutex());
m_context->params().clearParams();
}
}
unsigned int JsGlobalInstance::runMain()
{
DDebug(&__plugin,DebugInfo,"JsGlobalInstance::runMain() Start instance %s",toString().c_str());
ScriptRun* runner = m_owner->parser().createRunner(m_context,0,m_instance,m_owner->instances());
if (!runner)
return ScriptRun::Failed;
if (!m_context)
m_context = runner->context();
m_context->trackObjs(s_trackCreation);
contextInit(runner,toString());
ScriptRun::Status st = runner->run();
TelEngine::destruct(runner);
return st;
}
ObjList JsGlobal::s_globals;
Mutex JsGlobal::s_mutex(false,"JsGlobal");
bool JsGlobal::s_keepOldOnFail = false;
JsGlobal::JsGlobal(const char* scriptName, const char* fileName, bool relPath, bool fromCfg)
JsGlobal::JsGlobal(const char* scriptName, const char* fileName, bool relPath,
bool fromCfg, unsigned int instances)
: NamedString(scriptName,fileName),
m_inUse(true), m_confLoaded(fromCfg), m_file(fileName)
m_inUse(true), m_confLoaded(fromCfg), m_file(fileName), m_instanceCount(instances)
{
m_jsCode.basePath(s_basePath,s_libsPath);
if (relPath)
@ -6141,18 +6279,7 @@ JsGlobal::JsGlobal(const char* scriptName, const char* fileName, bool relPath, b
JsGlobal::~JsGlobal()
{
DDebug(&__plugin,DebugAll,"Unloading global Javascript '%s'",name().c_str());
if (m_jsCode.callable("onUnload")) {
ScriptRun* runner = m_jsCode.createRunner(m_context,NATIVE_TITLE);
if (runner) {
ObjList args;
runner->call("onUnload",args);
TelEngine::destruct(runner);
}
}
if (m_context) {
Lock mylock(m_context->mutex());
m_context->params().clearParams();
}
m_instances.clear();
}
bool JsGlobal::load()
@ -6172,6 +6299,21 @@ bool JsGlobal::fileChanged(const char* fileName) const
return m_jsCode.scriptChanged(fileName,s_basePath,s_libsPath);
}
bool JsGlobal::updateInstances(unsigned int instances)
{
// 0 means that it was called from some place where config was not read, so no change
// or no change in number of instances
if (!instances || instances == m_instanceCount)
return true;
// we already now that current instance is different from what is requested
// so if instances is 1 => m_instance count > 1, m_instanceCount == 1 => instance = 1
// so we need to completely reload the script
if (instances == 1 || m_instanceCount == 1)
return false;
m_instanceCount = instances;
return runMain();
}
void JsGlobal::markUnused()
{
for (ObjList* o = s_globals.skipNull(); o; o = o->skipNext()) {
@ -6207,12 +6349,13 @@ void JsGlobal::reloadDynamic()
}
}
bool JsGlobal::initScript(const String& scriptName, const String& fileName, bool relPath, bool fromCfg)
bool JsGlobal::initScript(const String& scriptName, const String& fileName, bool relPath,
bool fromCfg, unsigned int instances)
{
if (fileName.null())
return false;
DDebug(&__plugin,DebugInfo,"Initialize %s script '%s' from %s file '%s'",(fromCfg ? "configured" : "dynamically loaded"),
scriptName.c_str(),(relPath ? "relative" : "absolute"),fileName.c_str());
DDebug(&__plugin,DebugInfo,"Initialize %s script '%s' from %s file '%s' instances=%u",(fromCfg ? "configured" : "dynamically loaded"),
scriptName.c_str(),(relPath ? "relative" : "absolute"),fileName.c_str(),instances);
Lock mylock(JsGlobal::s_mutex);
ObjList* o = s_globals.find(scriptName);
if (o) {
@ -6224,12 +6367,16 @@ bool JsGlobal::initScript(const String& scriptName, const String& fileName, bool
return false;
}
if (!script->fileChanged(fileName)) {
unsigned int ret = script->updateInstances(instances);
script->m_inUse = true;
script->m_confLoaded = fromCfg;
return true;
// if positive, we can return. otherwise, it's a transition
// from multiple instances to one or viceversa and we reload the whole script
if (ret)
return true;
}
}
return buildNewScript(mylock,o,scriptName,fileName,relPath,fromCfg,true);
return buildNewScript(mylock,o,scriptName,fileName,relPath,fromCfg,true,instances);
}
bool JsGlobal::reloadScript(const String& scriptName)
@ -6245,7 +6392,7 @@ bool JsGlobal::reloadScript(const String& scriptName)
return fileName && buildNewScript(mylock,o,scriptName,fileName,false,script->m_confLoaded);
}
void JsGlobal::loadScripts(const NamedList* sect)
void JsGlobal::loadScripts(const NamedList* sect, const NamedList* instSect)
{
if (!sect)
return;
@ -6256,33 +6403,60 @@ void JsGlobal::loadScripts(const NamedList* sect)
continue;
String tmp = *n;
Engine::runParams().replaceParams(tmp);
JsGlobal::initScript(n->name(),tmp);
JsGlobal::initScript(n->name(),tmp,true,true,instSect ? instSect->getIntValue(n->name(),0,0) : 0);
}
}
bool JsGlobal::runMain()
{
ScriptRun* runner = m_jsCode.createRunner(m_context);
if (!runner)
return false;
if (!m_context)
m_context = runner->context();
m_context->trackObjs(s_trackCreation);
contextInit(runner,name());
ScriptRun::Status st = runner->run();
TelEngine::destruct(runner);
return (ScriptRun::Succeeded == st);
DDebug(&__plugin,DebugInfo,"JsGlobal::runMain() Load and run %u instances, current number of instances:%u",
m_instanceCount,m_instances.count());
if (m_instanceCount <= 1) {
JsGlobalInstance* inst = new JsGlobalInstance(this,0);
if(ScriptRun::Succeeded != inst->runMain())
return false;
m_instances.append(inst);
}
else {
unsigned int lCount = m_instances.count();
// add instances if m_instancesCount is increased
for (unsigned int i = 0; i < m_instanceCount; i++) {
JsGlobalInstance* inst = getInstance(i + 1);
if (inst) {
TelEngine::destruct(inst);
continue;
}
inst = new JsGlobalInstance(this,i + 1);
if(ScriptRun::Succeeded != inst->runMain())
return false;
m_instances.append(inst);
}
// remove instances if m_instances was decreased
for (unsigned int i = m_instanceCount; i < lCount; i++) {
JsGlobalInstance* inst = getInstance(i + 1);
if (!inst)
continue;
m_instances.remove(inst);
TelEngine::destruct(inst);
}
}
return true;
}
bool JsGlobal::buildNewScript(Lock& lck, ObjList* old, const String& scriptName,
const String& fileName, bool relPath, bool fromCfg, bool fromInit)
const String& fileName, bool relPath, bool fromCfg, bool fromInit, unsigned int instances)
{
bool objCount = s_trackObj && getObjCounting();
NamedCounter* saved = 0;
if (objCount)
saved = Thread::setCurrentObjCounter(getObjCounter("js:" + scriptName,true));
JsGlobal* oldScript = old ? static_cast<JsGlobal*>(old->get()) : 0;
JsGlobal* script = new JsGlobal(scriptName,fileName,relPath,fromCfg);
if (0 == instances) // keep number of instances if none is given
instances = oldScript ? oldScript->instances() : 1;
JsGlobal* script = new JsGlobal(scriptName,fileName,relPath,fromCfg,instances);
bool ok = false;
if (script->load() || !s_keepOldOnFail || !old) {
if (old)
@ -6374,7 +6548,10 @@ bool JsModule::commandExecute(String& retVal, const String& line)
Lock lck(JsGlobal::s_mutex);
for (ObjList* o = JsGlobal::globals().skipNull(); o ; o = o->skipNext()) {
JsGlobal* script = static_cast<JsGlobal*>(o->get());
retVal << script->name() << " = " << *script << "\r\n";
retVal << script->name() << " = " << *script;
if (script->instances() > 1)
retVal << ":" << script->instances();
retVal << "\r\n";
}
lck.acquire(this);
for (unsigned int i = 0; i < calls().length(); i++) {
@ -6395,12 +6572,18 @@ bool JsModule::commandExecute(String& retVal, const String& line)
cmd.extractTo(" ",scr).trimSpaces();
if (scr.null() || cmd.null())
return false;
int pos = scr.find("/");
String baseScr = scr.substr(0,pos);
Lock mylock(JsGlobal::s_mutex);;
JsGlobal* script = static_cast<JsGlobal*>(JsGlobal::globals()[scr]);
JsGlobal* script = static_cast<JsGlobal*>(JsGlobal::globals()[baseScr]);
if (script) {
RefPointer<ScriptContext> ctxt = script->context();
mylock.drop();
return evalContext(retVal,cmd,ctxt);
JsGlobalInstance* inst = script->getInstance(scr);
if (inst) {
RefPointer<ScriptContext> ctxt = inst->context();
mylock.drop();
TelEngine::destruct(inst);
return evalContext(retVal,cmd,ctxt);
}
}
mylock.acquire(this);
JsAssist* assist = static_cast<JsAssist*>(calls()[scr]);
@ -6416,7 +6599,34 @@ bool JsModule::commandExecute(String& retVal, const String& line)
if (cmd.startSkip("eval") && cmd.trimSpaces())
return evalContext(retVal,cmd);
if (cmd.startSkip("allocations") && cmd.trimSpaces()) {
if (cmd.startSkip("allocations instance") && cmd.trimSpaces()) {
String scr;
cmd.extractTo(" ",scr).trimSpaces();
String baseScr = scr.substr(0,scr.find("/"));
unsigned int top = cmd.toInteger(25,0,1,100);
if (scr.null())
return false;
Lock mylock(JsGlobal::s_mutex);;
JsGlobal* script = static_cast<JsGlobal*>(JsGlobal::globals()[baseScr]);
if (script) {
JsGlobalInstance* inst = script->getInstance(scr);
if (inst) {
bool ret = evalCtxtAllocations(retVal,top,inst->context(),script->parser().code(),scr);
TelEngine::destruct(inst);
return ret;
}
}
mylock.acquire(this);
RefPointer<JsAssist> assist = static_cast<JsAssist*>(calls()[scr]);
if (assist) {
mylock.drop();
return assist->evalAllocations(retVal,top);
}
retVal << "Cannot find script context: " << scr << "\n\r";
return true;
}
if (cmd.startSkip("allocations total") && cmd.trimSpaces()) {
String scr;
cmd.extractTo(" ",scr).trimSpaces();
unsigned int top = cmd.toInteger(25,0,1,100);
@ -6424,8 +6634,20 @@ bool JsModule::commandExecute(String& retVal, const String& line)
return false;
Lock mylock(JsGlobal::s_mutex);;
JsGlobal* script = static_cast<JsGlobal*>(JsGlobal::globals()[scr]);
if (script)
return evalCtxtAllocations(retVal,top,script->context(),script->parser().code(),scr);
if (script) {
ObjList list;
for (unsigned int i = 0; i <= script->instances(); i++) {
JsGlobalInstance* inst = script->getInstance(i);
if (inst) {
ObjList* c = inst->context() ? inst->context()->countAllocations() : 0;
if (c)
list.insert(c);
TelEngine::destruct(inst);
}
}
mylock.drop();
return evalInstanceAllocations(retVal,top,list,script->parser().code(),scr);
}
mylock.acquire(this);
RefPointer<JsAssist> assist = static_cast<JsAssist*>(calls()[scr]);
if (assist) {
@ -6519,8 +6741,15 @@ bool JsModule::commandComplete(Message& msg, const String& partLine, const Strin
Lock lck(JsGlobal::s_mutex);
for (ObjList* o = JsGlobal::globals().skipNull(); o ; o = o->skipNext()) {
JsGlobal* script = static_cast<JsGlobal*>(o->get());
if (script->name())
itemComplete(msg.retValue(),s_eval + script->name(),partWord);
if (script->name()) {
for (unsigned int i = 0; i <= script->instances(); i++) {
JsGlobalInstance* inst = script->getInstance(i);
if (inst) {
itemComplete(msg.retValue(),s_eval + inst->toString(),partWord);
TelEngine::destruct(inst);
}
}
}
}
lck.acquire(this);
for (unsigned int i = 0; i < calls().length(); i++) {
@ -6536,7 +6765,7 @@ bool JsModule::commandComplete(Message& msg, const String& partLine, const Strin
itemComplete(msg.retValue(),*list,partWord);
return true;
}
else if (partLine == YSTRING("javascript reload") || partLine == YSTRING("javascript allocations")) {
else if (partLine == YSTRING("javascript reload") || partLine == YSTRING("javascript allocations total")) {
Lock lck(JsGlobal::s_mutex);
for (ObjList* o = JsGlobal::globals().skipNull(); o ; o = o->skipNext()) {
JsGlobal* script = static_cast<JsGlobal*>(o->get());
@ -6545,6 +6774,27 @@ bool JsModule::commandComplete(Message& msg, const String& partLine, const Strin
}
return true;
}
else if (partLine == YSTRING("javascript allocations instance")) {
Lock lck(JsGlobal::s_mutex);
for (ObjList* o = JsGlobal::globals().skipNull(); o ; o = o->skipNext()) {
JsGlobal* script = static_cast<JsGlobal*>(o->get());
if (script && script->instances() > 1) {
for (unsigned int i = 0; i <= script->instances(); i++) {
JsGlobalInstance* inst = script->getInstance(i);
if (inst) {
itemComplete(msg.retValue(),inst->toString(),partWord);
TelEngine::destruct(inst);
}
}
}
}
return true;
}
else if (partLine == YSTRING("javascript allocations")) {
itemComplete(msg.retValue(),"total",partWord);
itemComplete(msg.retValue(),"instance",partWord);
return 0;
}
return Module::commandComplete(msg,partLine,partWord);
}
@ -6629,7 +6879,7 @@ bool JsModule::received(Message& msg, int id)
if (!m_started) {
m_started = true;
Configuration cfg(Engine::configFile("javascript"));
JsGlobal::loadScripts(cfg.getSection("late_scripts"));
JsGlobal::loadScripts(cfg.getSection("late_scripts"),cfg.getSection("instances"));
}
return false;
} // switch (id)
@ -6718,9 +6968,9 @@ void JsModule::initialize()
}
JsGlobal::markUnused();
lck.drop();
JsGlobal::loadScripts(cfg.getSection("scripts"));
JsGlobal::loadScripts(cfg.getSection("scripts"),cfg.getSection("instances"));
if (m_started)
JsGlobal::loadScripts(cfg.getSection("late_scripts"));
JsGlobal::loadScripts(cfg.getSection("late_scripts"),cfg.getSection("instances"));
JsGlobal::reloadDynamic();
JsGlobal::freeUnused();
}