/vesta/vestasys.org/vesta/eval/98/src/ApplyCache.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // File: ApplyCache.C
00020 
00021 #include <Basics.H>
00022 #include <FP.H>
00023 #include <Model.H>
00024 #include <FV.H>
00025 #include <CacheIndex.H>
00026 #include <CacheC.H>
00027 #include "ApplyCache.H"
00028 #include "Expr.H"
00029 #include "Val.H"
00030 #include "Pickle.H"
00031 #include "Err.H"
00032 #include "PrimRunTool.H"
00033 #include "Debug.H"
00034 #include "ThreadData.H"
00035 #include <Table.H>
00036 #include <algorithm>
00037 
00038 using std::ostream;
00039 using std::endl;
00040 using Basics::OBufStream;
00041 using OS::cio;
00042 
00043 // KCS, 2001-12-6: Changed both evaluatorRunToolVersion and
00044 // evaluatorFunctionVersion, as integer values are now fingerprinted
00045 // as 32-bit values.
00046 
00047 // KCS, 2002-8-20: Changed evaluatorFunctionVersion due to a fix to
00048 // dependency analysis in several primitive functions for boundary
00049 // cases with empty lists and bindings.
00050 
00051 // KCS, 2002-11-6: Changed evaluatorFunctionVersion due to a bug fix
00052 // to dependency collection code which iadvertently munged dependency
00053 // paths.  This bug *seemed* to only add additional bogus secondary
00054 // dependencies, but it's safer to update evaluatorFunctionVersion.
00055 
00056 // KCS, 2003-2-11: Changed both evaluatorRunToolVersion and
00057 // evaluatorFunctionVersion, as the pickle version has changed for
00058 // the network byte order conversion.
00059 
00060 // KCS, 2004-04-05: Changed evaluatorFunctionVersion due to
00061 // dependency analysis bug fixes in CollectModel.
00062 
00063 // STV&KCS, 2004-12-25: Changed evaluatorRunToolVersion after adding
00064 // "dumped_core" to _run_tool result.
00065 
00066 // KCS, 2005-02-11: Changed both evaluatorRunToolVersion and
00067 // evaluatorFunctionVersion due to dependency analysis bug fix in
00068 // _run_tool (not recording a dependency on directories looked up but
00069 // never accessed).
00070 
00071 // KCS, 2006-08-06: Changed both evaluatorRunToolVersion and
00072 // evaluatorFunctionVersion due to dependency analysis bug fix in
00073 // _run_tool (not including ./envVars in the recorded dependencies of
00074 // the result).
00075 
00076 // IF, 2006-08-16: Changed evaluatorRunToolVersion and 
00077 // evaluatorFunctionVersion, as pickle/unpickleInt16 was replaced by 
00078 // pickle/unpickleInt32 in most cases.
00079 
00080 // KCS, 2006-10-26: Changed evaluatorFunctionVersion when fixing a
00081 // dependency analysis bug in _map/_par_map which recorded
00082 // insufficient dependencies when a call mapping over a binding
00083 // returns an empty binding.
00084 
00085 // KCS, 2007-04-22: Changed evaluatorFunctionVersion when making the
00086 // _findre primitive function official.  (The parsed represenation of
00087 // a fucntion refernceing a new primitive is unusable by older
00088 // evaluators.)
00089 
00090 // KCS, 2007-05-01: Reverted evaluatorFunctionVersion since we've
00091 // backed out _findre for now.
00092 
00093 // Get the pickle version
00094 extern int currentPickleVersion;
00095 static const Basics::int32 currentPickleVersion_net = Basics::hton32(currentPickleVersion);
00096 
00097 // Runtool call version:
00098 const char *evaluatorRunToolVersion = "Wed Aug 16 13:07:11 EDT 2006";
00099 const FP::Tag evaluatorRunToolVersionTag(evaluatorRunToolVersion);
00100 
00101 // Function call version:
00102 const char *evaluatorFunctionVersion = "Thu Oct 26 01:44:45 2006";
00103 const FP::Tag evaluatorFunctionVersionTag(evaluatorFunctionVersion);
00104 
00105 // The number of addentry calls to the cache:
00106 static int addEntryCount = 0;
00107 
00108 // The mutex protects the variables lastRenewed and
00109 // renewLease_failure.
00110 static Basics::mutex leaseMu;
00111 static time_t lastRenewed;
00112 static bool renewLease_failure = false;
00113 
00114 // A table to keep from running identical functions/tools in parallel.
00115 // This checks for a PK and waits on a condition if that PK
00116 // is already in progress.
00117 static Basics::mutex runningPkTableMu;
00118 class rpt_cond {
00119         Basics::cond cond;
00120         int count; // number of in progress calls with this PK
00121         bool dec_and_del() {
00122                 assert(count > 0);
00123                 if(--count == 0) {
00124                         delete this;
00125                         return false;
00126                 } else {
00127                         return true;
00128                 }
00129         };
00130     public:
00131         rpt_cond() { count = 1; };
00132         void wait() {
00133                 count++;
00134                 cond.wait(runningPkTableMu);
00135                 (void) dec_and_del();
00136         };
00137         void wake() {
00138                 if(dec_and_del()) {
00139                         cond.broadcast();
00140                 }
00141         };
00142         
00143 };
00144 static Table<FP::Tag, rpt_cond *>::Default runningPkTable;
00145 
00146 //Checks the runningPkTable and sleeps if another thread is currently
00147 //evaluating a function/tool with the same pk.
00148 //Returns true if another thread might have populated the cache
00149 //for us, false if we need to do the work ourself.
00150 bool WaitForDuplicateEval(FP::Tag pk, const char *thing) {
00151         rpt_cond *rptCond = 0;
00152         runningPkTableMu.lock();
00153         bool found = runningPkTable.Get(pk, /*OUT*/ rptCond);
00154         if(!found) {
00155                 rptCond = NEW_PTRFREE(rpt_cond);
00156                 runningPkTable.Put(pk, rptCond);
00157                 runningPkTableMu.unlock();
00158                 return false;
00159         } else {
00160                 //wait
00161                 cio().start_err() << ThreadLabel()
00162                         << "Waiting on possibly identical "
00163                         << thing << endl;
00164                 cio().end_err();
00165                 assert(rptCond != 0);
00166                 rptCond->wait();
00167                 //woken up.  the other run must have finished
00168                 runningPkTableMu.unlock();
00169                 return true;
00170         }
00171 }
00172 // after a cache entry is added, wake up any remaining threads that
00173 // might be waiting for it.
00174 void WakeWaitingEvals(FP::Tag pk) {
00175         rpt_cond *rptCond = 0;
00176         runningPkTableMu.lock();
00177         bool found = runningPkTable.Delete(pk, /*OUT*/ rptCond);
00178         assert(found);
00179         assert(rptCond != 0);
00180         rptCond->wake();
00181         runningPkTableMu.unlock();
00182         // GC'll get rptCond
00183 }
00184 
00185 
00186 void Tags(const CompactFV::List& names, const Context& c, 
00187           /*OUT*/ FP::List& tags) {
00188   // Used for cache lookup:
00189   int len = names.num;
00190   if (len > 0) {
00191     tags.len = len;
00192     tags.fp = NEW_PTRFREE_ARRAY(FP::Tag, len);
00193     int size = names.tbl.NumArcs();
00194     Val *vals = NEW_ARRAY(Val, size);
00195     int i;
00196     for (i = 0; i < size; i++) { vals[i] = NULL; }
00197     for (i = 0; i < len; i++)   {
00198       short int idx = names.idx[i];
00199       PathKind pkind = (PathKind)names.types[i];
00200       tags.fp[i] = LookupPath(idx, pkind, names.tbl, c, vals)->FingerPrint();
00201     }
00202   } else {
00203     tags.len = 0;
00204     tags.fp = NULL;
00205   }
00206   return;
00207 }
00208 
00209 bool NamesTagsPickle(Val val, bool cutoff, const Context& inPKArgs,
00210                      /*OUT*/ char*& types, /*OUT*/ FV2::List& names,
00211                      /*OUT*/ FP::List& tags, /*OUT*/ VestaVal::T& vval,
00212                      DPaths *fv_exclude = 0) {
00213   /* Create all the stuff needed for an AddEntry call. */
00214 
00215   // We now create the secondary key of the entry. Since some dependencies
00216   // on the function arguments have already been encoded in the primary key,
00217   // they are redundant, and therefore removed.
00218   DPaths *sk = NEW_CONSTR(DPaths, (val->dps));
00219   ValueDpnd(val, sk);
00220   DepPathTbl::TIter iter(sk);
00221   DepPathTbl::KVPairPtr ptr;
00222   Text id;
00223   if(!inPKArgs.Null() || (fv_exclude != 0))
00224     {
00225       while (iter.Next(ptr)) {
00226         bool deleted = false;
00227         Context work = inPKArgs;
00228         while (!work.Null() && !deleted) {
00229           id = work.Pop()->name;
00230           if (ptr->key.content->path->getlo() == id)
00231             {
00232               sk->Delete(ptr->key, ptr, false);
00233               deleted = true;
00234             }
00235         }
00236         // If we have a set of paths to exclude from the secondary key
00237         if((fv_exclude != 0) && !deleted)
00238           {
00239             // Ugh this is O(n*m) because we have to compare each entry of
00240             // sk with each entry of fv_exclude
00241             DepPathTbl::TIter exclude_iter(fv_exclude);
00242             DepPathTbl::KVPairPtr exclude_ptr;
00243             while(exclude_iter.Next(exclude_ptr) && !deleted)
00244               {
00245                 // Determine whether the path from fv_exclude is a
00246                 // prefix of the path in this entry of sk.
00247 
00248                 // If the entry from sk has a shorter path, it's
00249                 // obviously not a prefix.
00250                 bool match = (ptr->key.content->path->size() >= 
00251                               exclude_ptr->key.content->path->size());
00252 
00253                 // Compare path elements until we get a mismatch or run
00254                 // out.
00255                 for(unsigned int i = 0;
00256                     match && (i < exclude_ptr->key.content->path->size());
00257                     i++)
00258                   {
00259                     match = (ptr->key.content->path->get(i) ==
00260                              exclude_ptr->key.content->path->get(i));
00261                   }
00262 
00263                 // Yes it's a prefix.  Exclude this secondary
00264                 // dependency.
00265                 if(match)
00266                   {
00267                     sk->Delete(ptr->key, ptr, false);
00268                     deleted = true;
00269                   }
00270               }
00271           }
00272       }
00273     }
00274   sk->Resize();
00275   // Set names and tags:
00276   int len = sk->Size();
00277   names.len = len;
00278   tags.len = len;
00279   if (len > 0) {
00280     types = NEW_PTRFREE_ARRAY(char, len);    
00281     names.name = NEW_ARRAY(FV2::TPtr, len);
00282     tags.fp = NEW_PTRFREE_ARRAY(FP::Tag, len);
00283     iter.Reset();
00284     int index = 0;
00285     while (iter.Next(ptr)) {
00286       types[index] = (char)ptr->key.content->pKind;
00287       names.name[index] = ptr->key.content->path;
00288       if (ptr->val->vKind != FpVK && ptr->key.content->pKind == ExprPK) {
00289         if (ptr->val->vKind == ClosureVK)
00290           tags.fp[index++] = ((ClosureVC*)ptr->val)->FingerPrintExpr();
00291         else {
00292           assert(ptr->val->vKind == ModelVK);
00293           tags.fp[index++] = ((ModelVC*)ptr->val)->FingerPrintFile();
00294         }
00295       }
00296       else
00297         tags.fp[index++] = ptr->val->FingerPrint();
00298     }
00299   }
00300   // Pickle the value:
00301   if (cutoff) ModelCutOff(val);
00302   return Pickle(val, vval);
00303 }
00304 
00305 static void CheckLeases() {
00306   leaseMu.lock();    
00307   bool expired = (time(NULL) - lastRenewed) > leaseDuration;
00308   bool failed = renewLease_failure;
00309   leaseMu.unlock();
00310   if (expired) {
00311     throw(Evaluator::failure("Leases timed out. Start over.", true));
00312   } else if(failed) {
00313     throw(Evaluator::failure("Lease renewal failed.", true));
00314   }
00315 }
00316 
00317 void CollectKids(CacheEntry::IndicesApp* orphanCIs, int kidsIndex,
00318                  CacheEntry::Indices& kids) {
00319   CheckLeases();
00320   kids.len = orphanCIs->len - kidsIndex;
00321   kids.index = orphanCIs->index + kidsIndex;
00322 }
00323     
00324 void UpdateOrphans(CacheEntry::IndicesApp* orphanCIs, int kidsIndex,
00325                    CacheEntry::Index ci) {
00326   frontierMu.lock();
00327   assert(kidsIndex <= orphanCIs->len);
00328   orphanCIs->len = kidsIndex;
00329   orphanCIs->Append(ci);
00330   frontierMu.unlock();  
00331 }
00332 
00333 void Checkpoint() {
00334   CheckLeases();
00335   frontierMu.lock();        
00336   addEntryCount++;
00337   if ((addEntryCount & 0x3f) == 0) {
00338     CacheEntry::IndicesApp orphanCIs;
00339     ThreadData::mu.lock();
00340     ThreadData* cur = ThreadData::head;
00341     while (cur) {
00342       assert(cur->orphanCIs != 0);
00343       for (int i = 0; i < cur->orphanCIs->len; i++) {
00344         orphanCIs.Append(cur->orphanCIs->index[i]);
00345       }
00346       cur = cur->next;
00347     }
00348     ThreadData::mu.unlock();
00349     theCache->Checkpoint(topModelRoot->fptag, topModelSid, orphanCIs, false);
00350   }
00351   frontierMu.unlock();
00352 }
00353 
00354 void FreeNamesTags(CompactFV::List& names, FP::List& tags) {
00355   // Free names and tags after cache lookup:
00356   names.tbl = PrefixTbl();
00357   tags.len = 0;
00358   tags.fp = NULL;
00359 }
00360 
00361 // General function application:
00362 Context BindApplicationArgs(ClosureVC *clos, ArgList actuals, const Context& c) {
00363   Context result, closCon = clos->con;
00364   Exprs forms = clos->func->args->elems;
00365   Exprs acts = actuals->elems;
00366   int fSize = forms.size();
00367   int aSize = acts.size();
00368   Expr fe;
00369   AssignEC *formal;
00370   Text name;
00371   int i;
00372 
00373   if (aSize > fSize + 1) {
00374     actuals->EError(cio().start_err(), "Too many actual parameters:");
00375     cio().end_err();
00376     return conEmpty;
00377   }
00378   for (i = 0; i < aSize; i++) { // Actuals to formals
00379     if (i == fSize)
00380       name = nameDot;
00381     else {
00382       fe = forms.get(i);
00383       if (fe->kind == NameEK)
00384         name = ((Name)fe)->id;
00385       else if (fe->kind == AssignEK)
00386         name = ((AssignEC*)fe)->lhs->id;
00387       else {
00388         ostream& err_stream = cio().start_err();
00389         actuals->EError(err_stream, 
00390                         "Bad parameter list. It is neither actual nor default: `");
00391         ErrorExpr(err_stream, fe);
00392         ErrorDetail(err_stream, "'.");
00393         cio().end_err();
00394         return conEmpty;
00395       }
00396     }
00397     PushToContext(name, acts.get(i), c, result);
00398   }
00399   for (i = aSize; i < fSize; i++) { // Default rest of formals
00400     fe = forms.get(i);
00401     if (fe->kind == AssignEK) {
00402       formal = (AssignEC*)fe;
00403       PushToContext(formal->lhs->id, formal->rhs, closCon, result);
00404     }
00405     else {
00406       ostream& err_stream = cio().start_err();
00407       actuals->EError(err_stream, "Bad parameter list. Must have default: `");
00408       ErrorExpr(err_stream, fe);
00409       ErrorDetail(err_stream, "'.");
00410       cio().end_err();
00411       return conEmpty;
00412     }
00413   }
00414   if (aSize <= fSize) {
00415     Name eDot = NEW_CONSTR(NameEC, (nameDot, actuals->loc));
00416     PushToContext(nameDot, eDot, c, result);
00417   }
00418   return result;
00419 }
00420 
00421 // Determine whether we should compare dependencies for this CI.  (We
00422 // only do it once per CI in a single invocation.)  Only used when
00423 // dependencyCheck is true.
00424 static bool shouldDependencyCheck(CacheEntry::Index cIndex)
00425 {
00426   static Basics::mutex mu;
00427   static BitVector *doneCIs = 0;
00428 
00429   mu.lock();
00430   if(!doneCIs)
00431     doneCIs = NEW(BitVector);
00432   bool not_yet = !doneCIs->Set(cIndex);
00433   mu.unlock();
00434   return not_yet;
00435 }
00436 
00437 Val ApplicationFromCache(ClosureVC* clos, const Context& argsCon, SrcLoc *loc) {
00438   FP::Tag pk(evaluatorFunctionVersionTag);
00439   pk.Extend((char*)(&currentPickleVersion_net), sizeof_assert(currentPickleVersion_net, 4));
00440   CompactFV::List fvNames;
00441   FV2::List entryNames;
00442   FP::List tags;
00443   CacheEntry::Index cIndex;
00444   VestaVal::T cVal;
00445   CacheIntf::LookupRes cResult = CacheIntf::Miss;
00446   Model::T model = clos->func->body->loc->shortId;
00447   Val result = 0;
00448 
00449   Val old_result = 0;
00450 
00451   IncCounter(&appCallCounter);
00452   Context evalCon = argsCon.Append(clos->con);
00453 
00454   ostream *traceRes = ThreadDataGet()->traceRes;
00455   // Evaluate in the nocaching cases:
00456   if (cacheOption != 3 || clos->func->noCache) {
00457     // Normal function caching is disabled.
00458     if (traceRes) *traceRes << ": disabled\n";
00459     result = clos->func->body->Eval(evalCon);
00460     if (cacheOption < 2) return result;
00461     return FuncDpnd(result, clos, argsCon);
00462   }
00463 
00464   // Compute the primary key:
00465   // The pk consists of the fingerprints of the closure body, the argumnets
00466   // that either is specified by pk pragma or evaluates to simple values.
00467   pk.Extend(clos->FingerPrintExpr());
00468   Context work = argsCon;
00469   (void)work.Pop();   // Do not put the dot into pk.
00470   int last = clos->func->args->elems.size();
00471   Bit64 inPKs = clos->func->args->inPKs;
00472   Context inPKArgs;
00473   while (!work.Null()) {
00474     Assoc elem = work.Pop();
00475     if (inPKs & ((Bit64)1 << --last)) {
00476       // Add this argument into pk.
00477       pk.Extend(elem->FingerPrint());
00478       inPKArgs.Push(elem);
00479     }
00480     else {
00481       switch (elem->val->vKind) {
00482       case BooleanVK: case IntegerVK: case PrimitiveVK:
00483       case TextVK: case ErrorVK:
00484         pk.Extend(elem->FingerPrint());
00485         inPKArgs.Push(elem);
00486         break;
00487       case ClosureVK:
00488         {
00489           FP::Tag tag(elem->name);
00490           tag.Extend(((ClosureVC*)elem->val)->FingerPrintExpr());
00491           pk.Extend(tag);
00492           break;
00493         }
00494       case ModelVK:
00495         {
00496           FP::Tag tag(elem->name);
00497           tag.Extend(((ModelVC*)elem->val)->FingerPrintFile());
00498           pk.Extend(tag);
00499           break;
00500         }
00501       case FpVK:
00502         assert(false);
00503       default:
00504         break;
00505       }
00506     }
00507   }
00508   // Evaluate with caching:
00509   ThreadData *thdata = ThreadDataGet();
00510   CacheEntry::IndicesApp* orphanCIs = thdata->orphanCIs;  
00511   try {
00512     while (true) {
00513       bool noEntry;
00514       FV::Epoch epoch = theCache->FreeVariables(pk, /*OUT*/ fvNames, /*OUT*/ noEntry);
00515       if (noEntry)
00516         cResult = CacheIntf::Miss;
00517       else {
00518         Tags(fvNames, evalCon, /*OUT*/ tags);
00519         cResult = theCache->Lookup(pk, epoch, tags, /*OUT*/ cIndex, /*OUT*/ cVal);
00520       }
00521       FreeNamesTags(fvNames, tags);
00522       if (cResult == CacheIntf::Hit) {
00523         if (Unpickle(cVal, evalCon, result)) {
00524           assert(result != 0);
00525           // If we're supposed to compare dependencies, remember the
00526           // cached value and pretend this was a miss.
00527           if(dependencyCheck && shouldDependencyCheck(cIndex))
00528             {
00529               old_result = result;
00530               cResult = CacheIntf::Miss;
00531             }
00532           else
00533             {
00534               if (traceRes) {
00535                 *traceRes << ": hit (ci=" << cIndex << ")\n";
00536               }
00537               IncCounter(&appHitCounter);
00538               UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
00539               return FuncDpnd(result, clos, argsCon);
00540             }
00541         }
00542         else {
00543           OBufStream l_msg;
00544           l_msg << "ApplicationFromCache: Cache hit but bad cache data."
00545                 << endl << endl
00546                 << "\tpk = " << pk << endl
00547                 << "\tci = " << cIndex << endl << endl
00548                 << "Evaluate as cache miss." << endl;
00549           Error(cio().start_err(), Text(l_msg.str()), loc);
00550           cio().end_err();
00551           cResult = CacheIntf::Miss;
00552         }
00553       }
00554       if (cResult == CacheIntf::Miss) {
00555         if (traceRes) *traceRes << ": miss\n";
00556         int kidsIndex = orphanCIs->len;
00557 
00558         // Do the duplicate run supression
00559         if(clos->func->noDup && WaitForDuplicateEval(pk, "function")) {
00560           // a duplicate was running.  try the cache lookup again
00561           continue;
00562         }
00563         try {
00564           result = clos->func->body->Eval(evalCon);
00565           if (!noAddEntry) {
00566             // Create a new cache entry:
00567             char *types;
00568             if (NamesTagsPickle(result, false, inPKArgs, /*OUT*/ types, 
00569                                 /*OUT*/ entryNames, /*OUT*/ tags, /*OUT*/ cVal)) {
00570               Text pksource(clos->func->loc->file);
00571               pksource += "/" + clos->func->name;
00572               pksource += "(), line " + IntToText(clos->func->loc->line);
00573               pksource += ", col " + IntToText(clos->func->loc->character);
00574               if(dependencyCheck) {
00575                 // If we got a cache hit earlier that we can compare
00576                 // against (we test it this way, because we change
00577                 // cResult in when dependencyCheck is set)...
00578                 if(old_result)
00579                   {
00580                     Val new_val = NULL;
00581                     if(Unpickle(cVal, evalCon, new_val)) {
00582                       assert(new_val != 0);
00583                       PrintDepsDiffs(pksource, pk, cIndex, old_result, new_val);
00584                       PrintDepsDiffs(pksource, pk, cIndex, result, new_val, "pickle");
00585                       if (traceRes) {
00586                         *traceRes << "  " << thdata->funcCallDepth << ". "
00587                                   << clos->func->args->loc->file << ": "
00588                                   << clos->func->name
00589                                   << "(): dependencies comapred (with ci=" 
00590                                   << cIndex << ")\n";
00591                       }
00592                     }
00593                     else
00594                       {
00595                         ostream &err = cio().start_err();
00596                         Error(err, "(Impl) Trying to compare dependencies, failed to unpickle new value");
00597                         InternalError(err, cio().helper(true), "ApplicationFromCache");
00598                         // Unreached
00599                         cio().end_err();
00600                       }
00601                   }
00602               }
00603               else {
00604                 CacheEntry::Indices kids;
00605                 CollectKids(orphanCIs, kidsIndex, kids);
00606                 // Add the entry, capturing the result of the call.
00607                 CacheIntf::AddEntryRes ae_res =
00608                   theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
00609                                      kids, pksource, /*OUT*/ cIndex);
00610                 // If the AddEntry fails, die with an error.
00611                 if(ae_res != CacheIntf::EntryAdded)
00612                   {
00613                     Error(cio().start_err(), Text("AddEntry failed: ")+
00614                           CacheIntf::AddEntryResName(ae_res)+"\n"
00615                           "This may be an evaluator bug.  "
00616                           "Please report it.\n",
00617                           loc);
00618                     cio().end_err();
00619                     if (traceRes) *traceRes << endl;
00620                     throw(Evaluator::failure(Text("AddEntry failed (may be an "
00621                                                   "evaluator bug)"),
00622                                              false));
00623                   }
00624                 UpdateOrphans(orphanCIs, kidsIndex, cIndex);
00625                 Checkpoint();
00626                 if (traceRes) {
00627                   *traceRes << "  " << thdata->funcCallDepth << ". "
00628                             << clos->func->args->loc->file << ": "
00629                             << clos->func->name << "(): add (ci="
00630                             << cIndex << ")\n";
00631                 }
00632               }
00633             }
00634           }
00635           if(clos->func->noDup) {
00636             WakeWaitingEvals(pk);
00637           }
00638         } catch (...) {
00639           if(clos->func->noDup) {
00640             WakeWaitingEvals(pk);
00641           }
00642           throw;
00643         }
00644         return FuncDpnd(result, clos, argsCon);
00645       }
00646       if (cResult != CacheIntf::FVMismatch) {
00647         if (traceRes) *traceRes << ": mismatch\n";
00648         OBufStream err_msg;
00649         err_msg << "ApplicationFromCache got bad result: "
00650                 << CacheIntf::LookupResName(cResult) << endl
00651                 << "\tpk = " << pk << endl
00652                 << "\tFV epoch = " << epoch << endl
00653                 << "\ttags.len = " << tags.len << endl
00654                 << "This may be an evaluator bug.  Please report it." << endl;
00655         Error(cio().start_err(), Text(err_msg.str()), loc);
00656         cio().end_err();
00657         result = NEW(ErrorVC);
00658         return result;
00659       }
00660     }
00661   } catch (PrefixTbl::Overflow) {
00662     ostream& err_stream = cio().start_err(); 
00663     Error(err_stream, 
00664           Text("Internal limits exceeded: PrefixTbl overflow\n"), loc);
00665     err_stream << "Caching function \"" << clos->func->name
00666                << "\" defined at:" << endl << endl
00667                << "  " << clos->func->loc->file
00668                << ", line " << clos->func->loc->line
00669                << ", char " << clos->func->loc->character
00670                << endl << endl
00671                << Text("This usually means that there are too many free variables "
00672                        "in the secondary key of the function being cached.  This "
00673                        "can often be alleviated by marking more arguments with "
00674                        "the /**pk**/ pragma.  (Fixing this will also reduce the CPU "
00675                        "load of your evaluator and cache server, and improve "
00676                        "build performance.)").WordWrap()
00677                << endl << endl;
00678     cio().end_err(/*aborting*/true);
00679     // This is a fatal error.  Exit and dump core.
00680     abort();
00681   } 
00682   catch (SRPC::failure f) {
00683     Error(cio().start_err(), Text("ApplicationFromCache: SRPC failure (")
00684           + IntToText(f.r) + "): " + f.msg + ".\n", loc);
00685     cio().end_err();
00686     if (traceRes) *traceRes << endl;
00687     throw(Evaluator::failure(Text("Cache server is possibly down"), false));
00688   }
00689   //return result; // not reached
00690 }
00691 
00692 Val ApplyFunction(ClosureVC* clos, ApplyEC *ae, const Context& c) {
00693   ArgList args = ae->args;
00694   Context argsCon;
00695 
00696   argsCon = BindApplicationArgs(clos, args, c);
00697 
00698   ThreadData *thdata = ThreadDataGet();
00699   ostream *traceRes = thdata->traceRes;
00700   thdata->funcCallDepth++;
00701   if (traceRes) {
00702     *traceRes << "  " << thdata->funcCallDepth << ". "
00703       << clos->func->args->loc->file << ": "
00704       << clos->func->name << "()";
00705   }
00706   if (argsCon == conEmpty) {
00707     // when argsCon is correct, it can not be empty since `dot' must be
00708     // defined in argsCon.
00709     ostream& err_stream = cio().start_err();
00710     ErrorDetail(err_stream, "\n  Formal list is ");
00711     ErrorExpr(err_stream, clos->func->args);
00712     ErrorDetail(err_stream, "\n  Actual list is ");
00713     ErrorExpr(err_stream, args);
00714     ErrorDetail(err_stream, "\n");
00715     cio().end_err();
00716     if (traceRes) *traceRes << ": badargs\n";
00717     return NEW(ErrorVC);
00718   }
00719 
00720   // Evaluate:
00721   Val result = ApplicationFromCache(clos, argsCon, ae->loc);
00722   thdata->funcCallDepth--;
00723   return result;
00724 }
00725   
00726 // Model application:
00727 Val NormalModelFromCache(ModelVC *fun, const Context& evalCon, SrcLoc *loc) {
00728   Model::T model = fun->content->sid;
00729   FP::Tag pk(evaluatorFunctionVersionTag);
00730   pk.Extend((char*)(&currentPickleVersion_net), sizeof_assert(currentPickleVersion_net, 4));
00731   CompactFV::List fvNames;
00732   FV2::List entryNames;
00733   FP::List tags;
00734   CacheEntry::Index cIndex;
00735   VestaVal::T cVal;
00736   CacheIntf::LookupRes cResult = CacheIntf::Miss;
00737   Val result = 0;
00738 
00739   Val old_result = 0;
00740 
00741   ThreadData *thdata = ThreadDataGet();
00742   ostream *traceRes = thdata->traceRes;
00743   
00744   // Evaluate as nocache if the model imports a local model:
00745   if (((ModelEC*)fun->content->model)->ImportLocalModel()) {
00746     result = ((ModelEC*)fun->content->model)->block->Eval(evalCon);
00747     ModelCutOff(result);
00748     return result;
00749   }
00750   
00751   IncCounter(&nModelCallCounter);
00752   // Record this call if traced:
00753   if (traceRes) {
00754     *traceRes << "  " << thdata->funcCallDepth << ". " << fun->content->name;
00755   }
00756 
00757   // Compute the primary key:
00758   pk.Extend(fun->FingerPrintFile());
00759 
00760   // Evaluate:
00761   CacheEntry::IndicesApp* orphanCIs = ThreadDataGet()->orphanCIs;  
00762   try {
00763     while (true) {
00764       bool noEntry;
00765       FV::Epoch epoch = theCache->FreeVariables(pk, /*OUT*/ fvNames, /*OUT*/ noEntry);
00766       if (noEntry)
00767         cResult = CacheIntf::Miss;
00768       else {
00769         Tags(fvNames, evalCon, /*OUT*/ tags);
00770         cResult = theCache->Lookup(pk, epoch, tags, /*OUT*/ cIndex, /*OUT*/ cVal);
00771       }
00772       FreeNamesTags(fvNames, tags);
00773       if (cResult == CacheIntf::Hit) {
00774         if (Unpickle(cVal, evalCon, result)) {
00775           assert(result != 0);
00776           // If we're supposed to compare dependencies, remember the
00777           // cached value and pretend this was a miss.
00778           if(dependencyCheck && shouldDependencyCheck(cIndex))
00779             {
00780               old_result = result;
00781               cResult = CacheIntf::Miss;
00782             }
00783           else
00784             {
00785               if (traceRes) {
00786                 *traceRes << ": hit (ci=" << cIndex << ")\n";
00787               }
00788               IncCounter(&nModelHitCounter);
00789               UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
00790               return result;
00791             }
00792         }
00793         else {
00794           OBufStream l_msg;
00795           l_msg << "NormalModelFromCache: Cache hit but bad cache data."
00796                 << endl << endl
00797                 << "\tpk = " << pk << endl
00798                 << "\tci = " << cIndex << endl << endl
00799                 << "Evaluate as cache miss." << endl; 
00800           Error(cio().start_err(), Text(l_msg.str()), loc);     
00801           cio().end_err();
00802           throw(Evaluator::failure(Text("Bad cache data"), false));
00803         }
00804       }
00805       if (cResult == CacheIntf::Miss) {
00806         if (traceRes) *traceRes << ": miss\n";
00807         int kidsIndex = orphanCIs->len;
00808         result = ((ModelEC*)fun->content->model)->block->Eval(evalCon);
00809         if (!noAddEntry) {
00810           // Create the normal-case model entry:
00811           char *types;
00812           if (NamesTagsPickle(result, true, conEmpty, /*OUT*/ types, 
00813                               /*OUT*/ entryNames, /*OUT*/ tags, /*OUT*/ cVal)) {
00814             Text pksource(fun->content->name);
00815             pksource += "() (normal)";
00816             if(dependencyCheck) {
00817               // If we got a cache hit earlier that we can compare
00818               // against (we test it this way, because we change
00819               // cResult in when dependencyCheck is set)...
00820               if(old_result)
00821                 {
00822                   Val new_val = NULL;
00823                   if(Unpickle(cVal, evalCon, new_val)) {
00824                     assert(new_val != 0);
00825                     PrintDepsDiffs(pksource, pk, cIndex, old_result, new_val);
00826                     PrintDepsDiffs(pksource, pk, cIndex, result, new_val, "pickle");
00827                     if (traceRes) {
00828                       *traceRes << "  " << thdata->funcCallDepth << ". " 
00829                                 << fun->content->name
00830                                 << ": dependencies comapred (with ci=" 
00831                                 << cIndex << ")\n";
00832                     }
00833                   }
00834                   else
00835                     {
00836                       ostream &err = cio().start_err();
00837                       Error(err, "(Impl) Trying to compare dependencies, failed to unpickle new value");
00838                       InternalError(err, cio().helper(true), "NormalModelFromCache");
00839                       // Unreached
00840                       cio().end_err();
00841                     }
00842                 }
00843             }
00844             else {
00845               CacheEntry::Indices kids;
00846               CollectKids(orphanCIs, kidsIndex, kids);
00847               // Add the entry, capturing the result of the call.
00848               CacheIntf::AddEntryRes ae_res =
00849                 theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
00850                                    kids, pksource, /*OUT*/ cIndex);
00851               // If the AddEntry fails, die with an error.
00852               if(ae_res != CacheIntf::EntryAdded)
00853                 {
00854                   Error(cio().start_err(), Text("AddEntry failed: ")+
00855                         CacheIntf::AddEntryResName(ae_res)+"\n"
00856                         "This may be an evaluator bug.  "
00857                         "Please report it.\n", loc);
00858                   cio().end_err();
00859                   if (traceRes) *traceRes << endl;
00860                   throw(Evaluator::failure(Text("AddEntry failed (may be an "
00861                                                 "evaluator bug)"),
00862                                            false));
00863                 }
00864               UpdateOrphans(orphanCIs, kidsIndex, cIndex);
00865               Checkpoint();
00866               if (traceRes) {
00867                 *traceRes << "  " << thdata->funcCallDepth << ". "
00868                           << fun->content->name
00869                           << ": add (ci=" << cIndex << ")\n";
00870               }
00871             }
00872           }
00873         }
00874         return result;
00875       }
00876       if (cResult != CacheIntf::FVMismatch) {
00877         if (traceRes) *traceRes << ": mismatch\n";
00878         OBufStream err_msg;
00879         err_msg << "NormalModelFromCache got bad result: "
00880                 << CacheIntf::LookupResName(cResult) << endl
00881                 << "\tpk = " << pk << endl
00882                 << "\tFV epoch = " << epoch << endl
00883                 << "\ttags.len = " << tags.len << endl
00884                 << "This may be an evaluator bug.  Please report it." << endl;
00885         Error(cio().start_err(), Text(err_msg.str()), loc);
00886         cio().end_err();
00887         result = NEW(ErrorVC);
00888         return result;
00889       }
00890     }
00891   } catch (PrefixTbl::Overflow) {
00892     ostream& err_stream = cio().start_err();
00893     Error(err_stream, 
00894           Text("Internal limits exceeded: PrefixTbl overflow\n"), loc);
00895     err_stream << "Caching model (normal):" << endl << endl
00896                << "  " << fun->content->name
00897                << endl << endl
00898                << Text("This usually means that there are too many free variables "
00899                        "in the secondary key of the function being cached.  For "
00900                        "models, this may mean too much work is being done in a "
00901                        "single model file.  Try splitting up the work of this "
00902                        "model file into several separate model files each doing "
00903                        "a smaller amount of work.  (Fixing this will also reduce "
00904                        "the CPU load of your evaluator and cache server, and "
00905                        "improve build performance.)").WordWrap()
00906                << endl << endl;
00907     cio().end_err(/*aborting*/true);
00908     // This is a fatal error.  Exit and dump core.
00909     abort();
00910   }
00911   catch (SRPC::failure f) {
00912     fun->VError(cio().start_err(), Text("NormalModelFromCache: SRPC failure (")
00913                 + IntToText(f.r) + "): " + f.msg + ".\n");
00914     cio().end_err();
00915     if (traceRes) *traceRes << endl;
00916     throw(Evaluator::failure(Text("Cache server is possibly down"), false));
00917   }
00918 }
00919 
00920 Val ModelFromCache(ModelVC* fun, const Context& argsCon, SrcLoc *loc) {
00921   Context evalCon;
00922   Model::T model = fun->content->sid;
00923   FP::Tag pk(evaluatorFunctionVersionTag);
00924   pk.Extend((char*)(&currentPickleVersion_net), sizeof_assert(currentPickleVersion_net, 4));
00925   CompactFV::List fvNames;
00926   FV2::List entryNames;
00927   FP::List tags;
00928   CacheEntry::Index cIndex;
00929   VestaVal::T cVal;
00930   CacheIntf::LookupRes cResult = CacheIntf::Miss;
00931   Val result = 0;
00932 
00933   Val old_result = 0;
00934 
00935   IncCounter(&sModelCallCounter);
00936   ThreadData *thdata = ThreadDataGet();
00937   ostream *traceRes = thdata->traceRes;
00938   
00939   // Evaluate in the nocache cases:
00940   if (cacheOption < 2) {
00941     if (traceRes) *traceRes << ": disabled\n";
00942     Val fun1 = ((ModelVC*)fun)->Force();
00943     if (fun1->vKind == ModelVK) {
00944       ModelEC *modelExpr = (ModelEC*)((ModelVC*)fun1)->content->model;
00945       evalCon = argsCon.Append(((ModelVC*)fun1)->content->c);
00946       return modelExpr->block->Eval(evalCon);
00947     }
00948     ostream& err_stream = cio().start_err();
00949     Error(err_stream, "Trying to apply a model that failed to parse: `", loc);
00950     ErrorVal(err_stream, fun1);
00951     ErrorDetail(err_stream, "'.\n");
00952     cio().end_err();
00953     result = NEW(ErrorVC);
00954     return result;
00955   }
00956   
00957   // Compute the primary key:
00958   pk.Extend(fun->FingerPrint());
00959 
00960   // Evaluate with caching:
00961   CacheEntry::IndicesApp* orphanCIs = ThreadDataGet()->orphanCIs;  
00962   try {
00963     while (true) {
00964       bool noEntry;
00965       FV::Epoch epoch = theCache->FreeVariables(pk, /*OUT*/ fvNames, /*OUT*/ noEntry);
00966       if (noEntry)
00967         cResult = CacheIntf::Miss;
00968       else {
00969         Tags(fvNames, argsCon, /*OUT*/ tags);
00970         cResult = theCache->Lookup(pk, epoch, tags, /*OUT*/ cIndex, /*OUT*/ cVal);
00971       }
00972       FreeNamesTags(fvNames, tags);
00973       if (cResult == CacheIntf::Hit) {
00974         if (Unpickle(cVal, argsCon, result)) {
00975           assert(result != 0);
00976           // If we're supposed to compare dependencies, remember the
00977           // cached value and pretend this was a miss.
00978           if(dependencyCheck && shouldDependencyCheck(cIndex))
00979             {
00980               old_result = result;
00981               cResult = CacheIntf::Miss;
00982             }
00983           else
00984             {
00985               if (traceRes) {
00986                 *traceRes << ": hit (ci=" << cIndex << ")\n";
00987               }
00988               IncCounter(&sModelHitCounter);
00989               UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
00990               return ModelDpnd(result, fun, argsCon);
00991             }
00992         }
00993         else {
00994           OBufStream l_msg;
00995           l_msg << "ModelFromCache: Cache hit but bad cache data." << endl << endl
00996                 << "\tpk = " << pk << endl
00997                 << "\tci = " << cIndex << endl << endl
00998                 << "Evaluate as cache miss." << endl;
00999           Error(cio().start_err(), Text(l_msg.str()), loc);
01000           cio().end_err();
01001           throw(Evaluator::failure(Text("Bad cache data"), false));
01002         }
01003       }
01004       if (cResult == CacheIntf::Miss) {
01005         if (traceRes) *traceRes << ": miss\n";
01006         int kidsIndex = orphanCIs->len;
01007         Val fun1 = ((ModelVC*)fun)->Force();
01008         if (fun1->vKind == ModelVK) {
01009           evalCon = argsCon.Append(((ModelVC*)fun1)->content->c);
01010           if(((ModelEC*)fun->content->model)->noDup && WaitForDuplicateEval(pk, "model")) {
01011             continue;
01012           }
01013           try {
01014             result = NormalModelFromCache(fun, evalCon, loc);
01015             if(((ModelEC*)fun->content->model)->noDup) {
01016                     WakeWaitingEvals(pk);
01017             }
01018           } catch (...) {
01019             if(((ModelEC*)fun->content->model)->noDup) {
01020               WakeWaitingEvals(pk);
01021             }
01022             throw;
01023           }
01024           if (noAddEntry) {
01025             ModelCutOff(result);
01026           }
01027           else {
01028             // Create the special-case model entry:
01029             char *types;
01030             if (NamesTagsPickle(result, false, conEmpty, /*OUT*/ types, 
01031                                 /*OUT*/ entryNames, /*OUT*/ tags, /*OUT*/ cVal)) {
01032               Text pksource(fun->content->name);
01033               pksource += "() (special)";         
01034               if(dependencyCheck) {
01035                 // If we got a cache hit earlier that we can compare
01036                 // against (we test it this way, because we change
01037                 // cResult in when dependencyCheck is set)...
01038                 if(old_result)
01039                   {
01040                     Val new_val = NULL;
01041                     if(Unpickle(cVal, evalCon, new_val)) {
01042                       assert(new_val != 0);
01043                       PrintDepsDiffs(pksource, pk, cIndex, old_result, new_val);
01044                       PrintDepsDiffs(pksource, pk, cIndex, result, new_val, "pickle");
01045                       if (traceRes) {
01046                         *traceRes << "  " << thdata->funcCallDepth << ". " 
01047                                   << fun->content->name
01048                                   << ": dependencies comapred (with ci="
01049                                   << cIndex << ")\n";
01050                       }
01051                     }
01052                     else
01053                       {
01054                         ostream &err = cio().start_err();
01055                         Error(err, "(Impl) Trying to compare dependencies, failed to unpickle new value");
01056                         InternalError(err, cio().helper(true), "ModelFromCache");
01057                         // Unreached
01058                         cio().end_err();
01059                       }
01060                   }
01061               }
01062               else {
01063                 CacheEntry::Indices kids;
01064                 CollectKids(orphanCIs, kidsIndex, kids);
01065                 // Add the entry, capturing the result of the call.
01066                 CacheIntf::AddEntryRes ae_res =
01067                   theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
01068                                      kids, pksource, /*OUT*/ cIndex);
01069                 // If the AddEntry fails, die with an error.
01070                 if(ae_res != CacheIntf::EntryAdded)
01071                   {
01072                     Error(cio().start_err(), Text("AddEntry failed: ")+
01073                           CacheIntf::AddEntryResName(ae_res)+"\n"
01074                           "This may be an evaluator bug.  "
01075                           "Please report it.\n", loc);
01076                     cio().end_err();
01077                     if (traceRes) *traceRes << endl;
01078                     throw(Evaluator::failure(Text("AddEntry failed (may be an "
01079                                                   "evaluator bug)"),
01080                                              false));
01081                   }
01082                 UpdateOrphans(orphanCIs, kidsIndex, cIndex);
01083                 Checkpoint();
01084                 if (traceRes) {
01085                   *traceRes << "  " << thdata->funcCallDepth << ". "
01086                             << fun->content->name
01087                             << ": add (ci=" << cIndex << ")\n";
01088                 }
01089               }
01090             }
01091           }
01092           return ModelDpnd(result, fun, argsCon);
01093         }
01094         ostream& err_stream = cio().start_err();
01095         Error(err_stream, "Trying to apply a model that failed to parse: `", loc);
01096         ErrorVal(err_stream, fun1);
01097         ErrorDetail(err_stream, "'.\n");
01098         cio().end_err();        
01099         result = NEW(ErrorVC);
01100         return result->Merge(fun);
01101       }
01102       if (cResult != CacheIntf::FVMismatch) {
01103         if (traceRes) *traceRes << ": mismatch\n";
01104         OBufStream err_msg;
01105         err_msg << "ModelFromCache got bad result: "
01106                 << CacheIntf::LookupResName(cResult) << endl
01107                 << "\tpk = " << pk << endl
01108                 << "\tFV epoch = " << epoch << endl
01109                 << "\ttags.len = " << tags.len << endl
01110                 << "This may be an evaluator bug.  Please report it." << endl;
01111         
01112         Error(cio().start_err(), Text(err_msg.str()), loc);
01113         cio().end_err();
01114         result = NEW(ErrorVC);
01115         return result;
01116       }
01117     }
01118   } catch (PrefixTbl::Overflow) {
01119     ostream& err_stream = cio().start_err();
01120     Error(err_stream, Text("Internal limits exceeded: PrefixTbl overflow\n"), loc);
01121     err_stream << "Caching model (special):" << endl << endl
01122                << "  " << fun->content->name
01123                << endl << endl
01124                << Text("This usually means that there are too many free variables "
01125                        "in the secondary key of the function being cached.  For "
01126                        "models, this may mean too much work is being done in a "
01127                        "single model file.  Try splitting up the work of this "
01128                        "model file into several separate model files each doing "
01129                        "a smaller amount of work.  (Fixing this will also reduce "
01130                        "the CPU load of your evaluator and cache server, and "
01131                        "improve build performance.)").WordWrap()
01132                << endl << endl;
01133     cio().end_err(/*aborting*/true);
01134     // This is a fatal error.  Exit and dump core.
01135     abort();
01136   } catch (SRPC::failure f) {
01137     Error(cio().start_err(), 
01138           Text("ModelFromCache: SRPC failure (") + IntToText(f.r) + "): "
01139           + f.msg + ".\n", loc);
01140     cio().end_err();
01141     if (traceRes) *traceRes << endl;
01142     throw(Evaluator::failure(Text("Cache server is possibly down"), false));
01143   }
01144   //return result; // not reached
01145 }
01146 
01147 Val ApplyModel(ModelVC* fun, ApplyEC *ae, const Context& c) {
01148   /* There are two cache entries created.  The first one created in
01149      NormalModelFromCache is the normal-case model entry, the second one
01150      is the special-case model entry.  In cache lookup, we always first
01151      look up the special-case model entry, and then the normal-case
01152      model entry.   */
01153   ArgList args = ae->args;
01154   Exprs acts = args->elems;
01155   Context argsCon;
01156 
01157   ThreadData *thdata = ThreadDataGet();
01158   ostream *traceRes = thdata->traceRes;
01159 
01160   // Bind model argument:
01161   int aSize = acts.size();
01162   if (aSize == 0) {
01163     Name eDot = NEW_CONSTR(NameEC, (nameDot, args->loc));
01164     PushToContext(nameDot, eDot, c, argsCon);
01165   }
01166   else if (aSize == 1)
01167     PushToContext(nameDot, acts.getlo(), c, argsCon);
01168   else {
01169     args->EError(cio().start_err(), "Too many actual parameters:");
01170     cio().end_err();
01171     thdata->funcCallDepth++;
01172     if (traceRes) {
01173       *traceRes << "  " << thdata->funcCallDepth << ". " << fun->content->name;
01174       *traceRes << ": badargs\n";
01175     }
01176     thdata->funcCallDepth--;
01177     return NEW(ErrorVC);
01178   }
01179 
01180   thdata->funcCallDepth++;
01181   // Record this call if traced:
01182   if (traceRes) {
01183     *traceRes << "  " << thdata->funcCallDepth << ". " << fun->content->name;
01184   }
01185 
01186   // Evaluate:
01187   Val result = ModelFromCache(fun, argsCon, ae->loc);
01188   thdata->funcCallDepth--;
01189   return result;
01190 }  
01191 
01192 // RunTool application:
01193 bool CheckTreatment(TextVC *tr) {
01194   Text txt(tr->NDS());
01195   return (txt == "ignore" || 
01196           txt == "report" || 
01197           txt == "report_nocache" ||
01198           txt == "value" ||
01199           txt == "report_value");         
01200 }
01201 
01202 bool AllTexts(BindingVC *b) {
01203   Context work = b->elems;
01204   while (!work.Null()) {
01205     Assoc a = work.Pop();
01206     if (a->val->vKind != TextVK) return false;
01207   }
01208   return true; 
01209 }
01210 
01211 bool BindRunToolArgs(ArgList args, const Context& c,
01212                      RunToolArgs& runToolArgs) {
01213   // Handle type-checking and defaulting of arguments to _run_tool
01214   int nArgs = args->Length();
01215   Exprs elems = args->elems;
01216   Val val;
01217 
01218   if (nArgs < 2) {
01219     args->EError(cio().start_err(), "Too few actual parameters:");
01220     cio().end_err();
01221     return false;
01222   }
01223   if (nArgs > 10) {
01224     args->EError(cio().start_err(), "Too many actual parameters:");
01225     cio().end_err();
01226     return false;
01227   }
01228   
01229   runToolArgs.loc = args->loc;
01230 
01231   // platform:
01232   val = elems.get(0)->Eval(c);
01233   if (val->vKind != TextVK) {
01234     args->EError(cio().start_err(), 
01235                  "The `platform' argument to _run_tool must be a text:");
01236     cio().end_err();
01237     return false;
01238   }
01239   runToolArgs.platform = (TextVC*)val;
01240 
01241   // command:
01242   val = elems.get(1)->Eval(c);
01243   bool ok = false;
01244   if (val->vKind == ListVK) {
01245     Vals vs = ((ListVC*)val)->elems;
01246     ok = true;
01247     while (!vs.Null())
01248       if (vs.Pop()->vKind != TextVK) { ok = false; break; }
01249   }
01250   if (!ok) {
01251     args->EError(cio().start_err(),
01252                  "The `command' argument to _run_tool must be a list of texts:");
01253     cio().end_err();
01254     return false;
01255   }
01256   runToolArgs.command_line = (ListVC*)val;
01257 
01258   // stdin:
01259   if (nArgs <= 2) {
01260     Text stdin_default(emptyText);
01261     val = NEW_CONSTR(TextVC, (stdin_default));
01262   }
01263   else {
01264     val = elems.get(2)->Eval(c);
01265     if (val->vKind != TextVK) {
01266       args->EError(cio().start_err(), 
01267                    "The `stdin' argument to _run_tool must be a text:");
01268       cio().end_err();
01269       return false;
01270     }
01271   }
01272   runToolArgs.stdin_data = (TextVC*)val;
01273 
01274   // stdout_treatment:
01275   if (nArgs <= 3) {
01276     Text stdout_treatment_default("report");
01277     val = NEW_CONSTR(TextVC, (stdout_treatment_default));
01278   }
01279   else {
01280     val = elems.get(3)->Eval(c);
01281     if (val->vKind != TextVK || !CheckTreatment((TextVC*)val)) {
01282       args->EError(cio().start_err(),
01283                    "The `stdout_treatment' argument to _run_tool is not a suitable text:");
01284       cio().end_err();
01285       return false;
01286     }
01287   }
01288   runToolArgs.stdout_treatment = (TextVC*)val;
01289 
01290   // stderr_treatment:
01291   if (nArgs <= 4) {
01292     Text stderr_treatment_default("report");
01293     val = NEW_CONSTR(TextVC, (stderr_treatment_default));
01294   }
01295   else {
01296     val = elems.get(4)->Eval(c);
01297     if (val->vKind != TextVK || !CheckTreatment((TextVC *)val)) {
01298       args->EError(cio().start_err(),
01299                    "The `stderr_treatment' argument to _run_tool is not a suitable text:");
01300       cio().end_err();
01301       return false;
01302     }
01303   }
01304   runToolArgs.stderr_treatment = (TextVC*)val;
01305 
01306   // status_treatment:
01307   if (nArgs <= 5) {
01308     Text status_treatment_default("report_nocache");
01309     val = NEW_CONSTR(TextVC, (status_treatment_default));
01310   }
01311   else {
01312     val = elems.get(5)->Eval(c);
01313     if (val->vKind != TextVK || !CheckTreatment((TextVC *)val)) {
01314       args->EError(cio().start_err(), 
01315                    "The `status_treatment' argument to _run_tool is not a suitable text:");
01316       cio().end_err();
01317       return false;
01318     }
01319   }
01320   runToolArgs.status_treatment = (TextVC*)val;
01321 
01322   // signal_treatment:
01323   if (nArgs <= 6) {
01324     Text signal_treatment_default("report_nocache");
01325     val = NEW_CONSTR(TextVC, (signal_treatment_default));
01326   }
01327   else {
01328     val = elems.get(6)->Eval(c);
01329     if (val->vKind != TextVK || !CheckTreatment((TextVC *)val)) {
01330       args->EError(cio().start_err(),
01331                    "The `signal_treatment' argument to _run_tool is not a suitable text:");
01332       cio().end_err();
01333       return false;
01334     }
01335   }
01336   runToolArgs.signal_treatment = (TextVC*)val;
01337 
01338   // fp_content:
01339   if (nArgs <= 7) {
01340     val = fpContent;
01341   }
01342   else {
01343     val = elems.get(7)->Eval(c);
01344     if (val->vKind == BooleanVK) {
01345       val = NEW_CONSTR(IntegerVC, (((BooleanVC*)val)->b ? -1 : 0));
01346     }
01347     else if (val->vKind != IntegerVK) {
01348       args->EError(cio().start_err(),
01349                    "The `fp_content' argument to _run_tool must be an integer or boolean:");
01350       cio().end_err();
01351       return false;
01352     }
01353     else if (((IntegerVC*)val)->num == -2) {
01354       val = fpContent;
01355     }
01356   }
01357   runToolArgs.fp_content = (IntegerVC*)val;
01358 
01359   // wd:
01360   if (nArgs <= 8) {
01361     Text wd_name(".WD");
01362     val = NEW_CONSTR(TextVC, (wd_name));
01363   }
01364   else {
01365     val = elems.get(8)->Eval(c);
01366     if (val->vKind != TextVK) {
01367       args->EError(cio().start_err(),
01368                    "The `wd' argument to _run_tool must be a text:");
01369       cio().end_err();
01370       return false;
01371     }
01372   }
01373   runToolArgs.wd_name = (TextVC*)val;
01374 
01375   // existing_writable:
01376   if (nArgs <= 9) {
01377     val = NEW_CONSTR(BooleanVC, (false));
01378   }
01379   else {
01380     val = elems.get(9)->Eval(c);
01381     if (val->vKind != BooleanVK) {
01382       args->EError(cio().start_err(), 
01383                    "The `existing_writable' argument to _run_tool must be a boolean:");
01384       cio().end_err();
01385       return false;
01386     }      
01387   }
01388   runToolArgs.existing_writable = (BooleanVC*)val;
01389 
01390   // .:
01391   val = LookupInContext(nameDot, c);
01392   if (val->vKind != BindingVK) {
01393     args->EError(cio().start_err(),
01394                  "The `.' argument to _run_tool must be a binding:");
01395     cio().end_err();
01396     return false;
01397   }
01398   runToolArgs.dot = (BindingVC *)val->Copy();
01399   runToolArgs.dot->path = NEW_CONSTR(DepPath, (nameDot));
01400   Val envVars = runToolArgs.dot->Lookup("envVars");
01401   if (envVars->vKind != BindingVK || !AllTexts((BindingVC*)envVars)) {
01402     args->EError(cio().start_err(),
01403                  "./envVars isn't a binding of texts:");
01404     cio().end_err();
01405     return false;
01406   }
01407   Val root = runToolArgs.dot->Lookup("root"); 
01408   if (root->vKind != BindingVK) {
01409     args->EError(cio().start_err(), "./root isn't a binding:");
01410     cio().end_err();
01411     return false;
01412   }
01413 
01414   // ./dep_control:
01415   val = runToolArgs.dot->LookupNoDpnd("tool_dep_control"); 
01416   if ((val == valUnbnd) || (val == 0)) {
01417     val = default_dep_control;
01418   }
01419   else {
01420     if (val->vKind != BindingVK) {
01421       args->EError(cio().start_err(), 
01422                    "./tool_dep_control must be a binding");
01423       cio().end_err();
01424       return false;
01425     }
01426     // Check for an unrecognized names in dep_control, and warn the
01427     // user if there are any.
01428     {
01429       TextSeq unrecognized_names;
01430       Context work = ((BindingVC *) val)->elems;
01431       while (!work.Null()) {
01432         Assoc a = work.Pop();
01433         // Note: if any new names are added to dep_control, this will
01434         // need to be updated.
01435         if((a->name != "pk") &&
01436            (a->name != "coarse") &&
01437            (a->name != "coarse_names"))
01438           unrecognized_names.addhi(a->name);
01439       }
01440       // We found some unrecognized names.  Print a warning for the
01441       // user as we'll ignore them.
01442       if(unrecognized_names.size() > 0)
01443         {
01444           ostream& err_stream = cio().start_err();
01445           Warning(err_stream,
01446                   "ignoring unrecognized names in ./tool_dep_control:",
01447                   runToolArgs.loc);
01448           err_stream << endl;
01449           for(unsigned int i = 0; i < unrecognized_names.size(); i++)
01450             {
01451               err_stream << "\t" << unrecognized_names.get_ref(i) << endl;
01452             }
01453           err_stream << endl;
01454           cio().end_err();
01455         }
01456     }
01457   }
01458   assert(val->vKind == BindingVK);
01459   runToolArgs.dep_control = (BindingVC *) val;
01460 
01461   // RunTool arguments are ok.
01462   return true;
01463 }
01464 
01465 // Make it possibke to use std::sort on a container of Assocs (see
01466 // below).
01467 static bool AssocNameLessThan(const Assoc &a, const Assoc &b)
01468 {
01469   assert(a != 0);
01470   assert(b != 0);
01471   return a->name < b->name;
01472 }
01473 
01474 static void print_ignored_path(ostream &out, const char *reason,
01475                                const ArcSeq &path)
01476 {
01477   out << "\t";
01478   // The first two elements of the path are always "./root", so we
01479   // skip them when printing a message about ignoring something.
01480   for(unsigned int i = 2; i < path.size(); i++)
01481     {
01482       if(i > 2) out << "/";
01483       out << path.get_ref(i);
01484     }
01485   out << " : " << reason << endl;
01486 }
01487 
01488 void RunToolPKFromRoot(BindingVC *control, BindingVC *dir, FP::Tag &pk,
01489                        const ArcSeq &partial_path, DPaths &fv_exclude,
01490                        ostream &ignore_msgs)
01491 {
01492   // We start by sorting the control binding by name.  We do this to
01493   // make sure that the PK does not depend on the order of elements in
01494   // the control binding.
01495   Context work_con = control->elems;
01496   Sequence<Assoc> work;
01497   while(!work_con.Null())
01498     {
01499       work.addhi(work_con.Pop());
01500     }
01501   std::sort(work.begin(), work.end(), AssocNameLessThan);
01502 
01503   // Now go through the sorted control binding
01504   while(work.size() > 0)
01505     {
01506       Assoc a = work.remlo();
01507       ArcSeq path_seq(partial_path);
01508       path_seq.addhi(a->name);
01509       Val v = dir->LookupNoDpnd(a->name);
01510 
01511       if((v != 0) && (v != valUnbnd))
01512         {
01513           // If the control value is a non-zero integer or a true
01514           // boolean, then we are to include this value in the PK
01515           if(((a->val->vKind == IntegerVK) &&
01516               ((IntegerVC *) a->val)->num) ||
01517              ((a->val->vKind == BooleanVK) &&
01518               ((BooleanVC *)a->val)->b))
01519             {
01520               // We construct a DepPath because it's a convenient way
01521               // to get a fingerprint for the path that we can include
01522               // in the PK along with the fingerprint of the value.
01523               // (We must include the path to avoid the case of the
01524               // same file appearing at two different paths and being
01525               // included in the PK at those different paths.)
01526               DepPath path(NEW_CONSTR(ArcSeq, (path_seq)), DummyPK);
01527 
01528               pk.Extend(path.content->pathFP);
01529               pk.Extend(v->FingerPrint());
01530 
01531               // Remember that we need to exclude this path from the
01532               // secondary dependencies of this _run_tool when adding
01533               // a cache entry.
01534               fv_exclude.Add(&path, a->val);
01535             }
01536           // If both are bindings, recurse
01537           else if((a->val->vKind == BindingVK) &&
01538                   (v != 0) &&
01539                   (v->vKind == BindingVK))
01540             {
01541               RunToolPKFromRoot((BindingVC *) a->val, (BindingVC *) v,
01542                                 pk, path_seq, fv_exclude, ignore_msgs);
01543             }
01544           // Note if the control is a binding but the value from the
01545           // directory is some other type, we will ignore it.
01546           else
01547             {
01548               print_ignored_path(ignore_msgs,
01549                                  ((a->val->vKind == BindingVK)
01550                                   ? "control binding for non-directory"
01551                                   : "invalid control type"),
01552                                  path_seq);
01553             }
01554         }
01555       // Note that if the the value is missing in the directory, we
01556       // ignore the control value.
01557       else
01558         {
01559           print_ignored_path(ignore_msgs, "not in ./root", path_seq);
01560         }
01561     }
01562 }
01563 
01564 DPaths *RunToolPK(const RunToolArgs& runToolArgs, FP::Tag &pk) {
01565   // Primary key for a runtool call:
01566   // We combine fingerprints of relevant arguments to _run_tool, 
01567   // except for ./root, whose dependencies are fine-grained. 
01568   pk.Extend("_run_tool");
01569   pk.Extend(runToolArgs.platform->FingerPrint());
01570   pk.Extend(runToolArgs.command_line->FingerPrint());
01571   pk.Extend(runToolArgs.stdin_data->FingerPrint());
01572   pk.Extend(runToolArgs.stdout_treatment->FingerPrint());
01573   pk.Extend(runToolArgs.stderr_treatment->FingerPrint());
01574   pk.Extend(runToolArgs.status_treatment->FingerPrint());
01575   pk.Extend(runToolArgs.signal_treatment->FingerPrint());
01576   pk.Extend(runToolArgs.fp_content->FingerPrint());
01577   pk.Extend(runToolArgs.wd_name->FingerPrint());
01578   if (runToolArgs.existing_writable->b)
01579     pk.Extend(runToolArgs.existing_writable->FingerPrint());
01580   Val envVars = runToolArgs.dot->Lookup("envVars");
01581   pk.Extend(envVars->FingerPrint());
01582 
01583   DPaths *fv_exclude = 0;
01584   if(runToolArgs.dep_control != 0)
01585     {
01586       Val pk_control = runToolArgs.dep_control->LookupNoDpnd("pk");
01587 
01588       if((pk_control != 0) &&
01589          (pk_control != valUnbnd))
01590         {
01591           if(pk_control->vKind == BindingVK)
01592             {
01593               ArcSeq path_seq;
01594               path_seq.addhi(".");
01595               path_seq.addhi("root");
01596 
01597               fv_exclude = NEW(DPaths);
01598               Val root = runToolArgs.dot->LookupNoDpnd("root"); 
01599               assert(root->vKind == BindingVK);
01600               OBufStream ignore_msgs;
01601               RunToolPKFromRoot((BindingVC *) pk_control, (BindingVC *) root,
01602                                 pk, path_seq, *fv_exclude, ignore_msgs);
01603               // If we ignored something from pk_control, print a
01604               // warning for the user
01605               if(!ignore_msgs.empty())
01606                 {
01607                   ostream& err_stream = cio().start_err();
01608                   Warning(err_stream,
01609                           ("ignoring some values in 'pk' sub-binding"
01610                            " of ./tool_dep_control:"),
01611                           runToolArgs.loc);
01612                   err_stream << endl
01613                              << ignore_msgs.str()
01614                              << endl;
01615                   cio().end_err();
01616                 }
01617             }
01618           else
01619             {
01620               // We're ignoring the whole thing because it's not a
01621               // binding: print a warning for the user
01622               Warning(cio().start_err(),
01623                       "ignoring non-binding for 'pk' in ./tool_dep_control",
01624                       runToolArgs.loc);
01625               cio().end_err();
01626             }
01627         }
01628       
01629     }
01630   return fv_exclude;
01631 }
01632 
01633 Val MergeArgsDpnd(Val result, const RunToolArgs& args) {
01634   // Add the dependency of the arguments of this runtool call.
01635   result->Merge(args.platform);
01636 
01637   ListVC *command = args.command_line;
01638   result->Merge(command);
01639   if (!command->path) {
01640     if (command->lenDps != NULL &&
01641         command->lenDps->Size() != 0) {
01642       DPaths psTemp;
01643       ValueDpnd(command, &psTemp);
01644       result->MergeDPS(&psTemp);
01645     }
01646     else {
01647       Vals vs = command->elems;
01648       while (!vs.Null())
01649         result->Merge(vs.Pop());
01650     }
01651   }
01652   result->Merge(args.stdin_data);
01653   result->Merge(args.stdout_treatment);
01654   result->Merge(args.stderr_treatment);
01655   result->Merge(args.wd_name);
01656   result->Merge(args.existing_writable);
01657   
01658   Val envVars = args.dot->Lookup("envVars");
01659   assert(envVars->vKind == BindingVK);
01660   result->Merge((BindingVC*)envVars);
01661   assert(envVars->path);
01662   return result;
01663 }
01664 
01665 static Basics::thread renewLeaseThread;
01666 
01667 static void* RenewLeases(void *arg) throw () {
01668   time_t tsStart;
01669   // time_t sleepDuration = (time_t)(leaseDuration * 0.8);
01670   time_t sleepDuration = 10;
01671 
01672   // Remember how many time we've hit the "server busy" case.
01673   unsigned int server_busy_count = 0;
01674   
01675   while (true) {
01676     int left = sleepDuration;
01677     do {
01678       left = sleep(left);
01679     } while (left > 0);
01680 
01681     // If lease already expired, quit.
01682     leaseMu.lock();
01683     if (time(&tsStart) - lastRenewed > leaseDuration) {
01684       leaseMu.unlock();
01685       // If we've had trouble getting the cache server to accept our
01686       // calls and the leases expired, print a message about that.
01687       if(server_busy_count > 0)
01688         {
01689           Error(cio().start_err(), 
01690                 Text("RenewLeases thread got \"connection refused: server busy\" ") +
01691                 IntToText(server_busy_count) + " times, and now leases have expired!\n");
01692           cio().end_err();
01693         }
01694       return NULL;
01695     }
01696     leaseMu.unlock();
01697     
01698     // Renew leases:
01699     CacheEntry::IndicesApp orphanCIs;    
01700     frontierMu.lock();
01701     ThreadData::mu.lock();
01702     ThreadData* cur = ThreadData::head;
01703     while (cur) {
01704       assert(cur->orphanCIs != 0);
01705       for (int i = 0; i < cur->orphanCIs->len; i++) {
01706         orphanCIs.Append(cur->orphanCIs->index[i]);
01707       }
01708       for(ThreadData::orphanCI_set::iterator it =
01709             cur->unclaimed_child_orphanCIs.begin();
01710           it != cur->unclaimed_child_orphanCIs.end();
01711           it++)
01712         {
01713           orphanCIs.Append(*it);
01714         }
01715       cur = cur->next;
01716     }
01717     ThreadData::mu.unlock();
01718     frontierMu.unlock();
01719 
01720     bool renewed = false;
01721     try
01722       {
01723         // Renew the leases, remembering whether we succeeded.
01724         renewed = theCache->RenewLeases(orphanCIs);
01725 
01726         // No "server busy" SRPC failure.
01727         server_busy_count = 0;
01728 
01729         // If we didn't renew successfully, print an error message,
01730         // remember that we've failed, and exit the thread.
01731         if(!renewed)
01732           {
01733             Error(cio().start_err(), 
01734                   Text("RenewLeases returned failure!\n") +
01735                   "This may be a bug.  Please reposrt it.\n");
01736             cio().end_err();
01737 
01738             leaseMu.lock();
01739             renewLease_failure = true;
01740             leaseMu.unlock();
01741 
01742             return NULL;
01743           }
01744       }
01745     // If we get an SRPC failure...
01746     catch (SRPC::failure f)
01747       {
01748         // If this looks like hitting the cache server's connection
01749         // limits, ignore it (but remember it).  (Presumably we'll get
01750         // in on a subsequent call.)
01751         if((f.r == 1) && (f.msg.FindText("connection refused: server busy") != -1))
01752           {
01753             server_busy_count++;
01754           }
01755         // If it doesn't look like the LimService message...
01756         else
01757           {
01758             // ...assume the cache server went down.  Print an error
01759             // message with the SRPC failure, note that we've failed,
01760             // and exit the thread.
01761             Error(cio().start_err(), Text("RenewLeases thread: SRPC failure (")
01762                   + IntToText(f.r) + "): " + f.msg + ".\n");
01763             cio().end_err();
01764 
01765             leaseMu.lock();
01766             renewLease_failure = true;
01767             leaseMu.unlock();
01768 
01769             return NULL;
01770           }
01771       }
01772     
01773     // If lease expires during renewing, quit.
01774     leaseMu.lock();
01775     if (time(NULL) - lastRenewed > leaseDuration) {
01776       leaseMu.unlock();
01777       // If we've had trouble getting the cache server to accept our
01778       // calls and the leases expired, print a message about that.
01779       if(server_busy_count > 0)
01780         {
01781           Error(cio().start_err(), 
01782                 Text("RenewLeases thread got \"connection refused: server busy\" ") +
01783                 IntToText(server_busy_count) + " times, and now leases have expired!\n");
01784           cio().end_err();
01785         }
01786       return NULL;
01787     }
01788     
01789     if(renewed)
01790       {
01791         // Leases are renewed successfully:
01792         lastRenewed = tsStart;
01793       }
01794     leaseMu.unlock();    
01795   }
01796 }
01797 
01798 extern "C" void StartRenewLeaseThread_inner() {
01799   if (cacheOption != 0) {
01800     time(&lastRenewed);  
01801     renewLeaseThread.fork_and_detach(RenewLeases, (void*)NULL);
01802   }
01803 }
01804 
01805 void StartRenewLeaseThread()
01806 {
01807   static pthread_once_t init_once = PTHREAD_ONCE_INIT;
01808   pthread_once(&init_once, StartRenewLeaseThread_inner);
01809 }
01810 
01811 Val RunToolFromCache(const RunToolArgs& runToolArgs, const Context& c, SrcLoc *loc) {
01812   FP::Tag pk(evaluatorRunToolVersionTag);
01813   pk.Extend((char*)(&currentPickleVersion_net), sizeof_assert(currentPickleVersion_net, 4));
01814   CompactFV::List fvNames;
01815   FV2::List entryNames;
01816   FP::List tags;
01817   CacheEntry::Index cIndex;
01818   VestaVal::T cVal;
01819   CacheIntf::LookupRes cResult = CacheIntf::Miss;
01820   Model::T model = NullShortId;
01821   Val result = 0;
01822   VestaSource* rootForTool;
01823 
01824   Val old_result = 0;
01825   
01826   ThreadData *thdata = ThreadDataGet();
01827   ostream *traceRes = thdata->traceRes;
01828 
01829   // Evaluate in the nocaching cases:
01830   if (cacheOption == 0) {
01831     if (traceRes) *traceRes << ": disabled\n";
01832     result = RunTool(runToolArgs, rootForTool);
01833     DeleteRootForTool(rootForTool);
01834     return result;
01835   }
01836 
01837   // Compute the primary key and gather paths to be excluded from the
01838   // fv set when adding a cache entry
01839   DPaths *fv_exclude = RunToolPK(runToolArgs, pk);
01840 
01841   // Evaluate with caching:
01842   CacheEntry::IndicesApp* orphanCIs = ThreadDataGet()->orphanCIs;    
01843   try {
01844     while (true) {
01845       bool noEntry;
01846       FV::Epoch epoch = theCache->FreeVariables(pk, /*OUT*/ fvNames, /*OUT*/ noEntry);
01847       if (noEntry)
01848         cResult = CacheIntf::Miss;
01849       else {
01850         Tags(fvNames, c, /*OUT*/ tags);
01851         cResult = theCache->Lookup(pk, epoch, tags, /*OUT*/ cIndex, /*OUT*/ cVal);
01852       }
01853       FreeNamesTags(fvNames, tags);
01854       if (cResult == CacheIntf::Hit) {
01855         if (Unpickle(cVal, c, result)) {
01856           assert(result != 0);
01857           // If we're supposed to compare dependencies, remember the
01858           // cached value and pretend this was a miss.
01859           if(dependencyCheck && shouldDependencyCheck(cIndex))
01860             {
01861               old_result = result;
01862               cResult = CacheIntf::Miss;
01863             }
01864           else
01865             {
01866               if (traceRes) *traceRes << ": hit(ci=" << cIndex << ")\n";
01867               IncCounter(&toolHitCounter);
01868               if (cacheOption == 1) {
01869                 result->dps = NULL;
01870                 return result;
01871               }
01872               UpdateOrphans(orphanCIs, orphanCIs->len, cIndex);
01873               return MergeArgsDpnd(result, runToolArgs);
01874             }
01875         }
01876         else {
01877           OBufStream l_msg;
01878           l_msg << "RunToolFromCache: Cache hit but bad cache data." << endl << endl
01879                 << "\tpk = " << pk << endl
01880                 << "\tci = " << cIndex << endl << endl
01881                 << "Evaluate as cache miss." << endl;
01882           Error(cio().start_err(), Text(l_msg.str()), loc);
01883           cio().end_err();
01884           cResult = CacheIntf::Miss;
01885         }
01886       }
01887       if (cResult == CacheIntf::Miss) {
01888         if (traceRes) *traceRes << ": miss\n";
01889         int kidsIndex = orphanCIs->len;
01890 
01891         // Check to make sure there isn't an outstanding tool run with the same pk
01892         if(WaitForDuplicateEval(pk, "tool")) {
01893                 // another thread just did it.  repeat the lookup
01894                 continue;
01895         }
01896 
01897         // run the tool
01898         try {
01899           result = RunTool(runToolArgs, rootForTool);
01900           char *types;
01901           if (!noAddEntry &&
01902             NamesTagsPickle(result, false, conEmpty, /*OUT*/ types, /*OUT*/ entryNames,
01903                             /*OUT*/ tags, /*OUT*/ cVal, fv_exclude)) {
01904             Text pksource("_run_tool, command line: ");
01905             pksource += ToolCommandLineAsText(runToolArgs);
01906 
01907             if(dependencyCheck) {
01908               // If we got a cache hit earlier that we can compare
01909               // against (we test it this way, because we change
01910               // cResult in when dependencyCheck is set)...
01911               if(old_result) {
01912                 Val new_val = NULL;
01913                 if(Unpickle(cVal, c, new_val)) {
01914                   assert(new_val != 0);
01915                   PrintDepsDiffs(pksource, pk, cIndex, old_result, new_val);
01916                   PrintDepsDiffs(pksource, pk, cIndex, result, new_val, "pickle");
01917 
01918                   if (traceRes) {
01919                     *traceRes << "  " << thdata->funcCallDepth << ". " << loc->file 
01920                               << ": " << "_run_tool(): dependencies comapred (with ci="
01921                               << cIndex << ")\n";
01922                   }
01923 
01924                 } else {
01925                   ostream &err = cio().start_err();
01926                   Error(err, "(Impl) Trying to compare dependencies, failed to unpickle new value");
01927                   InternalError(err, cio().helper(true), "RunToolFromCache");
01928                   // Unreached
01929                   cio().end_err();
01930                 }
01931               }
01932             } else {
01933               CacheEntry::Indices kids;
01934               CollectKids(orphanCIs, kidsIndex, kids);
01935               // kids should be empty when evaluating eagerly.
01936 
01937               // Add the entry, capturing the result of the call.
01938               CacheIntf::AddEntryRes ae_res =
01939                     theCache->AddEntry(pk, types, entryNames, tags, cVal, model,
01940                                  kids, pksource, /*OUT*/ cIndex);
01941               // If the AddEntry fails, die with an error.
01942               if(ae_res != CacheIntf::EntryAdded) {
01943                 Error(cio().start_err(),
01944                       Text("AddEntry failed: ")+
01945                       CacheIntf::AddEntryResName(ae_res)+"\n"
01946                       "This may be an evaluator bug.  "
01947                       "Please report it.\n",
01948                       loc);
01949                 cio().end_err();
01950                 if (traceRes) *traceRes << endl;
01951                 throw(Evaluator::failure(Text("AddEntry failed (may be an "
01952                                               "evaluator bug)"),
01953                                         false));
01954               }
01955               // cIndex is added to the orphans.
01956               UpdateOrphans(orphanCIs, kidsIndex, cIndex);
01957               Checkpoint();
01958               if (traceRes) {
01959                 *traceRes << "  " << thdata->funcCallDepth << ". " << loc->file << ": "
01960                         << "_run_tool(): add (ci=" << cIndex << ")\n";
01961               }
01962             }
01963           }
01964           // now wake up the other threads waiting for the same PK
01965           WakeWaitingEvals(pk);
01966         } catch(...) {
01967           WakeWaitingEvals(pk);
01968           throw;
01969         }
01970 
01971         // delete the volatile dir for root after adding cache entry.
01972         // The new cache entry is now protecting the deriveds from weeding.
01973         DeleteRootForTool(rootForTool);   
01974         if (cacheOption == 1) {
01975           result->dps = NULL;
01976           return result;
01977         }
01978         return MergeArgsDpnd(result, runToolArgs);
01979       }
01980       if (cResult != CacheIntf::FVMismatch) {
01981         if (traceRes) *traceRes << ": mismatch\n";
01982         OBufStream err_msg;
01983         err_msg << "RunToolFromCache got bad result: "
01984                 << CacheIntf::LookupResName(cResult) << endl
01985                 << "\tpk = " << pk << endl
01986                 << "\tFV epoch = " << epoch << endl
01987                 << "\ttags.len = " << tags.len << endl
01988                 << "This may be an evaluator bug.  Please report it." << endl;
01989         Error(cio().start_err(), Text(err_msg.str()), loc);
01990         cio().end_err();
01991         result = NEW(ErrorVC);
01992         return result;
01993       }
01994     }
01995   } catch (PrefixTbl::Overflow) {
01996     Text cmd_line = ToolCommandLineAsText(runToolArgs);
01997     ostream& err_stream = cio().start_err();
01998     Error(err_stream, Text("Internal limits exceeded: PrefixTbl overflow\n"), loc);
01999     err_stream << "Caching _run_tool with command line:" << endl << endl
02000                << "  " << cmd_line << endl << endl
02001                << Text("This usually means that there are too many free variables "
02002                        "in the secondary key of the function being cached.  For "
02003                        "_run_tool calls, this may mean you're trying to do too "
02004                        "much work in a single tool invocation.  Try splitting the "
02005                        "work of this tool invocation into several separate tool "
02006                        "invocations each doing a smaller amount of work and using "
02007                        "a smaller number of source files.  (Fixing this will also "
02008                        "reduce the CPU load of your evaluator and cache server, and "
02009                        "improve build performance.)").WordWrap()
02010                << endl << endl;
02011     cio().end_err(/*aborting*/true);
02012     // This is a fatal error.  Exit and dump core.
02013     abort();
02014   } catch (SRPC::failure f) {
02015     Error(cio().start_err(), 
02016           Text("RunToolFromCache: SRPC failure (")
02017           + IntToText(f.r) + "): " + f.msg + ".\n",
02018           loc);
02019     cio().end_err();
02020     if (traceRes) *traceRes << endl;
02021     throw(Evaluator::failure(Text("Cache server is possibly down"), false));
02022   }
02023   // return result;  // not reached
02024 }
02025 
02026 Val ApplyRunTool(ArgList args, const Context& c) {
02027   RunToolArgs runToolArgs;
02028 
02029   ThreadData *thdata = ThreadDataGet();
02030   ostream *traceRes = thdata->traceRes;
02031   
02032   IncCounter(&toolCallCounter);
02033   if (!BindRunToolArgs(args, c, runToolArgs)) {
02034     thdata->funcCallDepth++;
02035     if (traceRes) {
02036       *traceRes << "  " << thdata->funcCallDepth << ". " << args->loc->file << ": ";
02037       *traceRes << "_run_tool()";
02038       *traceRes << ": badargs\n";
02039     }
02040     thdata->funcCallDepth--;
02041     return NEW(ErrorVC);
02042   }
02043   thdata->funcCallDepth++;
02044   if (traceRes) {
02045     *traceRes << "  " << thdata->funcCallDepth << ". " << args->loc->file << ": ";
02046     *traceRes << "_run_tool()";
02047   }
02048 
02049   // Evaluate:
02050   Val result = RunToolFromCache(runToolArgs, c, args->loc);
02051   thdata->funcCallDepth--;
02052   return result;
02053 }

Generated on Thu May 24 23:01:46 2007 for Vesta by  doxygen 1.5.1