/** * @file depend.c * \brief interface for graph code from the viewpoint of events. * */ #include "depend.h" #include "term.h" #include "system.h" #include "binding.h" #include "warshall.h" #include "debug.h" #include "error.h" /* * Generic structures * --------------------------------------------------------------- */ //! Event dependency structure struct depeventgraph { //! Flag denoting what it was made for (newrun|newbinding) int fornewrun; //! Number of runs; int runs; //! System where it derives from System sys; //! Number of nodes int n; //! Rowsize int rowsize; //! Graph structure unsigned int *G; //! Zombie dummy push int zombie; //! Previous graph struct depeventgraph *prev; }; //! Pointer shorthard typedef struct depeventgraph *Depeventgraph; /* * Globals * --------------------------------------------------------------- */ Depeventgraph currentdepgraph; /* * Default code * --------------------------------------------------------------- */ //! Default init void dependInit (const System sys) { currentdepgraph = NULL; } //! Pring void dependPrint () { Depeventgraph dg; eprintf ("Printing DependEvent stack, top first.\n\n"); for (dg = currentdepgraph; dg != NULL; dg = dg->prev) { eprintf ("%i nodes, %i rowsize, %i zombies, %i runs: created for new ", dg->n, dg->rowsize, dg->zombie, dg->runs); if (dg->fornewrun) { eprintf ("run"); } else { eprintf ("binding"); } eprintf ("\n"); } eprintf ("\n"); #ifdef DEBUG { int n1; int r1; int o1; r1 = 0; o1 = 0; eprintf ("Printing dependency graph.\n"); for (n1 = 0; n1 < nodeCount (); n1++) { int n2; int r2; int o2; if ((n1 - o1) >= currentdepgraph->sys->runs[r1].rolelength) { o1 += currentdepgraph->sys->runs[r1].rolelength; r1++; eprintf ("\n"); } r2 = 0; o2 = 0; eprintf ("%5i : ", n1); for (n2 = 0; n2 < nodeCount (); n2++) { if ((n2 - o2) >= currentdepgraph->sys->runs[r2].rolelength) { o2 += currentdepgraph->sys->runs[r2].rolelength; r2++; eprintf (" "); } eprintf ("%i", getNode (n1, n2)); } eprintf ("\n"); } eprintf ("\n"); } #endif } //! Default cleanup void dependDone (const System sys) { if (currentdepgraph != NULL) { globalError++; eprintf ("\n\n"); dependPrint (); globalError--; error ("depgraph stack (depend.c) not empty at dependDone, bad iteration?"); } } /* * Libs * --------------------------------------------------------------- */ //! Convert from event to node in a graph (given that sys is set) int eventtonode (const Depeventgraph dgx, const int r, const int e) { int i; int n; n = 0; for (i = 0; i < dgx->sys->maxruns; i++) { if (i == r) { // this run #ifdef DEBUG if (dgx->sys->runs[i].rolelength <= e) { error ("Bad offset for eventtonode"); } #endif return (n + e); } else { // not this run, add offset n += dgx->sys->runs[i].rolelength; } } error ("Bad offset (run number too high?) for eventtonode"); return 0; } //! Return the number of nodes in a graph int countnodes (const Depeventgraph dgx) { int i; int nodes; nodes = 0; for (i = 0; i < dgx->sys->maxruns; i++) { nodes += dgx->sys->runs[i].rolelength; } return nodes; } //! Graph size given the number of nodes unsigned int getGraphSize (const Depeventgraph dgx) { return (dgx->n * dgx->rowsize); } //! Create graph from sys Depeventgraph dependCreate (const System sys) { Depeventgraph dgnew; dgnew = (Depeventgraph) MALLOC (sizeof (struct depeventgraph)); dgnew->sys = sys; dgnew->fornewrun = true; dgnew->runs = sys->maxruns; dgnew->zombie = 0; dgnew->prev = NULL; dgnew->n = countnodes (dgnew); // count nodes works on ->sys dgnew->rowsize = WORDSIZE (dgnew->n); dgnew->G = (unsigned int *) CALLOC (1, getGraphSize (dgnew) * sizeof (unsigned int)); // works on ->n and ->rowsize return dgnew; } //! Copy graph from current one Depeventgraph dependCopy (const Depeventgraph dgold) { Depeventgraph dgnew; // Copy old to new dgnew = (Depeventgraph) MALLOC (sizeof (struct depeventgraph)); memcpy ((void *) dgnew, (void *) dgold, (size_t) sizeof (struct depeventgraph)); // New copy dgnew->fornewrun = false; dgnew->zombie = 0; // copy inner graph dgnew->G = (unsigned int *) MALLOC (getGraphSize (dgold) * sizeof (unsigned int)); memcpy ((void *) dgnew->G, (void *) dgold->G, getGraphSize (dgold) * sizeof (unsigned int)); return dgnew; } //! Destroy graph void dependDestroy (const Depeventgraph dgold) { FREE (dgold->G); FREE (dgold); } //! push graph to stack (generic) void dependPushGeneric (Depeventgraph dgnew) { dgnew->prev = currentdepgraph; currentdepgraph = dgnew; } //! restore graph from stack (generic) void dependPopGeneric (void) { Depeventgraph dgprev; dgprev = currentdepgraph->prev; dependDestroy (currentdepgraph); currentdepgraph = dgprev; } //! Construct graph dependencies from sys /** * uses currentdepgraph->sys */ void dependFromSys (void) { int r; List bl; // There are two types of orderings. // 1. Role orderings (within runs) for (r = 0; r < currentdepgraph->sys->maxruns; r++) { int e; for (e = 1; e < currentdepgraph->sys->runs[r].rolelength; e++) { setDependEvent (r, e - 1, r, e); } } // 2. Binding orderings // We implicitly assume these cause no cycles (by construction this is // correct) for (bl = currentdepgraph->sys->bindings; bl != NULL; bl = bl->next) { Binding b; b = (Binding) bl->data; if (valid_binding (b)) { int r1, e1, r2, e2; r1 = b->run_from; e1 = b->ev_from; r2 = b->run_to; e2 = b->ev_to; if (!((r1 == r2) && (e1 == e2))) { // Not a self-binding setDependEvent (r1, e1, r2, e2); } } } } //! Detect whether the graph has a cycle. If so, a node can get to itself (through the cycle) int hasCycle () { int n; for (n = 0; n < currentdepgraph->n; n++) { if (getNode (n, n)) { return true; } } return false; } /* * Public Code * --------------------------------------------------------------- */ //! get node int getNode (const int n1, const int n2) { return BIT (currentdepgraph->G + currentdepgraph->rowsize * n1, n2); } //! set node void setNode (const int n1, const int n2) { SETBIT (currentdepgraph->G + currentdepgraph->rowsize * n1, n2); } //! Count nodes int nodeCount (void) { return countnodes (currentdepgraph); } /* * Simple setting */ void setDependEvent (const int r1, const int e1, const int r2, const int e2) { int n1, n2; n1 = eventtonode (currentdepgraph, r1, e1); n2 = eventtonode (currentdepgraph, r2, e2); setNode (n1, n2); } /* * Simple testing */ int isDependEvent (const int r1, const int e1, const int r2, const int e2) { int n1, n2; n1 = eventtonode (currentdepgraph, r1, e1); n2 = eventtonode (currentdepgraph, r2, e2); return getNode (n1, n2); } //! create new graph after adding runs or events (new number of nodes) void dependPushRun (const System sys) { dependPushGeneric (dependCreate (sys)); dependFromSys (); } //! restore graph to state after previous run add void dependPopRun (void) { if (!currentdepgraph->fornewrun) { globalError++; dependPrint (); globalError--; error ("Trying to pop graph created for new binding."); } dependPopGeneric (); } //! create new graph by adding event bindings /* * The push code returns true or false: if false, the operation fails because * it there is now a cycle in the graph, and there is no need to pop the * result. */ int dependPushEvent (const int r1, const int e1, const int r2, const int e2) { if (isDependEvent (r2, e2, r1, e1)) { // Adding would imply a cycle, so we won't do that. #ifdef DEBUG if (DEBUGL (3)) { eprintf ("Cycle detected for binding %i,%i -> %i,%i.\n", r1, e1, r2, e2); } if (DEBUGL (5)) { dependPrint (); } #endif return false; } else { // No immediate cycle: new graph, return true TODO disabled if ((1 == 0) && ((r1 == r2) && (e1 == e2)) || isDependEvent (r1, e1, r2, e2)) { // if n->n or the binding already existed, no changes // no change: add zombie currentdepgraph->zombie += 1; } else { // change: make new graph copy of the old one dependPushGeneric (dependCopy (currentdepgraph)); // add new binding setDependEvent (r1, e1, r2, e2); // recompute closure transitive_closure (currentdepgraph->G, currentdepgraph->n); // check for cycles if (hasCycle ()) { //warning ("Cycle slipped undetected by the reverse check."); // Closure introduced cycle, undo it dependPopEvent (); return false; } } return true; } } //! restore graph to state before previous binding add void dependPopEvent (void) { if (currentdepgraph->fornewrun) { globalError++; dependPrint (); globalError--; error ("Trying to pop graph created for new run."); } if (currentdepgraph->zombie > 0) { // zombie pushed currentdepgraph->zombie -= 1; } else { // real graph dependPopGeneric (); } } //! Current event to node int eventNode (const int r, const int e) { return eventtonode (currentdepgraph, r, e); }