source: CIVL/examples/verifyThis/treeBarrier.cvl

main
Last change on this file was ea777aa, checked in by Alex Wilton <awilton@…>, 3 years ago

Moved examples, include, build_default.properties, common.xml, and README out from dev.civl.com into the root of the repo.

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@5704 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 5.4 KB
RevLine 
[9266093]1/* VerifyThis 2016 - Challenge 3: Static Tree Barriers
2 * https://docs.google.com/document/d/1OvS5b7qXW-xXW1M36JTmSsrc7sjBV-Ni0IO6bKX7yfk/edit
3 *
4 * Consider a multi-threaded program execution. In each state with N threads,
5 * we assume we have given a binary tree with N nodes. Each node corresponds
6 * to exactly one thread. In the context of this challenge, we do not
7 * consider thread creation and termination; the number of nodes and their
8 * position in the tree is assumed to be immutable. Each node has references
9 * to at most two children, and each node except for the root has a reference
10 * to its parent. Moreover, each node stores a boolean value sense and an
11 * integer version.
12 * The tree described above represents a tree barrier that can be used for
13 * thread synchronization.
14 * Synchronization is performed in two phases. In the synchronization phase,
15 * each thread that calls barrier() on its node waits until all threads have
16 * called barrier. The sense field is used to propagate information about
17 * waiting threads up in the tree. When all threads have called barrier(),
18 * the propagation reaches the root of the tree and initiates the wake-up
19 * phase, which proceeds top-down.
20 * Assume a state in which sense is false and version is zero in all nodes.
21 * Assume further that no thread is currently executing barrier() and that
22 * threads invoke barrier() only on their nodes. The number of threads (and,
23 * thus, the number of nodes in the tree) is constant, but unknown.
24 *
25 * Tasks. Prove that:
26 * (1) the following invariant holds in all states:
27 * If n.sense is true for any node n then m.sense is true for all nodes
28 * m in the subtree rooted in n.
29 * (2) for any call n.barrier(), if the call terminates then there was a
30 * state during the execution of the method where all nodes had the
31 * same version.
32 *
33 * This solution only verifies Task (2).
[22b4ef04]34 */
35#include <civlc.cvh>
36#include <stdlib.h>
37#include <stdbool.h>
38#include <stdio.h>
39
40// the number of nodes... (tried with N=1,2,3)
41$input int N = 3; // N=4 took 115 seconds
42
43typedef struct _node {
44 $proc p;
45 struct _node *left, *right;
46 struct _node *parent;
47 _Bool sense;
48 int version;
49} *Node;
50
51Node theNodes[N];
52int count = 0;
53
54// check all sensens in u and descendants are true...
55void checkSensesTrue(Node u) {
56 if (u != NULL) {
57 $assert(u->sense);
58 checkSensesTrue(u->left);
59 checkSensesTrue(u->right);
60 }
61}
62
63// the function a thread runs...
64void thread(Node myNode) {
65
66 // the barrier function
67 void barrier() {
68 $assert(!myNode->sense);
69
70 // synchronization phase
71 if (myNode->left != NULL)
72 $when (myNode->left->sense);
73 if (myNode->right != NULL)
74 $when (myNode->right->sense);
75
76 $atomic {
77 myNode->sense = true;
78 checkSensesTrue(myNode);
79 myNode->version++;
80 if (myNode->parent == NULL) {
81 for (int i=0; i<N; i++)
82 $assert(theNodes[i]->version == myNode->version);
83 }
84 }
85
86
87 // wake-up phase
88 if (myNode->parent == NULL) {
89 myNode->sense = false;
90 }
91
92 $when (!myNode->sense);
93 if (myNode->left != NULL)
94 myNode->left->sense = false;
95 if (myNode->right != NULL)
96 myNode->right->sense = false;
97
98 $assert(!myNode->sense);
99 }
100
101 //myNode->p = $self;
102 // run around barrier 3 times...
103 for (int i=0; i<3; i++) {
104 barrier();
105 }
106}
107
108
109Node makeTree(Node left, Node right) {
110 Node result = (Node)malloc(sizeof(struct _node));
111
112 result->left = left;
113 result->right = right;
114 result->sense = false;
115 result->version = 0;
116 if (left != NULL)
117 left->parent = result;
118 if (right != NULL)
119 right->parent = result;
120 result->parent = NULL;
121 return result;
122}
123
124
125// create an arbitrary tree with numNodes nodes...
126Node makeArbitraryTree(int numNodes) {
127 printf("Entering makeArbitraryTree: numNodes = %d\n", numNodes);
128 if (numNodes == 0)
129 return NULL;
130
131 // how many nodes in left sub-tree?
132 // nondeterministically choose integer in range 0..numNodes-1.
133 // total number of nodes = leftSize + rightSize + 1
134
135 int leftSize = $choose_int(numNodes);
136
137 printf("leftSize = %d\n", leftSize);
138 $assert(leftSize >= 0);
139 $assert(leftSize < numNodes);
140
141 int rightSize = numNodes - (leftSize + 1);
142
143 printf("rightSize = %d\n", rightSize);
144 printf("numNodes = %d\n", numNodes);
145 printf("\n");
146
147 Node leftTree = makeArbitraryTree(leftSize);
148 Node rightTree = makeArbitraryTree(numNodes - leftSize - 1);
149 Node result = makeTree(leftTree, rightTree);
150
151 theNodes[count] = result;
152 count++;
153 return result;
154}
155
156// compute number of nodes in tree...
157int sizeOfTree(Node tree) {
158 if (tree == NULL)
159 return 0;
160
161 int result = 1 + sizeOfTree(tree->left) + sizeOfTree(tree->right);
162
163 return result;
164}
165
166// free all nodes in the tree...
167void freeTree(Node tree) {
168 if (tree != NULL) {
169 freeTree(tree->left);
170 freeTree(tree->right);
171 free(tree);
172 }
173}
174
175
176int main() {
177 Node theTree = makeArbitraryTree(N);
178
179 $atomic {
180 // sanity check...
181 $assert(sizeOfTree(theTree) == N);
182 $assert(count == N);
183 for (int i=0; i<N; i++)
184 $assert(theNodes[i] != NULL);
185 for (int i=0; i<N; i++) {
186 $proc p = $spawn thread(theNodes[i]);
187
188 theNodes[i]->p = p;
189 }
190 }
191 // now the procs are running, wait for them all to terminate...
192 for (int i=0; i<N; i++)
193 $wait(theNodes[i]->p);
194 freeTree(theTree);
195}
Note: See TracBrowser for help on using the repository browser.