1 #ifndef _EXECUTIONGRAPH_H
2 #define _EXECUTIONGRAPH_H
7 #include "specannotation.h"
9 #include "modeltypes.h"
12 #include "execution.h"
14 #include "methodcall.h"
15 #include "specannotation.h"
18 const int SELF_CYCLE = 0xfffe;
21 Record the a potential commit point information, including the potential
22 commit point label number and the corresponding operation
24 typedef struct PotentialOP {
25 ModelAction *operation;
28 PotentialOP(ModelAction *op, CSTR name);
36 typedef SnapList<PotentialOP*> PotentialOPList;
39 This represents the execution graph at the method call level. Each node is a
40 MethodCall type that has the runtime info (return value & arguments) and the
41 state info the method call. The edges in this graph are the hb/SC edges
42 dereived from the ordering points of the method call. Those edges
43 information are stoed in the PREV and NEXT set of MethodCall struct.
45 class ExecutionGraph {
47 ExecutionGraph(ModelExecution *e, bool allowCyclic);
49 /********** Public class interface for the core checking engine **********/
51 Build the graph for an execution. It should returns true when the graph
54 void buildGraph(action_list_t *actions);
56 /** Check whether this is a broken execution */
59 /** Check whether this is an execution that has method calls without
61 bool isNoOrderingPoint();
64 Check whether this is a cyclic execution graph, meaning that the graph
65 has an cycle derived from the ordering points' hb/SC relation
69 /** Reset the internal graph "broken" state to okay again */
72 /** Check whether the execution is admmisible */
73 bool checkAdmissibility();
75 /** Checking cyclic graph specification */
76 bool checkCyclicGraphSpec(bool verbose);
78 /** Check whether a number of random history is correct */
79 bool checkRandomHistories(int num = 1, bool stopOnFail = true, bool verbose = false);
81 /** Check whether all histories are correct */
82 bool checkAllHistories(bool stopOnFailure = true, bool verbose = false);
84 /********** A few public printing functions for DEBUGGING **********/
87 Print out the ordering points and dynamic calling info (return value &
88 arguments) of all the methods in the methodList
90 void printAllMethodInfo(bool verbose);
92 /** Print a random sorting */
93 void printOneHistory(MethodList *list, CSTR header = "A random history");
95 /** Print all the possible sortings */
96 void printAllHistories(MethodListVector *sortings);
98 /** Print out the graph for the purpose of debugging */
99 void print(bool allEdges = false);
102 Print out the graph in reverse order (with previous edges) for the
105 void PrintReverse(bool allEdges);
110 /** The corresponding execution */
111 ModelExecution *execution;
113 /** All the threads each in a separate list of actions */
114 SnapVector<action_list_t*> *threadLists;
116 /** A plain list of all method calls (Method) in this execution */
117 MethodList *methodList;
120 A list that represents some random history. The reason we have this here
121 is that before checking anything, we have to check graph acyclicity, and
122 that requires us to check whether we can generate a topological sorting.
123 Therefore, when we check it, we store that random result here.
125 MethodList *randomHistory;
127 /** Whether this is a broken graph */
130 /** Whether this graph has method calls that have no ordering points */
131 bool noOrderingPoint;
133 /** Whether there is a cycle in the graph */
136 /** Whether users expect us to check cyclic graph */
140 /** The state initialization function */
141 NamedFunction *initial;
143 /** FIXME: The final check function; we might delete this */
144 NamedFunction *final;
146 /** The state copy function */
149 /** The state clear function */
150 NamedFunction *clear;
152 /** The state print-out function */
153 NamedFunction *printState;
155 /** The map from interface label name to the set of spec functions */
156 StateFuncMap *funcMap;
158 /** The commutativity rule array and its size */
159 CommutativityRule *commuteRules;
162 /********** Internal member functions **********/
165 Simply build a vector of lists of thread actions. Such info will be very
166 useful for later constructing the execution graph
168 void buildThreadLists(action_list_t *actions);
170 /** Build the nodes from a thread list */
171 void buildNodesFromThread(action_list_t *actions);
173 /** Build the nodes from all the thread lists */
174 void buildNodesFromThreads();
178 Find the previous non-annotation model action (ordering point from the
181 ModelAction* findPrevAction(action_list_t *actions, action_list_t::iterator
185 Extract a MethodCall node starting from the current iterator, and the
186 iter iterator will be advanced to the next INTERFACE_BEGIN annotation.
187 When called, the iter must point to an INTERFACE_BEGIN annotation
189 Method extractMethod(action_list_t *actions, action_list_t::iterator &iter);
192 Process the initialization annotation block to initialize the
193 commutativity rule info and the checking function info
195 void processInitAnnotation(AnnoInit *annoInit);
198 A utility function to extract the actual annotation
199 pointer and return the actual annotation if this is an annotation action;
200 otherwise return NULL.
202 SpecAnnotation* getAnnotation(ModelAction *act);
205 After building up the graph (both the nodes and egdes are correctly
206 built), we also call this function to initialize the most recent
207 justified node of each method node.
209 A justified method node of a method m is a method that is in the allPrev
210 set of m, and all other nodes in the allPrev set of m are either before
211 or after it. The most recent justified node is the most recent one in
214 void initializeJustifiedNode();
217 After extracting the MethodCall info for each method call, we use this
218 function to build the edges (a few different sets of edges that
219 represent the edge of the execution graph (PREV, NEXT & CONCURRENT...)
224 This method call is used to check whether the edge sets of the nodes are
225 built correctly --- consistently. We should only use this routine after the
226 builiding of edges when debugging
231 The conflicting relation between two model actions by hb/SC. If act1 and
232 act2 commutes, it returns 0; Otherwise, if act1->act2, it returns 1; and
233 if act2->act1, it returns -1
235 int conflict(ModelAction *act1, ModelAction *act2);
238 If there is no conflict between the ordering points of m1 and m2, then
239 it returns 0; Otherwise, if m1->m2, it returns 1; and if m2->m1, it
240 returns -1. If some ordering points have inconsistent conflicting
241 relation, we print out an error message (Self-cycle) and set the broken
244 int conflict(Method m1, Method m2);
247 Check whether m1 is before m2 in hb/SC; Reachability <=> m1 -hb/SC-> m2.
248 We need to call this method when checking admissibility properties
250 bool isReachable(Method m1, Method m2);
253 Find the list of nodes that do not have any incoming edges (root nodes).
254 Be careful that when generating histories, this function will also
255 consider whether a method node logicall exists.
257 MethodVector* getRootNodes();
260 Find the list of nodes that do not have any outgoing edges (end nodes)
262 MethodVector* getEndNodes();
265 A helper function for generating and check all sequential histories. Before calling this function, initialize an empty
266 MethodList , and pass it as curList. Also pass the size of the method
267 list as the numLiveNodes.
269 If you only want to stop the checking process when finding one failed
270 history, pass true to stopOnFailure.
272 bool checkAllHistoriesHelper(MethodList *curList, int &numLiveNodes, int
273 &historyNum, bool stopOnFailure, bool verbose);
276 /** Check whether a specific history is correct */
277 bool checkHistory(MethodList *history, int historyIndex, bool verbose = false);
279 /** Generate one random topological sorting */
280 MethodList* generateOneRandomHistory();
283 The helper function to generate one random topological sorting
285 void generateOneRandomHistoryHelper(MethodList
286 *curList, int &numLiveNodes);
288 /** Return the fake nodes -- START & END */
289 Method getStartMethod();
290 Method getFinishMethod();
292 /** Whether method call node m is a fake node */
293 inline bool isFakeMethod(Method m) {
294 return isStartMethod(m) || isFinishMethod(m);
297 /** Whether method call node m is a starting node */
298 inline bool isStartMethod(Method m) {
299 return m->name == GRAPH_START;
302 /** Whether method call node m is a finish node */
303 inline bool isFinishMethod(Method m) {
304 return m->name == GRAPH_FINISH;
308 Print out the ordering points and dynamic calling info (return value &
311 void printMethodInfo(Method m, bool verbose);
313 /** Clear the states of the method call */
317 Check the state specifications (PreCondition & PostCondition & state
318 transition and evaluation) based on the graph (called after
319 admissibility check). The verbose option controls whether we print a
320 detailed list of checking functions that we have called
322 bool checkStateSpec(MethodList *history, bool verbose, int historyNum);
325 Check the justifying subhistory with respect to history of m.
327 bool checkJustifyingSubhistory(MethodList *subhistory, Method cur,
328 bool verbose, int historyIndex);
330 /** Print a problematic thread list */
331 void printActions(action_list_t *actions, const char *header = "The problematic thread list:");
333 /** Print one jusifying subhistory of method call cur */
334 void printOneSubhistory(MethodList *history, Method cur,