Matcher::sp_iterator Matcher::setSourceFile(StringRef target) { // If target is empty, we assume it's a self-testing: // i.e., the beginning of the compilation unit will be // used. if (target.empty()) { processSubprograms(module); patchname=""; initialized = true; return sp_begin(); } std::string oldfile = filename; if (!initName(target)) return sp_end(); if (oldfile == filename) { if (DEBUG_MATCHER) errs() << "Target source didn't change since last time, reuse old processing.\n"; } else { cu_iterator ci = matchCompileUnit(target); if (ci == cu_end()) return sp_end(); MySPs.clear(); processSubprograms(*ci); std::sort(MySPs.begin(), MySPs.end(), cmpDISPCopy); if (DEBUG_MATCHER) dumpSPs(); } initialized = true; // shouldn't just return MySPs.begin(). because a CU may contain SPs from other CUs. return slideToFile(filename); }
/*---------------------------------------------------------------------- Reading input somehow failed and we need to shutdown now Args: none Result: pine exits ---*/ void read_bail(void) { dprint((1, "read_bail: cleaning up\n")); /* Do not bail out on a tcp timeout, instead close the troublesome stream */ if(ps_global->tcptimeout && some_stream_is_locked()){ ps_global->read_bail = 1; return; } end_signals(1); /* * This gets rid of temporary cache files for remote addrbooks. */ completely_done_with_adrbks(); /* * This flushes out deferred changes and gets rid of temporary cache * files for remote config files. */ if(ps_global->prc){ if(ps_global->prc->outstanding_pinerc_changes) write_pinerc(ps_global, Main, WRP_NOUSER); if(ps_global->prc->rd) rd_close_remdata(&ps_global->prc->rd); free_pinerc_s(&ps_global->prc); } /* as does this */ if(ps_global->post_prc){ if(ps_global->post_prc->outstanding_pinerc_changes) write_pinerc(ps_global, Post, WRP_NOUSER); if(ps_global->post_prc->rd) rd_close_remdata(&ps_global->post_prc->rd); free_pinerc_s(&ps_global->post_prc); } sp_end(); dprint((1, "done with read_bail clean up\n")); imap_flush_passwd_cache(TRUE); end_keyboard(F_ON(F_USE_FK,ps_global)); end_tty_driver(ps_global); if(filter_data_file(0)) our_unlink(filter_data_file(0)); exit(0); }
void sp_abort() { struct sp_table *st; for (st = sp_first_update(); st != NULL; st = sp_next_update()) { sp_undo_mod_dir(st); } sp_clear_updates(); sp_end(); }
/* * * Adjust sp_iterator to the starting position of * the target source file region. * * Assumption: MySPs contains the sorted subprograms * */ Matcher::sp_iterator Matcher::slideToFile(StringRef fname) { if (!processed) { errs() << "Warning: Matcher hasn't processed module\n"; return sp_end(); } sp_iterator I = sp_begin(), E = sp_end(); while(I != E) { std::string debugname; if (I->filename.size() > 0 && I->filename[0] == '/') debugname = I->filename; else debugname = I->directory + "/" + I->filename; if (endswith(debugname.c_str(), patchname)) { break; } I++; } if (I == E) errs() << "Warning: no matching file(" << patchname << ") was found in the CU\n"; return I; }
/** A progressive method to match the function(s) in a given scope. * When there are more than one function in the scope, the first function * will be returned and scope's beginning is *modified* to the end of this * returned function so that the caller could perform a loop of call until * matchFunction return NULL; * * * Note: finder.processModule(M) should be called before the first call of matchFunction. * * **/ Function * Matcher::matchFunction(sp_iterator & I, Scope &scope, bool & multiple) { if (!initialized) { errs() << "Matcher is not initialized\n"; return NULL; } // hit the boundary if (scope.end < scope.begin) { return NULL; } /** Off-the-shelf SP finder **/ sp_iterator E = sp_end(); while (I != E) { if (strlen(patchname) != 0) { std::string debugname = I->directory + "/" + I->filename; if (I->filename.size() > 0 && I->filename[0] == '/') debugname = I->filename; else debugname = I->directory + "/" + I->filename; if (!endswith(debugname.c_str(), patchname)) { errs() << "Warning: Reaching the end of " << patchname << " in current CU\n"; return NULL; } } if (I->lastline == 0) { if (I + 1 == E) return I->function; // It's tricky to return I here. Maybe NULL is better // Line number is guaranteed to be positive, no need to check overflow here. if (I->linenumber == (I + 1)->linenumber) { errs() << "Warning two functions overlap: "; if (I->function && (I + 1)->function) { errs() << I->function->getName() << ", "; errs() << (I + 1)->function->getName(); } errs() << "\n"; I->lastline = (I + 1)->linenumber; } else I->lastline = (I + 1)->linenumber - 1; if (I->lastline < I->linenumber) { errs() << "Bad things happened in " << patchname << ":" << scope << ", " << I->lastline << "," << I->linenumber << "\n"; assert(false); // Unless the two are modifying the same line. } } // For boundary case, we only break if that function is one line function. if (I->lastline > scope.begin || (I->lastline == scope.begin && I->lastline == I->linenumber)) break; I++; } if (I == E) return NULL; // // | f1 | Cases of scope: // f1.lastline -> |_______| (1) (2) (3) (4) (5) // + + ^ ^ ^ // + GAP + | | | // + + v | | // f2.linenumber-> --------- | | // | | v ^ ^ | // | f2 | | | | // f2.lastline -> |_______| v | | // + + | | // ... v v // // Case (1) if (I->linenumber > scope.end || (I->linenumber == scope.end && I->lastline > I->linenumber)) return NULL; if (I->lastline < scope.end) { // Case (4), (5) scope.begin = I->lastline + 1; // adjust beginning to next multiple = true; } multiple = false; return I->function; }
errstat sp_commit() { struct sp_table *st; struct sp_save *firstmod; objnum obj; errstat err; /* When we get an error writing to the (probably local) bulletsvr, * we can do nothing but panic(). We cannot abort the transaction * because the other members will (presumably?) not have this problem * and hence have accepted the modification. */ /* First see if we have multiple modifications as a result of the last * command. (This may happen as a result of sp_install()). * If so, we must use the intentions module rather than the modlist module * in order to guarantee atomicity. */ st = sp_first_update(); firstmod = (st != NULL) ? st->st_dir->sd_mods : NULL; if ((firstmod != NULL && firstmod->ss_next == NULL) /* just 1 mod */ && (st->st_dir->sd_update == NULL) /* just 1 dir */) { obj = st - _sp_table; assert(sp_in_use(st)); if (st->st_flags & SF_DESTROYING) { MON_EVENT("destroying dir"); (void) remove_dir(obj); } else { /* Note: we don't increase the current seqno of the directory * itself, but use as the new seqnr the (already incremented) * *global* sequence number. * This avoids the possibility of having different incarnations * of the same directory at the same time. */ get_global_seqno(&st->st_dir->sd_seq_no); err = ml_store(obj); if (err != STD_OK && err != STD_NOSPACE) { /* Command not handled by modlist module, or no space in the * modlist itself, or not enough memory. */ if (!ml_in_use()) { /* Try to modify it, when possible and efficient. * Otherwise write it out as a whole. */ err = write_new_dir(obj, 1); } else { /* Write it as a whole and remove it from the mod list */ err = ml_write_dir(obj); } } switch (err) { case STD_OK: sp_free_mods(st); break; case STD_NOSPACE: /* The directory would become to big. This error should be * consistent to all members, because they have the same * data and use the same buffer sizes. */ scream("dir %ld would become too big", (long) obj); sp_abort(); /* undoes the modification */ return err; default: /* must panic; see above */ panic("sp_commit: cannot write dir %ld (%s)", (long) obj, err_why(err)); } } } else { /* There are multiple updates or no updates at all */ capability curcaps[NBULLETS]; capability newcaps[NBULLETS]; capability filesvrs[NBULLETS]; struct sp_table *next_st; int nintents, avail; /* First make sure we have room for all of the intentions. */ avail = intent_avail(); nintents = 0; for (st = sp_first_update(); st != NULL; st = sp_next_update()) { nintents++; } if (nintents > avail) { scream("too many intentions: %d (max %d)", nintents, avail); MON_EVENT("too many intentions"); sp_abort(); return STD_NOSPACE; } fsvr_get_svrs(filesvrs, NBULLETS); for (st = sp_first_update(); st != NULL; st = next_st ) { next_st = sp_next_update(); obj = st - _sp_table; /* Add an updated version of this dir to the intentions list. * All dirs for which we have modifications should be in memory: */ assert(sp_in_use(st)); assert(in_cache(obj)); /* Note: all directories modified in as a result of the current * modification get the same seqno! */ get_global_seqno(&st->st_dir->sd_seq_no); if (!ml_in_use()) { /* Try to modify it, when possible and efficient. * Otherwise write it out as a whole. */ get_dir_caps(obj, curcaps); err = dirf_modify(obj, NBULLETS, curcaps, newcaps, filesvrs); } else { err = dirf_write(obj, NBULLETS, newcaps, filesvrs); } switch (err) { case STD_OK: /* Put the new cap(s) in the intentions list. Don't install * them in the supertable yet: that'll be done after we have * written the intention. It'll also give us the opportunity * to destroy the old versions afterwards. */ intent_add(obj, newcaps); MON_EVENT("added intention"); break; case STD_NOSPACE: /* The directory would become to big. This error should be * consistent to all members, because they have the same * data and use the same buffer sizes. * Remove the intentions and let the transaction fail. */ intent_undo(); scream("dir %ld would become too big", (long) obj); sp_abort(); /* undoes the modifications */ return err; default: /* must panic; see above */ panic("sp_commit: cannot write dir %ld (%s)", (long) obj, err_why(err)); } } if (nintents > 0) { /* Write the intentions created to disk */ super_store_intents(); /* Install the modified directories in the super table and remove * the intention again. If we happen to crash between storing the * intention and executing it, we'll complete it the next time * during recovery. */ intent_make_permanent(); MON_EVENT("executed intention"); } } sp_clear_updates(); sp_end(); return STD_OK; }