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