#include #include "deptree.h" int DepTree::CreateNodeFromVar(const std::string& var, DepTreeVars& vars, CallStack& callstack) { COUT(DEBUG)<<"DepTree::CreateNodeFromVar "<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 "<second)!=callstack.end()) { COUT(ERROR)<<"Circular dependency of variable "<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()."<Dump()< 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()<<"."<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."<parents.insert(this); auto ret=n->CreateNodeFromSP(DepTree::SAVE,i,vars); if(ret!=0) return ret; } for(G_toType::size_type i=0; iparents.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 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(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(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"<Dump()<<")"<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"<Dump()<<")"<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 "<name<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(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"<Dump()<<")"<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"<Dump()<<")"<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 "<name<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