You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

470 lines
11 KiB

#include <stack>
#include "deptree.h"
int DepTree::CreateNodeFromVar(const std::string& var, DepTreeVars& vars, CallStack& callstack)
{
COUT(DEBUG)<<"DepTree::CreateNodeFromVar "<<var<<std::endl;
if(G_vars.count(var)==0)
{
COUT(ERROR)<<"Definition of variable "<<var<<" not found"<<std::endl;
return 1;
}
UsedType ids;
vars[var]=this;
G_vars[var]->UsedIdents(ids);
type=DepTree::VAR;
name=var;
DepTreeVars::const_iterator d;
int ret;
callstack.insert(this);
for(auto& i:ids)
{
d=vars.find(i);
if(d==vars.end())
{
auto n=*childrens.insert(new DepTree).first;
n->parents.insert(this);
ret=n->CreateNodeFromVar(i,vars,callstack);
if(ret!=0)
{
COUT(ERROR)<<" in definition of variable "<<name<<std::endl;
return ret;
}
}
else
{
if(callstack.find(d->second)!=callstack.end())
{
COUT(ERROR)<<"Circular dependency of variable "<<name<<" from variable "<<i<<std::endl;
return 1;
}
childrens.insert(d->second);
d->second->parents.insert(this);
}
}
callstack.erase(this);
return 0;
}
int DepTree::CreateNodeFromSP(DepTree::NodeType list, G_toType::size_type ind, DepTreeVars& vars)
{
if(list!=DepTree::SAVE && list!=DepTree::PRINT)
{
COUT(ERROR)<<"Internal error, incorrect NodeType in DepTree::CreateNodeFromSP()."<<std::endl;
return 2;
}
COUT(DEBUG)<<"DepTree::CreateNodeFromSP "<<((list==DepTree::SAVE)?G_tosave:G_toprint)[ind]->Dump()<<std::endl;
std::set<std::string> ids;
CallStack callstack;
type=list;
index=ind;
if(type==DepTree::SAVE) G_tosave[index]->UsedIdents(ids);
else if(type==DepTree::PRINT) G_toprint[index]->UsedIdents(ids);
DepTreeVars::const_iterator d;
int ret;
for(auto& i:ids)
{
d=vars.find(i);
if(d==vars.end())
{
auto n=*childrens.insert(new DepTree).first;
n->parents.insert(this);
ret=n->CreateNodeFromVar(i,vars,callstack);
if(ret!=0)
{
COUT(ERROR)<<" in "<<((type==DepTree::SAVE)?"save":"print")<<" directive "<<((type==DepTree::SAVE)?G_tosave:G_toprint)[index]->Dump()<<"."<<std::endl;
return ret;
}
}
else
{
childrens.insert(d->second);
d->second->parents.insert(this);
}
}
return 0;
}
int DepTree::CreateGlobalTree(UsedType& used)
{
if(parents.size()!=0)
{
COUT(ERROR)<<"Internal error, DepTree::CreateGlobalTree() call for non-root node."<<std::endl;
return 2;
}
DepTreeVars vars;
type=DepTree::ROOT;
for(G_toType::size_type i=0; i<G_tosave.size(); i++)
{
auto n=*childrens.insert(new DepTree).first;
n->parents.insert(this);
auto ret=n->CreateNodeFromSP(DepTree::SAVE,i,vars);
if(ret!=0) return ret;
}
for(G_toType::size_type i=0; i<G_toprint.size(); i++)
{
auto n=*childrens.insert(new DepTree).first;
n->parents.insert(this);
auto ret=n->CreateNodeFromSP(DepTree::PRINT,i,vars);
if(ret!=0) return ret;
}
for(auto& i: vars) used.insert(i.first);
return 0;
}
DepTree::LeafVector DepTree::FindLeafNodes() const
{
LeafVector leafs;
std::stack<NodeVector::const_iterator> path,ends;
NodeVector::const_iterator it,end;
// define isvisited as reversion of last visited
bool isvisited=!visited;
// ascending to root
const DepTree* root=this;
while(root->parents.size()!=0) root=*(root->parents.begin());
const DepTree* curnode=root;
curnode->visited=isvisited;
it=curnode->childrens.begin();
end=curnode->childrens.end();
while(true)
{
if(it!=end)
{
if((*it)->visited==isvisited) {++it; continue;}
path.push(it); ends.push(end);
curnode=(*it);
curnode->visited=isvisited;
it=curnode->childrens.begin();
end=curnode->childrens.end();
if(it==end) leafs.push_back(const_cast<DepTree*>(curnode));
}
else
{
if(path.size()==0) break;
it=path.top(); path.pop();
end=ends.top(); ends.pop();
++it;
}
}
return leafs;
}
// Multi-threaded version
void* TreeEvaluateM(void* arg)
{
struct timespec skip={0,10000000};
DepTree::thread_params* p=reinterpret_cast<DepTree::thread_params*>(arg);
DepTree* leaf;
ObjectBase *ob,*eob;
ObjectList* ol;
bool err;
while(true)
{
// Begin critical section (access to root)
pthread_mutex_lock(&p->root_mtx);
// Check, if all done, or error happens?
if(0==p->root->childrens.size() || 0!=p->exitcode) {pthread_mutex_unlock(&p->root_mtx); return 0;}
// End critical section
pthread_mutex_unlock(&p->root_mtx);
// Begin critical section (access to leafs)
pthread_mutex_lock(&p->leaf_mtx);
// Check, if some work available?
if(0==p->leafs.size()) {pthread_mutex_unlock(&p->leaf_mtx); nanosleep(&skip,0); continue;}
// Select working node
leaf=*(p->leafs.begin());
// and remove its from list
p->leafs.erase(p->leafs.begin());
// End critical section
pthread_mutex_unlock(&p->leaf_mtx);
if(DepTree::SAVE==leaf->type)
{
err=false;
// Begin critical section (access to G_toprint or G_tosave)
pthread_mutex_lock(&p->prsv_mtx);
ol=G_tosave[leaf->index];
// End critical section
pthread_mutex_unlock(&p->prsv_mtx);
ol->Evaluate(&err); // For list Evaluate always return 0;
if(err)
{
COUT(ERROR)<<" in instruction save"<<ol->Dump()<<")"<<std::endl;
p->exitcode=1;
return 0;
}
if(!Save(ol))
{
p->exitcode=1;
return 0;
}
// This leaf can have only one parent - root
// Begin critical section (access to root)
pthread_mutex_lock(&p->root_mtx);
(*leaf->parents.begin())->childrens.erase(leaf);
// End critical section
pthread_mutex_unlock(&p->root_mtx);
}
if(DepTree::PRINT==leaf->type)
{
err=false;
// Begin critical section (access to G_toprint or G_tosave)
pthread_mutex_lock(&p->prsv_mtx);
ol=G_toprint[leaf->index];
// End critical section
pthread_mutex_unlock(&p->prsv_mtx);
ol->Evaluate(&err); // For list Evaluate always return 0;
if(err)
{
COUT(ERROR)<<" in instruction print"<<ol->Dump()<<")"<<std::endl;
p->exitcode=1;
return 0;
}
if(!Print(ol))
{
p->exitcode=1;
return 0;
}
// Begin critical section (access to root)
pthread_mutex_lock(&p->root_mtx);
// This leaf can have only one parent - root
(*leaf->parents.begin())->childrens.erase(leaf);
// End critical section
pthread_mutex_unlock(&p->root_mtx);
}
if(DepTree::VAR==leaf->type)
{
// Begin critical section (access to G_vars)
pthread_mutex_lock(&p->vars_mtx);
ob=G_vars.at(leaf->name);
G_vars.erase(leaf->name);
// End critical section
pthread_mutex_unlock(&p->vars_mtx);
// Main working call
err=false;
eob=ob->Evaluate(&err);
if(err)
{
COUT(ERROR)<<" in definition of variable "<<leaf->name<<std::endl;
p->exitcode=1;
return 0;
}
// eob is evaluated object
if(0!=eob) delete ob;
else eob=ob;
// Begin critical section (access to tree structure)
pthread_mutex_lock(&p->tree_mtx);
for(auto& i:leaf->parents)
{
// leaf not children of anyone
i->childrens.erase(leaf);
// Replace variable on eob
if(DepTree::SAVE==i->type)
{
// Begin critical section (access to G_toprint or G_tosave)
pthread_mutex_lock(&p->prsv_mtx);
G_tosave[i->index]->ReplaceVar(leaf->name,eob); // ReplaceVar always return 0 for ObjectList
// End critical section
pthread_mutex_unlock(&p->prsv_mtx);
}
if(DepTree::PRINT==i->type)
{
// Begin critical section (access to G_toprint or G_tosave)
pthread_mutex_lock(&p->prsv_mtx);
G_toprint[i->index]->ReplaceVar(leaf->name,eob); // ReplaceVar always return 0 for ObjectList
// End critical section
pthread_mutex_unlock(&p->prsv_mtx);
}
if(DepTree::VAR==i->type)
{
// Begin critical section (access to G_vars)
pthread_mutex_lock(&p->vars_mtx);
ob=G_vars[i->name]->ReplaceVar(leaf->name,eob);
if(0!=ob)
{
delete G_vars[i->name];
G_vars[i->name]=ob;
}
// End critical section
pthread_mutex_unlock(&p->vars_mtx);
}
// Begin critical section (access to leafs)
pthread_mutex_lock(&p->leaf_mtx);
// If node have no children, it's a new leaf node
if(0==i->childrens.size() && DepTree::ROOT!=i->type) p->leafs.push_back(i);
pthread_mutex_unlock(&p->leaf_mtx);
// End critical section
}
// End critical section
pthread_mutex_unlock(&p->tree_mtx);
delete eob;
}
leaf->parents.clear();
delete leaf;
}
return 0;
}
// Single-threaded version
void* TreeEvaluate(void* arg)
{
DepTree::thread_params* p=reinterpret_cast<DepTree::thread_params*>(arg);
DepTree* leaf;
ObjectBase *ob,*eob;
ObjectList* ol;
bool err;
while(0!=p->leafs.size())
{
// Select working node
leaf=*(p->leafs.begin());
// and remove its from list
p->leafs.erase(p->leafs.begin());
if(DepTree::SAVE==leaf->type)
{
err=false;
ol=G_tosave[leaf->index];
ol->Evaluate(&err); // For list Evaluate always return 0;
if(err)
{
COUT(ERROR)<<" in instruction save"<<ol->Dump()<<")"<<std::endl;
p->exitcode=1;
return 0;
}
// eob is evaluated object
if(!Save(ol))
{
p->exitcode=1;
return 0;
}
// This leaf can have only one parent - root
(*leaf->parents.begin())->childrens.erase(leaf);
}
if(DepTree::PRINT==leaf->type)
{
err=false;
ol=G_toprint[leaf->index];
ol->Evaluate(&err); // For list Evaluate always return 0;
if(err)
{
COUT(ERROR)<<" in instruction print"<<ol->Dump()<<")"<<std::endl;
p->exitcode=1;
return 0;
}
if(!Print(ol))
{
p->exitcode=1;
return 0;
}
// This leaf can have only one parent - root
(*leaf->parents.begin())->childrens.erase(leaf);
}
if(DepTree::VAR==leaf->type)
{
err=false;
ob=G_vars.at(leaf->name);
G_vars.erase(leaf->name);
// Main working call
eob=ob->Evaluate(&err);
if(err)
{
COUT(ERROR)<<" in definition of variable "<<leaf->name<<std::endl;
p->exitcode=1;
return 0;
}
// eob is evaluated object
if(0!=eob) delete ob;
else eob=ob;
//G_vars.erase(leaf->name);
for(auto& i:leaf->parents)
{
// leaf not children of anyone
i->childrens.erase(leaf);
// Replace variable on eob
if(DepTree::SAVE==i->type) G_tosave[i->index]->ReplaceVar(leaf->name,eob); // ReplaceVar always return 0 for ObjectList
if(DepTree::PRINT==i->type) G_toprint[i->index]->ReplaceVar(leaf->name,eob);
if(DepTree::VAR==i->type)
{
ob=G_vars[i->name]->ReplaceVar(leaf->name,eob);
if(0!=ob) {delete G_vars[i->name]; G_vars[i->name]=ob;}
}
// If node have no children, it's a new leaf node
if(0==i->childrens.size() && DepTree::ROOT!=i->type) p->leafs.push_back(i);
}
delete eob;
}
leaf->parents.clear();
delete leaf;
}
return 0;
}
int DepTree::EvaluateTree(unsigned int nthreads)
{
DepTree::thread_params p;
p.exitcode=0;
p.leafs=FindLeafNodes();
if(1==nthreads) TreeEvaluate(&p);
else
{
pthread_t* threads=new pthread_t[nthreads-1];
p.root=this;
pthread_mutex_init(&p.leaf_mtx,0);
pthread_mutex_init(&p.root_mtx,0);
pthread_mutex_init(&p.vars_mtx,0);
pthread_mutex_init(&p.prsv_mtx,0);
pthread_mutex_init(&p.tree_mtx,0);
while(0!=p.root->parents.size()) p.root=*(p.root->parents.begin());
for(unsigned int i=0;i<nthreads-1;++i) pthread_create(threads+i,0,&TreeEvaluateM,&p);
TreeEvaluateM(&p);
for(unsigned int i=0;i<nthreads-1;++i) pthread_join(threads[i],0);
delete[] threads;
pthread_mutex_destroy(&p.leaf_mtx);
pthread_mutex_destroy(&p.root_mtx);
pthread_mutex_destroy(&p.vars_mtx);
pthread_mutex_destroy(&p.prsv_mtx);
pthread_mutex_destroy(&p.tree_mtx);
}
return p.exitcode;
}