/* Print out just the variable that is modified */ void FastTcpAgent::traceVar(TracedVar* v) { double curtime; Scheduler& s = Scheduler::instance(); char wrk[500]; int n; curtime = &s ? s.clock() : 0; if (!strcmp(v->name(), "avgRTT_") || !strcmp(v->name(), "baseRTT_") || !strcmp(v->name(), "mi_threshold_") ) sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %-6.3f", curtime, addr(), port(), daddr(), dport(), v->name(), double(*((TracedDouble*) v))); else if (!strcmp(v->name(), "avg_cwnd_last_RTT_") || !strcmp(v->name(), "alpha_") || !strcmp(v->name(), "beta_") || !strcmp(v->name(), "high_accuracy_cwnd_" ) ) sprintf(wrk,"%-8.5f %-2d %-2d %-2d %-2d %s %d", curtime, addr(), port(), daddr(), dport(), v->name(), int(*((TracedInt*) v))); else { TcpAgent::traceVar(v); return; } n = strlen(wrk); wrk[n] = '\n'; wrk[n+1] = 0; if (channel_) (void)Tcl_Write(channel_, wrk, n+1); wrk[n] = 0; return; }
/* MEMNEED -- Increase topd by incr INT's. Since at present the dictionary * is fixed in size, abort if the dictionary overflows. */ char * memneed ( int incr /* amount of space desired in ints, not bytes */ ) { memel *old; old = daddr (topd); topd += incr; /* Quad alignment is desirable for some architectures. */ if (topd & 1) topd++; if (topd > maxd) cl_error (E_IERR, "dictionary full"); return ((char *)old); }
/* RESTOR -- Restor all global variables for the given task and insure the * integrity of the dictionary and control stack. * Go through the dictionary and properly disgard any packages, ltasks, * pfiles, environments and params that may be above the new topd. * Write out any pfiles that are not just working copies that have been * updated before discarding them. * Don't call error() because in trying to restor to an interactive task * it might call us again and cause an inf. loop. Instead, issue fatal error * which will kill the cl for good. This seems reasonable since we might * as well die if we can't restor back to an interactive state. * N.B. we assume that a pfile's params will either all lie above or all * below tp->t_topd. If this can ever happen, must add a further check * of each pfile below topd and lob off any params above topd. * The way posargset, et al, and call/execnewtask are now, we are safe. */ void restor ( struct task *tp ) { memel *topdp; register struct ltask *ltp; register struct package *pkp; register struct param *pp; register struct pfile *pfp; struct param *last_pp; int n; if (cldebug) { eprintf ("restoring task `%s', tp: %d\n", tp->t_ltp->lt_lname,tp); eprintf (" topd %d/%d\n", topd, tp->t_topd); } topd = tp->t_topd; pc = tp->t_pc; topos = tp->t_topos; basos = tp->t_basos; topcs = tp->t_topcs; curpack = tp->t_curpack; yyin = tp->t_in; parse_state = PARSE_FREE; topdp = daddr (topd); /* Set pachead to first package below new topd. Then lob off any ltasks * all remaining packages might have above topd. It is sufficient to * stop the ltask checks for a given package once find an ltask * below topd since the dictionary always grows upward. * (Recall that since new ltasks are always added at the top of the * dictionary, and pkp->pk_ltp always points to the most recently * added ltask, then the thread moves to lower and lower addrs.) * Thus, work downward and throw out all ltasks until find one below * the new topd. */ for (pkp = reference (package, pachead); pkp; pkp = pkp->pk_npk) if ((memel)pkp < (memel)topdp) { pachead = dereference (pkp); break; } if (pkp == NULL) cl_error (E_FERR, "package list broken"); for (; pkp; pkp = pkp->pk_npk) { for (ltp = pkp->pk_ltp; ltp; ltp = ltp->lt_nlt) if ((memel)ltp < (memel)topdp) { pkp->pk_ltp = ltp; break; } if ((memel)pkp->pk_ltp >= (memel)topdp) /* All ltasks in this package were above topd */ pkp->pk_ltp = NULL; } /* Similarly for pfiles and their params; however, since new params * are always added at the top of the dictionary and linked in at the * END of the list (at pfp->pf_lastpp), the thread off pfp->pf_pp * moves to higher and higher addrs. Thus, we work our way up and * throw out all params above the new topd. Also, close off any open * list files from discarded params along the way, if any. * Also, see if any of the params were P_SET and set PF_UPDATE. * This avoids having to set PF_UPDATE for each assignment when the * is not always easily found. * N.B. hope mode param that some t_modep is using is never disgarded.. * Also, guard against writing out pfiles in background. */ for (pfp = reference (pfile, parhead); pfp; pfp = pfp->pf_npf) { /* Lob off any pfiles above new topd. Go through their * params, updating if necessary and closing any lists. */ if ((memel)pfp < (memel)topdp) { parhead = dereference (pfp); break; } for (pp = pfp->pf_pp; pp != NULL; pp = pp->p_np) { /* Close if list file and enable flushing if P_SET. */ if (pp->p_type & PT_LIST) closelist (pp); if (pp->p_flags & P_SET) pfp->pf_flags |= PF_UPDATE; } if (((pfp->pf_flags & (PF_UPDATE|PF_COPY)) == PF_UPDATE) && !(firstask->t_flags & T_BATCH)) pfileupdate (pfp); } /* Discard any recently added parameters above topd, where the pfile * itself is below topd. This happens when a new parameter is added * to an existing incore pfile, e.g., in a declaration. */ for (; pfp; pfp = pfp->pf_npf) { if ((memel)(pfp->pf_lastpp) < (memel)topdp) continue; /* quick check */ last_pp = NULL; n = 0; for (pp = pfp->pf_pp; pp != NULL; pp = pp->p_np) { if ((memel)pp >= (memel)topdp) { if (cldebug) fprintf (stderr, "chop pfile for task %s at param %s\n", pfp->pf_ltp->lt_lname, last_pp->p_name); if (last_pp) last_pp->p_np = NULL; pfp->pf_lastpp = last_pp; pfp->pf_n = n; break; } else { last_pp = pp; n++; } } } /* Delete any SET environment statements processed since this task * was spawned. If any redefs are uncovered the original values are * reset in all connected subprocesses. */ if (tp->t_envp) c_prenvfree (0, tp->t_envp); /* If the task being restored defined a package, dump all processes * in the process cache spawned since the package was loaded. */ if (tp->t_pno) pr_prunecache (tp->t_pno); }