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