| 1 | \part{Introduction}
|
|---|
| 2 | \label{part:intro}
|
|---|
| 3 |
|
|---|
| 4 | \chapter{Acknowledgement}
|
|---|
| 5 |
|
|---|
| 6 | The CIVL project is funded by the U.S.\ National Science Foundation
|
|---|
| 7 | under awards CCF-1346769 and CCF-1346756.
|
|---|
| 8 |
|
|---|
| 9 | \chapter{What is CIVL?}
|
|---|
| 10 |
|
|---|
| 11 | \textbf{CIVL} stands for \emph{Concurrency Intermediate Verification
|
|---|
| 12 | Language}. The \emph{CIVL platform} encompasses:
|
|---|
| 13 | \begin{enumerate}
|
|---|
| 14 | \item the programming language \textbf{CIVL-C}, a dialect of C with
|
|---|
| 15 | additional primitives supporting concurrency, specification, and modeling;
|
|---|
| 16 | \item verification and
|
|---|
| 17 | analysis tools, including a symbolic execution-based model checker for
|
|---|
| 18 | checking various properties of, or finding defects in, CIVL-C
|
|---|
| 19 | programs; and
|
|---|
| 20 | \item tools that translate from many commonly used
|
|---|
| 21 | languages/APIs to CIVL-C.
|
|---|
| 22 | \end{enumerate}
|
|---|
| 23 |
|
|---|
| 24 | The CIVL-C language is primarily intended to be an intermediate
|
|---|
| 25 | representation for verification. A C program using
|
|---|
| 26 | MPI~\cite{mpi-forum:2012:mpi30}, CUDA~\cite{cuda-programming-guide},
|
|---|
| 27 | OpenMP~\cite{openmp-standard}, OpenCL~\cite{opencl-standard}, or
|
|---|
| 28 | another API (or even some combination of APIs), will be automatically
|
|---|
| 29 | translated into CIVL-C and then verified. The advantages of such a
|
|---|
| 30 | framework are clear: the developer of a new verification technique
|
|---|
| 31 | could implement it for CIVL-C and then immediately see its impact
|
|---|
| 32 | across a broad range of concurrent programs. Likewise, when a new
|
|---|
| 33 | concurrency API is introduced, one only needs to implement a
|
|---|
| 34 | translator from it to CIVL-C in order to reap the benefits of all the
|
|---|
| 35 | verification tools in the platform. Programmers would have a valuable
|
|---|
| 36 | verification and debugging tool, while API designers could use CIVL as
|
|---|
| 37 | a ``sandbox'' to investigate possible API modifications, additions,
|
|---|
| 38 | and interactions.
|
|---|
| 39 |
|
|---|
| 40 | This manual covers all aspects of the CIVL framework, and is organized in parts
|
|---|
| 41 | as follows:
|
|---|
| 42 | \begin{enumerate}
|
|---|
| 43 | \item this introduction, including ``quick start'' instructions for
|
|---|
| 44 | downloading and installing CIVL and several examples;
|
|---|
| 45 | \item a complete description of the CIVL-C language;
|
|---|
| 46 | \item a formal semantics for the language; and
|
|---|
| 47 | \item a description of the tools in the framework.
|
|---|
| 48 | \end{enumerate}
|
|---|
| 49 |
|
|---|
| 50 | \chapter{Installation and Quick Start}
|
|---|
| 51 |
|
|---|
| 52 | This chapter gives instructions for downloading and installing CIVL,
|
|---|
| 53 | and running the verification tool on an example.
|
|---|
| 54 |
|
|---|
| 55 | \subsection*{Notes}
|
|---|
| 56 |
|
|---|
| 57 | \begin{itemize}
|
|---|
| 58 | \item The instructions say to install three theorem provers. In
|
|---|
| 59 | reality, each of these is optional. CIVL will still work without
|
|---|
| 60 | any theorem provers, but the results will not be very precise, i.e.,
|
|---|
| 61 | it will produce a lot of false warnings. The more provers you
|
|---|
| 62 | install, the more precise the analysis.
|
|---|
| 63 | \end{itemize}
|
|---|
| 64 |
|
|---|
| 65 | \subsection*{Instructions}
|
|---|
| 66 |
|
|---|
| 67 | \begin{enumerate}
|
|---|
| 68 | \item Install the automated theorem prover CVC3 (if you have not
|
|---|
| 69 | already). The easiest way to do this is to visit
|
|---|
| 70 | \url{http://www.cs.nyu.edu/acsys/cvc3/download.html} and download
|
|---|
| 71 | the latest, optimized build with static library and executable for
|
|---|
| 72 | your OS. Place the executable file \texttt{cvc3} somewhere in your
|
|---|
| 73 | \texttt{PATH}. You can discard everything else. Alternatively, on
|
|---|
| 74 | some linux systems, CVC3 can be installed using the package manager
|
|---|
| 75 | via ``\texttt{sudo apt-get install cvc3}''. This will place
|
|---|
| 76 | \texttt{cvc3} in \texttt{/usr/bin}.
|
|---|
| 77 |
|
|---|
| 78 | \item Install the automated theorem prover CVC4 (if you have not
|
|---|
| 79 | already). The easiest way to do this is to visit
|
|---|
| 80 | \url{http://cvc4.cs.nyu.edu/downloads/} and choose one of the
|
|---|
| 81 | installation approaches. You only need the binary (\texttt{cvc4}),
|
|---|
| 82 | and you must put it in your \texttt{PATH}. Alternatively, on OS X
|
|---|
| 83 | you may install using MacPorts by ``\texttt{sudo port install
|
|---|
| 84 | cvc4}''.
|
|---|
| 85 |
|
|---|
| 86 | \item Install the automated theorem prover Z3 (if you have not
|
|---|
| 87 | already). Follow instructions at
|
|---|
| 88 | \url{http://z3.codeplex.com/SourceControl/latest#README}. Make sure
|
|---|
| 89 | the executable \texttt{z3} is in your path.
|
|---|
| 90 |
|
|---|
| 91 | \item Install a Java 7 SDK if you have not already. Go to
|
|---|
| 92 | \url{http://www.oracle.com/technetwork/java/javase/downloads/} for
|
|---|
| 93 | the latest from Oracle. On linux, you can instead use the package
|
|---|
| 94 | manager: ``\texttt{sudo apt-get install openjdk-7-jdk}''.
|
|---|
| 95 |
|
|---|
| 96 | \item Download and unpack the latest stable release of CIVL from
|
|---|
| 97 | \url{http://vsl.cis.udel.edu/civl}.
|
|---|
| 98 |
|
|---|
| 99 | \item The resulting directory should be named
|
|---|
| 100 | \texttt{CIVL-\textit{tag}} for some string \textit{tag} which
|
|---|
| 101 | identifies the version of CIVL you downloaded. Move this directory
|
|---|
| 102 | wherever you like.
|
|---|
| 103 |
|
|---|
| 104 | \item The JAR file in the \texttt{lib} directory is all you need to
|
|---|
| 105 | run CIVL. You may move this JAR file wherever you want. You run
|
|---|
| 106 | CIVL by typing a command of the form ``\texttt{java -jar
|
|---|
| 107 | /path/to/civl-TAG.jar ...}''. For convenience, you may instead
|
|---|
| 108 | use the shell script \texttt{civl} included in the \texttt{bin}
|
|---|
| 109 | directory. This allows you to replace ``\texttt{java -jar
|
|---|
| 110 | /path/to/civl-TAG.jar}'' with just ``\texttt{civl}'' on the
|
|---|
| 111 | command line. Simply edit the \texttt{civl} script to reflect the
|
|---|
| 112 | path to the JAR file and place the script somewhere in your
|
|---|
| 113 | \texttt{PATH}. Alternatively, you can define an alias in your
|
|---|
| 114 | \texttt{.profile}, \verb!.bash_profile!, \texttt{.bashrc}, or
|
|---|
| 115 | equivalent, such as
|
|---|
| 116 | \begin{verbatim}
|
|---|
| 117 | alias civl='java -jar /path/to/civl-TAG.jar'
|
|---|
| 118 | \end{verbatim}
|
|---|
| 119 | In the following, we will assume that you have defined a command
|
|---|
| 120 | \texttt{civl} in one of these ways.
|
|---|
| 121 |
|
|---|
| 122 | \item From the command line, type ``\texttt{civl help}''. You should see
|
|---|
| 123 | a help message describing the command line syntax.
|
|---|
| 124 |
|
|---|
| 125 | \item From the command line, type ``\texttt{civl config}''. This should
|
|---|
| 126 | report that \texttt{cvc3}, \texttt{cvc4}, and \texttt{z3} were
|
|---|
| 127 | found, and it should create a file called \texttt{.sarl} in your
|
|---|
| 128 | home directory.
|
|---|
| 129 |
|
|---|
| 130 | \end{enumerate}
|
|---|
| 131 |
|
|---|
| 132 | To test your installation, copy the file
|
|---|
| 133 | \texttt{examples/concurrency/locksBad.cvl} to your working directory.
|
|---|
| 134 | Look at the program: it is a simple 2-process program with two shared
|
|---|
| 135 | variables used as locks. The two processes try to obtain the locks in
|
|---|
| 136 | opposite order, which can lead to a deadlock if both processes obtain
|
|---|
| 137 | their first lock before either obtains the second. Type
|
|---|
| 138 | ``\verb!civl verify locksBad.cvl!''. You should see some output
|
|---|
| 139 | culminating in a message
|
|---|
| 140 | \begin{verbatim}
|
|---|
| 141 | The program MAY NOT be correct. See CIVLREP/locksBad_log.txt
|
|---|
| 142 | \end{verbatim}
|
|---|
| 143 |
|
|---|
| 144 | Type ``\verb!civl replay locksBad.cvl!''. You should see a
|
|---|
| 145 | step-by-step account of how the program arrived at the deadlock.
|
|---|
| 146 |
|
|---|
| 147 |
|
|---|
| 148 | \chapter{Examples}
|
|---|
| 149 |
|
|---|
| 150 | In this section we show a few simple CIVL-C programs which illustrate
|
|---|
| 151 | some of the pertinent features of the language. We also show the results
|
|---|
| 152 | of running some of the tools on them.
|
|---|
| 153 |
|
|---|
| 154 | \section{Dining Philosophers}
|
|---|
| 155 |
|
|---|
| 156 | Dijkstra's well-known Dining Philosophers system can be encoded in
|
|---|
| 157 | CIVL-C as shown in Figure \ref{fig:dining}.
|
|---|
| 158 |
|
|---|
| 159 | \begin{figure}[t]
|
|---|
| 160 | \begin{small}
|
|---|
| 161 | \begin{verbatim}
|
|---|
| 162 | #include <civlc.h>
|
|---|
| 163 |
|
|---|
| 164 | $input int B; // upper bound on number of philosophers
|
|---|
| 165 | $input int n; // number of philosophers
|
|---|
| 166 | $assume 2<=n && n<=B;
|
|---|
| 167 | _Bool forks[n]; // Each fork will be on the table (0) or in a hand (1).
|
|---|
| 168 |
|
|---|
| 169 | void dine(int id) {
|
|---|
| 170 | int left = id;
|
|---|
| 171 | int right = (id + 1) % n;
|
|---|
| 172 |
|
|---|
| 173 | while (1) {
|
|---|
| 174 | $when (forks[left] == 0) forks[left] = 1;
|
|---|
| 175 | $when (forks[right] == 0) forks[right] = 1;
|
|---|
| 176 | forks[right] = 0;
|
|---|
| 177 | forks[left] = 0;
|
|---|
| 178 | }
|
|---|
| 179 | }
|
|---|
| 180 |
|
|---|
| 181 | void main() {
|
|---|
| 182 | for (int i = 0; i < n; i++) forks[i] = 0;
|
|---|
| 183 | for (int i = 0; i < n; i++) $spawn dine(i);
|
|---|
| 184 | }
|
|---|
| 185 | \end{verbatim}
|
|---|
| 186 | \end{small}
|
|---|
| 187 | \caption{\texttt{diningBad.cvl}: CIVL-C encoding of Dijkstra's Dining Philosophers}
|
|---|
| 188 | \label{fig:dining}
|
|---|
| 189 | \end{figure}
|
|---|
| 190 |
|
|---|
| 191 | In this encoding, an upper bound \ct{B} is placed on the number of
|
|---|
| 192 | philosophers \ct{n}. When verifying this program, a concrete value
|
|---|
| 193 | will be specified for \ct{B}. Hence the result of verification will
|
|---|
| 194 | apply to all \ct{n} between $2$ and \ct{B}, inclusive.
|
|---|
| 195 |
|
|---|
| 196 | Both \ct{B} and \ct{n} are delcared as \emph{input} variables using
|
|---|
| 197 | the type qualifier \cinput. An input variable may be
|
|---|
| 198 | initialized with any valid value of its type. In contrast, non-input
|
|---|
| 199 | variables declared in file scope will be initialized with a
|
|---|
| 200 | special \emph{undefined} value; if such a variable is read before it
|
|---|
| 201 | is defined, an error will be reported. In addition, any input variable
|
|---|
| 202 | may have a concrete initial value specified on the command line. In
|
|---|
| 203 | this case, we will specify a concrete value for \ct{B} on the command
|
|---|
| 204 | line but leave \ct{n} unconstrained.
|
|---|
| 205 |
|
|---|
| 206 | An $\cassume$ statement restricts the set of executions of the program
|
|---|
| 207 | to include only those traces in which the assumptions hold. In
|
|---|
| 208 | contrast with an $\cassert$ statement, CIVL does not check that the
|
|---|
| 209 | assumed expression holds, and will not generate an error message if it
|
|---|
| 210 | fails to hold. Thus an $\cassume$ statement allows the programmer to
|
|---|
| 211 | say to CIVL ``assume that this is true,'' while an $\cassert$
|
|---|
| 212 | statement allows the programmer to say to CIVL ``check that this is
|
|---|
| 213 | true.''
|
|---|
| 214 |
|
|---|
| 215 | A $\cwhen$ statement encodes a \emph{guarded command}. The $\cwhen$
|
|---|
| 216 | statement includes a boolean expression called the \emph{guard} and a
|
|---|
| 217 | statement body. The $\cwhen$ statement is enabled if and only if the
|
|---|
| 218 | \emph{guard} evaluates to \emph{true}, in which case the body may be
|
|---|
| 219 | executed. The first atomic statement in the body executes atomically
|
|---|
| 220 | with the evaluation of the guard, so it is guaranteed that the guard
|
|---|
| 221 | will hold when this initial sub-statement executes. Since assignment
|
|---|
| 222 | statements are atomic in CIVL, in this example the bodiy of each
|
|---|
| 223 | $\cwhen$ statement executes atomically with the guard evaluation.
|
|---|
| 224 |
|
|---|
| 225 | The $\cspawn$ statement is very similar to a function call. The main
|
|---|
| 226 | difference is that the function called is invoked in a new process
|
|---|
| 227 | which runs concurrently with the existing processes. The $\cspawn$
|
|---|
| 228 | statement itself returns immediately.
|
|---|
| 229 |
|
|---|
| 230 | The program may be verified for an upper bound of $5$ by typing the
|
|---|
| 231 | following at the command line:
|
|---|
| 232 | \begin{verbatim}
|
|---|
| 233 | civl verify -inputB=5 diningBad.cvl
|
|---|
| 234 | \end{verbatim}
|
|---|
| 235 |
|
|---|
| 236 | The output indicates that a deadlock has been found and a
|
|---|
| 237 | counterexample has been produced and saved. We can examine the
|
|---|
| 238 | counterexample, but it is more helpful to work with a \emph{minimal}
|
|---|
| 239 | counterexample, i.e., a deadlocking trace of minimal length. To find a
|
|---|
| 240 | minimal counterexample, we issue the command
|
|---|
| 241 |
|
|---|
| 242 | \begin{verbatim}
|
|---|
| 243 | civl verify -inputB=5 -min diningBad.cvl
|
|---|
| 244 | \end{verbatim}
|
|---|
| 245 |
|
|---|
| 246 | \begin{figure}[t]
|
|---|
| 247 | \begin{small}
|
|---|
| 248 | \begin{verbatim}
|
|---|
| 249 | CIVL v0.15 of 2014-12-23 -- http://vsl.cis.udel.edu/civl
|
|---|
| 250 | Error 0 encountered at depth 129:
|
|---|
| 251 | ...
|
|---|
| 252 | Error 25 encountered at depth 16:
|
|---|
| 253 | CIVL execution error (kind: DEADLOCK, certainty: PROVEABLE)
|
|---|
| 254 | A deadlock is possible:
|
|---|
| 255 | Path condition: true
|
|---|
| 256 | Enabling predicate: false
|
|---|
| 257 | ProcessState 0: terminated
|
|---|
| 258 | ProcessState 1: at location 26, f0:21.30-42 "forks[right]"
|
|---|
| 259 | Enabling predicate: false
|
|---|
| 260 | ProcessState 2: at location 26, f0:21.30-42 "forks[right]"
|
|---|
| 261 | Enabling predicate: false
|
|---|
| 262 | at f0:21.30-42 "forks[right]".
|
|---|
| 263 | State 664
|
|---|
| 264 | | Path condition
|
|---|
| 265 | | | true
|
|---|
| 266 | | Dynamic scopes
|
|---|
| 267 | | | dyscope 0 (parent=-1, static=0)
|
|---|
| 268 | | | | reachers = {1,2}
|
|---|
| 269 | | | | variables
|
|---|
| 270 | | | | | __atomic_lock_var = process<-1>
|
|---|
| 271 | | | | | B = 5
|
|---|
| 272 | | | | | n = 2
|
|---|
| 273 | | | | | forks = X_s0v4[0:=1, 1:=1]
|
|---|
| 274 | ...
|
|---|
| 275 | | Process states
|
|---|
| 276 | ...
|
|---|
| 277 | | | process 2
|
|---|
| 278 | | | | atomicCount = 0
|
|---|
| 279 | | | | call stack
|
|---|
| 280 | | | | | Frame[function=dine, location=25, f0:21.30-42 "forks[right]", scope=3]
|
|---|
| 281 | ...
|
|---|
| 282 | =================== Stats ===================
|
|---|
| 283 | validCalls : 15327
|
|---|
| 284 | proverCalls : 17
|
|---|
| 285 | memory (bytes) : 18554880
|
|---|
| 286 | time (s) : 2.17
|
|---|
| 287 | maxProcs : 6
|
|---|
| 288 | statesInstantiated : 9264
|
|---|
| 289 | statesSaved : 665
|
|---|
| 290 | statesSeen : 1758
|
|---|
| 291 | statesMatched : 1177
|
|---|
| 292 | steps : 2993
|
|---|
| 293 | transitions : 2934
|
|---|
| 294 |
|
|---|
| 295 | The program MAY NOT be correct. See CIVLREP/diningBad_log.txt
|
|---|
| 296 | \end{verbatim}
|
|---|
| 297 | \end{small}
|
|---|
| 298 | \caption{Output from \texttt{civl verify -inputB=5 -min diningBad.cvl}}
|
|---|
| 299 | \label{fig:diningOut}
|
|---|
| 300 | \end{figure}
|
|---|
| 301 |
|
|---|
| 302 | The result of this command is shown in Figure \ref{fig:diningOut}. The
|
|---|
| 303 | output indicates that a minimal counterexample has length 19, i.e.,
|
|---|
| 304 | involves 20 states and 19 transitions (the depth of 20 is one more
|
|---|
| 305 | than 19). It was the 26th and shortest trace found. It was deemed
|
|---|
| 306 | equivalent to the earlier traces and hence the earlier ones were
|
|---|
| 307 | discarded and only this one saved. We can replay the trace with the command
|
|---|
| 308 | \begin{verbatim}
|
|---|
| 309 | civl replay diningBad.cvl
|
|---|
| 310 | \end{verbatim}
|
|---|
| 311 |
|
|---|
| 312 | \begin{figure}
|
|---|
| 313 | \begin{small}
|
|---|
| 314 | \begin{verbatim}
|
|---|
| 315 | ...
|
|---|
| 316 | Transition 1: State 0, proc 0:
|
|---|
| 317 | 0->1: B = 5 at f0:9.0-12 "$input int B";
|
|---|
| 318 | 1->2: n = InitialValue(n) at f0:10.0-12 "$input int n";
|
|---|
| 319 | 2->3: $assume ((2<=n)&&(n<=B)) at f0:11.0-20 "$assume 2<=n && n ... B";
|
|---|
| 320 | 3->5: forks = InitialValue(forks) at f0:13.0-12 "int forks[n]";
|
|---|
| 321 | 5->6: i = 0 at f0:28.7-16 "int i = 0";
|
|---|
| 322 | --> State 1
|
|---|
| 323 |
|
|---|
| 324 | Transition 2: State 1, proc 0:
|
|---|
| 325 | 6->8: LOOP_TRUE_BRANCH at f0:28.18-23 "i < n";
|
|---|
| 326 | --> State 2
|
|---|
| 327 |
|
|---|
| 328 | ...
|
|---|
| 329 |
|
|---|
| 330 | Transition 12: State 12, proc 2:
|
|---|
| 331 | 18->19: left = id at f0:16.2-15 "int left = id";
|
|---|
| 332 | 19->20: right = ((id+1)%n) at f0:17.2-26 "int right = (id ... n";
|
|---|
| 333 | --> State 13
|
|---|
| 334 |
|
|---|
| 335 | Transition 13: State 13, proc 2:
|
|---|
| 336 | 20->23: LOOP_TRUE_BRANCH at f0:19.9-10 "1";
|
|---|
| 337 | --> State 14
|
|---|
| 338 |
|
|---|
| 339 | Transition 14: State 14, proc 1:
|
|---|
| 340 | 23->25: forks[left] = 1 at f0:20.29-44 "forks[left] = 1";
|
|---|
| 341 | --> State 15
|
|---|
| 342 |
|
|---|
| 343 | Transition 15: State 15, proc 2:
|
|---|
| 344 | 23->25: forks[left] = 1 at f0:20.29-44 "forks[left] = 1";
|
|---|
| 345 | --> State 16
|
|---|
| 346 | ...
|
|---|
| 347 | Violation of Deadlock found in State 16:
|
|---|
| 348 | A deadlock is possible:
|
|---|
| 349 | Path condition: true
|
|---|
| 350 | Enabling predicate: false
|
|---|
| 351 | ProcessState 0: terminated
|
|---|
| 352 | ProcessState 1: at location 25, f0:21.30-42 "forks[right]"
|
|---|
| 353 | Enabling predicate: false
|
|---|
| 354 | ProcessState 2: at location 25, f0:21.30-42 "forks[right]"
|
|---|
| 355 | Enabling predicate: false
|
|---|
| 356 |
|
|---|
| 357 | Trace ends after 15 transitions.
|
|---|
| 358 | Violation(s) found.
|
|---|
| 359 | ...
|
|---|
| 360 | \end{verbatim}
|
|---|
| 361 | \end{small}
|
|---|
| 362 | \caption{Output from \texttt{civl replay diningBad.cvl}}
|
|---|
| 363 | \label{fig:diningReplay}
|
|---|
| 364 | \end{figure}
|
|---|
| 365 |
|
|---|
| 366 | The result of this command is shown in Figure \ref{fig:diningReplay}.
|
|---|
| 367 | The output indicates that a deadlock has been found involving 2
|
|---|
| 368 | philosophers. The trace has 15 transitions; after the initialization
|
|---|
| 369 | sequence, each philosopher picks up her left fork.
|
|---|
| 370 |
|
|---|
| 371 | \section{A Multithreaded MPI Example}
|
|---|
| 372 |
|
|---|
| 373 | \begin{figure}[t]
|
|---|
| 374 | \begin{small}
|
|---|
| 375 | \begin{verbatim}
|
|---|
| 376 | #include<civlc.h>
|
|---|
| 377 | #define TAG 0
|
|---|
| 378 | #define NPROCS 2
|
|---|
| 379 | #define NTHREADS 2
|
|---|
| 380 |
|
|---|
| 381 | $gcomm gcomm = $gcomm_create($here, NPROCS);
|
|---|
| 382 |
|
|---|
| 383 | void MPI_Process (int rank) {
|
|---|
| 384 | $comm comm = $comm_create($here, gcomm, rank);
|
|---|
| 385 | $proc threads[NTHREADS];
|
|---|
| 386 |
|
|---|
| 387 | void Thread(int tid) {
|
|---|
| 388 | int x = rank;
|
|---|
| 389 | $message in, out = $message_pack(rank, 1-rank, TAG, &x, sizeof(int));
|
|---|
| 390 |
|
|---|
| 391 | for (int j=0; j<2; j++) {
|
|---|
| 392 | if (rank == 1) {
|
|---|
| 393 | for (int i=0; i<2; i++) $comm_enqueue(comm, out);
|
|---|
| 394 | for (int i=0; i<2; i++) in = $comm_dequeue(comm, 1-rank, TAG);
|
|---|
| 395 | } else {
|
|---|
| 396 | for (int i=0; i<2; i++) in = $comm_dequeue(comm, 1-rank, TAG);
|
|---|
| 397 | for (int i=0; i<2; i++) $comm_enqueue(comm, out);
|
|---|
| 398 | }
|
|---|
| 399 | }
|
|---|
| 400 | }
|
|---|
| 401 |
|
|---|
| 402 | for (int i=0; i<NTHREADS; i++) threads[i] = $spawn Thread(i);
|
|---|
| 403 | for (int i=0; i<NTHREADS; i++) $wait(threads[i]);
|
|---|
| 404 | $comm_destroy(comm);
|
|---|
| 405 | }
|
|---|
| 406 |
|
|---|
| 407 | void main() {
|
|---|
| 408 | $proc procs[NPROCS];
|
|---|
| 409 |
|
|---|
| 410 | for (int i=0; i<NPROCS; i++) procs[i] = $spawn MPI_Process(i);
|
|---|
| 411 | for (int i=0; i<NPROCS; i++) $wait(procs[i]);
|
|---|
| 412 | $gcomm_destroy(gcomm);
|
|---|
| 413 | }
|
|---|
| 414 | \end{verbatim}
|
|---|
| 415 | \end{small}
|
|---|
| 416 | \caption{\texttt{mpi-pthreads.cvl}: CIVL-C model of a (defective)
|
|---|
| 417 | multithreaded MPI program.}
|
|---|
| 418 | \label{fig:mpithreads}
|
|---|
| 419 | \end{figure}
|
|---|
| 420 |
|
|---|
| 421 | Figure \ref{fig:mpithreads} is an example of a CIVL-C model of
|
|---|
| 422 | multithreaded MPI program. The program consists of two processes,
|
|---|
| 423 | each of which spawns two threads. All four threads issue
|
|---|
| 424 | message-passing operations.
|
|---|
| 425 |
|
|---|
| 426 | This example illustrates some of the message-passing primitives
|
|---|
| 427 | provided in CIVL-C. A \emph{global communicator} object is allocated
|
|---|
| 428 | in the root scope. The constant $\chere$ has type $\cscope$ and
|
|---|
| 429 | refers to the scope in which the expression occurs; in this case it is
|
|---|
| 430 | the root (i.e., file) scope. This global communicator is declared to
|
|---|
| 431 | have \texttt{NPROCS} \emph{places}; these are points from which
|
|---|
| 432 | messages can be sent or received. The function \verb!MPI_Process! is
|
|---|
| 433 | used to model an MPI process. Each instance will create its own
|
|---|
| 434 | \emph{local communicator} object which specifies the global
|
|---|
| 435 | communicator and a place; this is the object that will be used to send
|
|---|
| 436 | or receive messages at that place.
|
|---|
| 437 |
|
|---|
| 438 | Each process spawns two instances of function \texttt{Thread}. Each
|
|---|
| 439 | thread creates a message object from a buffer, specifying the source
|
|---|
| 440 | and destination places, tag, pointer to the beginning of the buffer,
|
|---|
| 441 | and the size of the buffer. The message is \emph{enqueued} into the
|
|---|
| 442 | communication universe using the local communicator. Similarly,
|
|---|
| 443 | messages are dequeued by specifying the local communicator, source
|
|---|
| 444 | place, and tag.
|
|---|
| 445 |
|
|---|
| 446 | The program has a subtle defect, which only manifests on very specific
|
|---|
| 447 | interleavings of the threads. This defect can be found using
|
|---|
| 448 | \texttt{civl verify}.
|
|---|
| 449 |
|
|---|
| 450 |
|
|---|