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
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; |
|
}
|
|
|