| 1 | % LaTeX source for CIVL Reference Manual.
|
|---|
| 2 | %
|
|---|
| 3 | \documentclass[11pt]{book}
|
|---|
| 4 | \usepackage{amsmath}
|
|---|
| 5 | \usepackage{amsthm}
|
|---|
| 6 | \usepackage{xcolor}
|
|---|
| 7 | \usepackage{bbold}
|
|---|
| 8 | \usepackage{url}
|
|---|
| 9 | \usepackage[lined,vlined,linesnumbered,noresetcount]{algorithm2e}
|
|---|
| 10 |
|
|---|
| 11 | \include{preambular}
|
|---|
| 12 |
|
|---|
| 13 | \title{{\huge\bf CIVL}\\\mbox{The Concurrency Intermediate Verification
|
|---|
| 14 | Language}\\Reference Manual\\ v0.4}
|
|---|
| 15 | \author{%
|
|---|
| 16 | Matthew B.\ Dwyer \and
|
|---|
| 17 | Ganesh Gopalakrishnan \and
|
|---|
| 18 | Zvonimir Rakamaric \and
|
|---|
| 19 | Stephen F.\ Siegel \and
|
|---|
| 20 | Manchun Zheng \and
|
|---|
| 21 | Timothy K.\ Zirkel
|
|---|
| 22 | }
|
|---|
| 23 |
|
|---|
| 24 | \begin{document}
|
|---|
| 25 | \maketitle
|
|---|
| 26 | \tableofcontents
|
|---|
| 27 |
|
|---|
| 28 | \chapter{Quick Start}
|
|---|
| 29 |
|
|---|
| 30 | \begin{enumerate}
|
|---|
| 31 | \item Download and unpack the appropriate pre-compiled library of CIVL
|
|---|
| 32 | dependencies from \url{http://vsl.cis.udel.edu/tools/vsl_depend/}.
|
|---|
| 33 | There are versions for Darwin (OS X), 32-bit linux, and 64-bit
|
|---|
| 34 | linux.
|
|---|
| 35 | \item Move the resulting directory \texttt{vsl} to \texttt{/opt/vsl}.
|
|---|
| 36 | \item Download and unpack the latest stable release of CIVL from
|
|---|
| 37 | \url{http://vsl.cis.udel.edu/civl}. Again there are versions
|
|---|
| 38 | for Darwin, 32-bit linux, and 64-bit linux.
|
|---|
| 39 | \item The resulting directory should be named
|
|---|
| 40 | \texttt{CIVL-\textit{tag}} for some string \textit{tag} which
|
|---|
| 41 | identifies the version of CIVL you downloaded. Move this directory
|
|---|
| 42 | into \texttt{/opt}.
|
|---|
| 43 | \item You should now have an executable script
|
|---|
| 44 | \texttt{/opt/CIVL-\textit{tag}/bin/civl}. Move this script into
|
|---|
| 45 | your path, or create a symlink from somewhere in your path to it, or
|
|---|
| 46 | add the directory \texttt{/opt/CIVL-\textit{tag}/bin} to your path.
|
|---|
| 47 | \end{enumerate}
|
|---|
| 48 |
|
|---|
| 49 | From the command line, you should now be able to type \texttt{civl
|
|---|
| 50 | help} and see a help message describing the command line syntax.
|
|---|
| 51 |
|
|---|
| 52 | Copy the file
|
|---|
| 53 | \texttt{CIVL-\textit{tag}/examples/concurrency/locksBad.cvl} to your
|
|---|
| 54 | working directory. Look at the program: it is a simple 2-process
|
|---|
| 55 | program with two shared variables used as locks. The 2 processes try
|
|---|
| 56 | to obtain the locks in opposite order, leading to a deadlock.
|
|---|
| 57 |
|
|---|
| 58 | Type
|
|---|
| 59 | \begin{verbatim}
|
|---|
| 60 | civl verify locksBad.cvl
|
|---|
| 61 | \end{verbatim}
|
|---|
| 62 | You should see some output culminating in a message
|
|---|
| 63 | \begin{verbatim}
|
|---|
| 64 | The program MAY NOT be correct. See CIVLREP/locksBad_log.txt
|
|---|
| 65 | \end{verbatim}
|
|---|
| 66 |
|
|---|
| 67 | Type
|
|---|
| 68 | \begin{verbatim}
|
|---|
| 69 | civl replay locksBad.cvl
|
|---|
| 70 | \end{verbatim}
|
|---|
| 71 | You should see a step-by-step account of how the program arrived
|
|---|
| 72 | at the deadlock.
|
|---|
| 73 |
|
|---|
| 74 | \textbf{Note.} You can install \texttt{CIVL-\textit{tag}} and
|
|---|
| 75 | \texttt{vsl} in any directory you want, not just in \texttt{/opt}.
|
|---|
| 76 | You just need to edit the script file \texttt{civl} appropriately,
|
|---|
| 77 | replacing the default paths with the new paths.
|
|---|
| 78 |
|
|---|
| 79 | \part{Language}
|
|---|
| 80 |
|
|---|
| 81 | \chapter{Overview of CIVL-C}
|
|---|
| 82 |
|
|---|
| 83 | % write a grammar. Leave out type qualifiers, etc. Keep pointers.
|
|---|
| 84 | % Keep simple types? Why not keep all the standard types.
|
|---|
| 85 | % How about "symbolic types"? Make all the casts explicit.
|
|---|
| 86 | % Look at CIL?
|
|---|
| 87 |
|
|---|
| 88 | % Describe as subset of C, but leave out:... and add...
|
|---|
| 89 |
|
|---|
| 90 | % add Set<proc> and use it.
|
|---|
| 91 |
|
|---|
| 92 | \section{CIVL-C concepts and primitives}
|
|---|
| 93 |
|
|---|
| 94 | CIVL-C is a programming language. It is an extension of a subset of
|
|---|
| 95 | the C11 dialect of C. It does not include the standard C library.
|
|---|
| 96 |
|
|---|
| 97 | A CIVL-C program should begin with the line
|
|---|
| 98 | \begin{verbatim}
|
|---|
| 99 | #include <civlc.h>
|
|---|
| 100 | \end{verbatim}
|
|---|
| 101 | which includes the main CIVL-C header file, which declares all the
|
|---|
| 102 | types and other CIVL primitives. Almost all of the CIVL-C primitives
|
|---|
| 103 | which are not already in C begin with the symbol \texttt{\$} to easily
|
|---|
| 104 | distinguish them from any reserved work or identifier in a C program.
|
|---|
| 105 |
|
|---|
| 106 | A CIVL-C program encodes a CIVL model for a particular CIVL
|
|---|
| 107 | context. The types are essentially the C types with the additional
|
|---|
| 108 | process reference type (denoted \cproc). The expressions are C
|
|---|
| 109 | expressions with some additional expressions defined below.
|
|---|
| 110 |
|
|---|
| 111 | In CIVL-C, functions can be defined in any scope, not just in file
|
|---|
| 112 | scope. The lexical scope structure and placement of function
|
|---|
| 113 | definitions determine the static scope tree $\Sigma$ and the function
|
|---|
| 114 | prototype system. A function's defining scope is, as you would
|
|---|
| 115 | expect, the scope in which its definition occurs.
|
|---|
| 116 |
|
|---|
| 117 | The CIVL-C code will not have an explicit ``root'' procedure.
|
|---|
| 118 | Instead, a root procedure will be implicitly wrapped around the entire
|
|---|
| 119 | code. The global input variables will become the inputs to the root
|
|---|
| 120 | procedure. A ``\texttt{main}'' procedure must be delcared that takes
|
|---|
| 121 | no parameters but can have any return type. The body of \texttt{main}
|
|---|
| 122 | becomes the body of the root procedure. The return type of
|
|---|
| 123 | \texttt{main} becomes the return type of the root procedure. The
|
|---|
| 124 | \texttt{main} procedure itself disappears in translation.
|
|---|
| 125 |
|
|---|
| 126 | The reason for this protocol is that an arbitrary (sequential) C program
|
|---|
| 127 | is a legal (and reasonable) CIVL-C program. The global variables in the
|
|---|
| 128 | C program simply become variables declared in the root scope.
|
|---|
| 129 |
|
|---|
| 130 | The additional language elements are shown in Figure \ref{fig:cc}.
|
|---|
| 131 |
|
|---|
| 132 | \begin{figure}
|
|---|
| 133 | \begin{tabular}{ll}
|
|---|
| 134 | \cproc & the process type \\
|
|---|
| 135 | \cself & the evaluating process (constant of type \cproc) \\
|
|---|
| 136 | \cinput & type qualifier declaring variable to be a program input \\
|
|---|
| 137 | \coutput & type qualifier declaring variable to be a program output \\
|
|---|
| 138 | \cspawn & create a new process running procedure \\
|
|---|
| 139 | \cwait & wait for a process to terminate \\
|
|---|
| 140 | \cassert & check something holds \\
|
|---|
| 141 | \ctrue & boolean value true, used in assertions \\
|
|---|
| 142 | \cfalse & boolean value false, used in assertions \\
|
|---|
| 143 | \cassume & assume something holds \\
|
|---|
| 144 | \cwhen & guarded statement \\
|
|---|
| 145 | \cchoose & nondeterministic choice statement \\
|
|---|
| 146 | \cchooseint & nondeterministic choice of integer \\
|
|---|
| 147 | \cinvariant & declare a loop invariant \\
|
|---|
| 148 | \crequires & procedure precondition \\
|
|---|
| 149 | \censures & procedure postcondition \\
|
|---|
| 150 | \cresult & refers to result returned by procedure in contracts \\
|
|---|
| 151 | \cat & refer to variable in other process, e.g., \texttt{p@x} \\
|
|---|
| 152 | \ccollective & a collective expression\\
|
|---|
| 153 | \cheap & the heap type \\
|
|---|
| 154 | \cscope & the scope type, used to give a name to a scope \\
|
|---|
| 155 | \cmalloc & malloc function with additional heap arguments \\
|
|---|
| 156 | \texttt{*<...>} & scope-qualified pointer type
|
|---|
| 157 | \end{tabular}
|
|---|
| 158 | \caption{CIVL-C primitives. Some of these are part of the grammar of the language;
|
|---|
| 159 | others are defined in the header file \texttt{civlc.h}.}
|
|---|
| 160 | \label{fig:cc}
|
|---|
| 161 | \end{figure}
|
|---|
| 162 |
|
|---|
| 163 |
|
|---|
| 164 |
|
|---|
| 165 | \section{Detailed descriptions of primitives}
|
|---|
| 166 |
|
|---|
| 167 | \subsection{\cproc} This is a primitive object type and functions like
|
|---|
| 168 | any other primitive C type (e.g., \texttt{int}). An object of this
|
|---|
| 169 | type refers to a process. It can be thought of as a process ID, but
|
|---|
| 170 | it is not an integer and cannot be cast to one. Certain expressions
|
|---|
| 171 | take an argument of \cproc{} type and some return something of
|
|---|
| 172 | \cproc{} type.
|
|---|
| 173 |
|
|---|
| 174 | \subsection{\cself} This is a constant of type \cproc. It can be used
|
|---|
| 175 | wherever an argument of type \cproc{} is called for. It refers to the
|
|---|
| 176 | process that is evaluating the expression containing ``\cself''.
|
|---|
| 177 |
|
|---|
| 178 | \subsection{\cinput} A variable in the root scope only may be declared
|
|---|
| 179 | with this type modifier indicating it is an ``input'' variable, as in
|
|---|
| 180 | \begin{verbatim}
|
|---|
| 181 | $input int n;
|
|---|
| 182 | \end{verbatim}
|
|---|
| 183 | As explained above, the variable becomes a parameter to the root
|
|---|
| 184 | procedure. This is used when comparing two programs for functional
|
|---|
| 185 | equivalence. The two programs are functionally equivalent if,
|
|---|
| 186 | whenever they are given the same inputs (i.e., corresponding \cinput{}
|
|---|
| 187 | variables are initialized with the same values) they will produce the
|
|---|
| 188 | same outputs (i.e., corresponding \coutput{} variables will end up
|
|---|
| 189 | with the same values at termination). Input variables can also be
|
|---|
| 190 | assigned a concrete value on the command line.
|
|---|
| 191 |
|
|---|
| 192 | \subsection{\coutput} A variable in the root scope may be declared
|
|---|
| 193 | with this type modifier to declare it to be an output variable.
|
|---|
| 194 |
|
|---|
| 195 | \subsection{\cspawn} This is an expression with side-effects. It
|
|---|
| 196 | spawns a new process and returns a reference to the new process, i.e.,
|
|---|
| 197 | an object of type \cproc. The syntax is the same as a procedure
|
|---|
| 198 | invocation with the keyword ``\cspawn'' inserted in front:
|
|---|
| 199 | \begin{verbatim}
|
|---|
| 200 | $spawn f(expr1, ..., exprn)
|
|---|
| 201 | \end{verbatim}
|
|---|
| 202 | Typically the returned value is assigned to a variable, e.g.,
|
|---|
| 203 | \begin{verbatim}
|
|---|
| 204 | $proc p = $spawn f(i);
|
|---|
| 205 | \end{verbatim}
|
|---|
| 206 | If the invoked function \texttt{f} returns a value, that value is
|
|---|
| 207 | simply ignored.
|
|---|
| 208 |
|
|---|
| 209 | \subsection{\cwait} This is a statement that takes an argument of type
|
|---|
| 210 | \cproc{} and blocks until the referenced process terminates:
|
|---|
| 211 | \begin{verbatim}
|
|---|
| 212 | $wait expr;
|
|---|
| 213 | \end{verbatim}
|
|---|
| 214 |
|
|---|
| 215 | \subsection{\cassert} This is an assertion statement. It takes as its
|
|---|
| 216 | sole argument an expression of boolean type. The expressions have a
|
|---|
| 217 | richer syntax than C expressions. During verification, the assertion
|
|---|
| 218 | is checked. If it does not hold, a violation is reported.
|
|---|
| 219 | \begin{verbatim}
|
|---|
| 220 | $assert expr;
|
|---|
| 221 | \end{verbatim}
|
|---|
| 222 | Boolean values \ctrue{} and \cfalse{} may be used in assertions
|
|---|
| 223 | and assumptions.
|
|---|
| 224 |
|
|---|
| 225 | \subsection{\cassume} This is an assume statement. Its syntax is the
|
|---|
| 226 | same as that of \cassert. During verification, the assumed expression
|
|---|
| 227 | is assumed to hold. If this leads to a contradiction on some
|
|---|
| 228 | execution, that execution is simply ignored. It never reports a
|
|---|
| 229 | violation, it only restricts the set of possible executions that will
|
|---|
| 230 | be explored by the verification algorithm.
|
|---|
| 231 | \begin{verbatim}
|
|---|
| 232 | $assume expr;
|
|---|
| 233 | \end{verbatim}
|
|---|
| 234 |
|
|---|
| 235 | \subsection{\cwhen} This represents a guarded command:
|
|---|
| 236 | \begin{verbatim}
|
|---|
| 237 | $when (expr) stmt;
|
|---|
| 238 | \end{verbatim}
|
|---|
| 239 | All statements have a guard, either implicit or explicit. For most
|
|---|
| 240 | statements, the guard is \ctrue. The \cwhen{} statement allows one to
|
|---|
| 241 | attach an explicit guard to a statement.
|
|---|
| 242 |
|
|---|
| 243 | When \texttt{expr} is \emph{true}, the statement is enabled, otherwise
|
|---|
| 244 | it is disabled. A disabled statement is \emph{blocked}---it will not
|
|---|
| 245 | be scheduled for execution. When it is enabled, it may execute by
|
|---|
| 246 | moving control to the \texttt{stmt} and executing the first atomic
|
|---|
| 247 | action in the \texttt{stmt}.
|
|---|
| 248 |
|
|---|
| 249 | If \texttt{stmt} itself has a non-trivial guard, the guard of the
|
|---|
| 250 | \cwhen{} statement is effectively the conjunction of the \texttt{expr}
|
|---|
| 251 | and the guard of \texttt{stmt}.
|
|---|
| 252 |
|
|---|
| 253 | The evaluation of \texttt{expr} and the first atomic action of
|
|---|
| 254 | \texttt{stmt} effectively occur as a single atomic action. There is
|
|---|
| 255 | no guarantee that execution of \texttt{stmt} will continue atomically
|
|---|
| 256 | if it contains more than one atomic action, i.e., other processes may
|
|---|
| 257 | be scheduled.
|
|---|
| 258 |
|
|---|
| 259 | Examples:
|
|---|
| 260 | \begin{verbatim}
|
|---|
| 261 | $when (s>0) s--;
|
|---|
| 262 | \end{verbatim}
|
|---|
| 263 | This will block until \texttt{s} is positive and then decrement
|
|---|
| 264 | \texttt{s}. The execution of \texttt{s--} is guaranteed to take place
|
|---|
| 265 | in an environment in which \texttt{s} is positive.
|
|---|
| 266 |
|
|---|
| 267 | \begin{verbatim}
|
|---|
| 268 | $when (s>0) {s--; t++}
|
|---|
| 269 | \end{verbatim}
|
|---|
| 270 | The execution of \texttt{s--} must happen when \texttt{s>0}, but
|
|---|
| 271 | between \texttt{s--} and \texttt{t++}, other processes may execute.
|
|---|
| 272 |
|
|---|
| 273 | \begin{verbatim}
|
|---|
| 274 | $when (s>0) $when (t>0) x=y*t;
|
|---|
| 275 | \end{verbatim}
|
|---|
| 276 | This blocks until both \texttt{x} and \texttt{t} are positive then
|
|---|
| 277 | executes the assignment in that state. It is equivalent to
|
|---|
| 278 | \begin{verbatim}
|
|---|
| 279 | $when (s>0 && t>0) x=y*t;
|
|---|
| 280 | \end{verbatim}
|
|---|
| 281 |
|
|---|
| 282 | \subsection{\cchoose} A \cchoose{} statement has the form
|
|---|
| 283 | \begin{verbatim}
|
|---|
| 284 | $choose {
|
|---|
| 285 | stmt1;
|
|---|
| 286 | stmt2;
|
|---|
| 287 | ...
|
|---|
| 288 | default: stmt
|
|---|
| 289 | }
|
|---|
| 290 | \end{verbatim}
|
|---|
| 291 | The \texttt{default} clause is optional.
|
|---|
| 292 |
|
|---|
| 293 | The guards of the statements are evaluated and among those that are
|
|---|
| 294 | \emph{true}, one is chosen nondeterministically and executed. If none
|
|---|
| 295 | are \emph{true} and the \texttt{default} clause is present, it is
|
|---|
| 296 | chosen. The \texttt{default} clause will only be selected if all
|
|---|
| 297 | guards are \emph{false}. If no \texttt{default} clause is present and
|
|---|
| 298 | all guards are \emph{false}, the statement blocks. Hence the implicit
|
|---|
| 299 | guard of the \cchoose{} statement without a \texttt{default} clause is
|
|---|
| 300 | the disjunction of the guards of its sub-statements. The implicit
|
|---|
| 301 | guard of the \cchoose{} statement with a default clause is
|
|---|
| 302 | \emph{true}.
|
|---|
| 303 |
|
|---|
| 304 | Example: this shows how to encode a ``low-level'' CIVL guarded
|
|---|
| 305 | transition system:
|
|---|
| 306 |
|
|---|
| 307 | \begin{verbatim}
|
|---|
| 308 | l1: $choose {
|
|---|
| 309 | $when (x>0) {x--; goto l2;}
|
|---|
| 310 | $when (x==0) {y=1; goto l3;}
|
|---|
| 311 | default: {z=1; goto l4;}
|
|---|
| 312 | }
|
|---|
| 313 | l2: $choose {
|
|---|
| 314 | ...
|
|---|
| 315 | }
|
|---|
| 316 | l3: $choose {
|
|---|
| 317 | ...
|
|---|
| 318 | }
|
|---|
| 319 | \end{verbatim}
|
|---|
| 320 |
|
|---|
| 321 | \subsection{\cchooseint} This is a function with the following prototype:
|
|---|
| 322 | \begin{verbatim}
|
|---|
| 323 | int $choose_int(int n);
|
|---|
| 324 | \end{verbatim}
|
|---|
| 325 | It takes as input a positive integer \texttt{n} and returns an integer
|
|---|
| 326 | in the range $[0,\texttt{n}-1]$.
|
|---|
| 327 |
|
|---|
| 328 | \subsection{\cinvariant} This indicates a loop invariant. Each C loop
|
|---|
| 329 | construct has an optional invariant clause as follows:
|
|---|
| 330 | \begin{verbatim}
|
|---|
| 331 | while (expr) $invariant (expr) stmt
|
|---|
| 332 | for (e1; e2; e3) $invariant (expr) stmt
|
|---|
| 333 | do stmt while (expr) $invariant (expr) ;
|
|---|
| 334 | \end{verbatim}
|
|---|
| 335 | The invariant encodes the claim that if \texttt{expr} holds upon
|
|---|
| 336 | entering the loop and the loop condition holds, then it will hold
|
|---|
| 337 | after completion of execution of the loop body. The invariant is used
|
|---|
| 338 | by certain verification techniques.
|
|---|
| 339 |
|
|---|
| 340 | \emph{Status:} parsed, but nothing is currently done with this
|
|---|
| 341 | information.
|
|---|
| 342 |
|
|---|
| 343 | \subsection{Procedure contracts}
|
|---|
| 344 | The \crequires{} and \censures{} primitives are used to encode
|
|---|
| 345 | procedure contracts. There are optional
|
|---|
| 346 | elements that may occur in a procedure declaration or definition,
|
|---|
| 347 | as follows. For a function prototype:
|
|---|
| 348 | \begin{verbatim}
|
|---|
| 349 | T f(...)
|
|---|
| 350 | $requires expr;
|
|---|
| 351 | $ensures expr;
|
|---|
| 352 | ;
|
|---|
| 353 | \end{verbatim}
|
|---|
| 354 | For a function definition:
|
|---|
| 355 | \begin{verbatim}
|
|---|
| 356 | T f(...)
|
|---|
| 357 | $requires expr;
|
|---|
| 358 | $ensures expr;
|
|---|
| 359 | {
|
|---|
| 360 | ...
|
|---|
| 361 | }
|
|---|
| 362 | \end{verbatim}
|
|---|
| 363 | The value \cresult{} may be used in post-conditions to refer
|
|---|
| 364 | to the result returned by a procedure.
|
|---|
| 365 |
|
|---|
| 366 | \emph{Status}: parsed, but nothing is currently done with this
|
|---|
| 367 | information.
|
|---|
| 368 |
|
|---|
| 369 | \subsection{Remote expressions}. These have the form \verb!expr@x!
|
|---|
| 370 | and refer to a variable in another process, e.g., \verb!procs[i]@x!.
|
|---|
| 371 | This special kind of expression is used in collective expressions,
|
|---|
| 372 | which are used to formulate collective assertions and invariants.
|
|---|
| 373 |
|
|---|
| 374 | The expression \verb!expr! must have \cproc{} type. The variable
|
|---|
| 375 | \texttt{x} must be a statically visible variable in the context in
|
|---|
| 376 | which it is occurs. When this expression is evaluated, the evaluation
|
|---|
| 377 | context will be shifted to the process referred to by \texttt{expr}.
|
|---|
| 378 |
|
|---|
| 379 | \emph{Status}: not implemented.
|
|---|
| 380 |
|
|---|
| 381 | \subsection{Collective expressions}. These have the form
|
|---|
| 382 | \begin{verbatim}
|
|---|
| 383 | $collective(proc_expr, int_expr) expr
|
|---|
| 384 | \end{verbatim}
|
|---|
| 385 | This is a collective expression over a set of processes. The
|
|---|
| 386 | expression \texttt{proc{\U}expr} yields a pointer to the first element
|
|---|
| 387 | of an array of \cproc. The expression \texttt{int{\U}expr} gives the
|
|---|
| 388 | length of that array, i.e., the number of processes. Expression
|
|---|
| 389 | \texttt{expr} is a boolean-valued expression; it may use remote
|
|---|
| 390 | expressions to refer to variables in the processes specified in the
|
|---|
| 391 | array. Example:
|
|---|
| 392 | \begin{verbatim}
|
|---|
| 393 | $proc procs[N];
|
|---|
| 394 | ...
|
|---|
| 395 | $assert $collective(procs, N) i==procs[(pid+1)%N]@i ;
|
|---|
| 396 | \end{verbatim}
|
|---|
| 397 |
|
|---|
| 398 | \emph{Status}: not implemented.
|
|---|
| 399 |
|
|---|
| 400 | \chapter{Pointers and heaps}
|
|---|
| 401 |
|
|---|
| 402 | CIVL-C supports pointers, using the same operators with the same
|
|---|
| 403 | meanings as C (\texttt{\&}, \texttt{*}, pointer arithmetic).
|
|---|
| 404 | As mentioned above, there is also a heap type \cheap{}, which can
|
|---|
| 405 | be used to declare multiple heaps in a CIVL-C program. The
|
|---|
| 406 | interaction between pointers, heaps, and scopes is an important
|
|---|
| 407 | aspect of CIVL-C.
|
|---|
| 408 |
|
|---|
| 409 | \section{Pointer types}
|
|---|
| 410 |
|
|---|
| 411 | Given any object type $T$ and a static scope $s$ in a CIVL-C program,
|
|---|
| 412 | there is a type \emph{pointer-to-$T$-in-$s$}. The type is used to
|
|---|
| 413 | represent a pointer to a memory location of type $T$ in scope $s$ or a
|
|---|
| 414 | descendant of $s$ (i.e., some scope contained in $s$).
|
|---|
| 415 |
|
|---|
| 416 | If scope $s_1$ is a descendant of $s_2$ (i.e., $s_1$ is lexically
|
|---|
| 417 | contained in $s_2$), the type \emph{pointer-to-$T$-in-$s_1$} is a
|
|---|
| 418 | subtype of \emph{pointer-to-$T$-in-$s_2$}. This means that any
|
|---|
| 419 | expression of the first type can be used wherever an object of the
|
|---|
| 420 | second type is expected. In particular, any expression $e$ of the
|
|---|
| 421 | subtype can be assigned to a left-hand-side expression of the
|
|---|
| 422 | supertype without explicit casts; also $e$ can be used as an argument
|
|---|
| 423 | to a function for which the corresponding parameter has the supertype.
|
|---|
| 424 |
|
|---|
| 425 | The syntax for denoting this type adheres to the usual C syntax for
|
|---|
| 426 | denoting the type \emph{pointer-to-$T$} with the addition of a scope
|
|---|
| 427 | parameter within angular brackets immediately following the \texttt{*}
|
|---|
| 428 | token. For example, to declare a variable \texttt{p} of type
|
|---|
| 429 | \emph{pointer-to-$T$-in-$s$}, one writes
|
|---|
| 430 | \begin{verbatim}
|
|---|
| 431 | int *<s> p;
|
|---|
| 432 | \end{verbatim}
|
|---|
| 433 | If the scope modifier \texttt{<...>} is absent, the scope is taken to
|
|---|
| 434 | be the root scope $s_0$. The object has type
|
|---|
| 435 | \emph{pointer-to-$T$-in-$s_0$}, which is abreviated as
|
|---|
| 436 | \emph{pointer-to-$T$}. In this way, stanard C programs can be
|
|---|
| 437 | interpreted as CIVL-C programs.
|
|---|
| 438 |
|
|---|
| 439 | \section{Address-of operator}
|
|---|
| 440 |
|
|---|
| 441 | The address-of operator \texttt{\&} returns a pointer of the
|
|---|
| 442 | appropriate subtype using the innermost scope in which its left-hand-side
|
|---|
| 443 | argument is declared. For example
|
|---|
| 444 |
|
|---|
| 445 | \begin{verbatim}
|
|---|
| 446 | {
|
|---|
| 447 | $scope s1;
|
|---|
| 448 | int x;
|
|---|
| 449 | double a[N];
|
|---|
| 450 | int *<s1> p = &x;
|
|---|
| 451 | double *<s1> q = &a[2];
|
|---|
| 452 | }
|
|---|
| 453 | \end{verbatim}
|
|---|
| 454 | is correct (in particular, it is type-correct) because \texttt{\&x}
|
|---|
| 455 | has type \emph{pointer-to-\texttt{int}-in-\texttt{s1}}, since
|
|---|
| 456 | \texttt{s1} is the scope in which \texttt{x} is declared.
|
|---|
| 457 |
|
|---|
| 458 | \section{Pointer addition and subtractions}
|
|---|
| 459 |
|
|---|
| 460 | If \texttt{e} is an expression of type \emph{pointer-to-$T$-in-$s$}
|
|---|
| 461 | and \texttt{i} is an expression of integer type then \texttt{e+i} also
|
|---|
| 462 | has type \emph{pointer-to-$T$-in-$s$}. In other words, pointer
|
|---|
| 463 | addition cannot leave the scope of the original pointer. This
|
|---|
| 464 | reflects the fact that every object is contained in one scope, and
|
|---|
| 465 | pointer addition cannot leave the object.
|
|---|
| 466 |
|
|---|
| 467 |
|
|---|
| 468 | Pointer subtraction is defined on two pointers of the same type, where
|
|---|
| 469 | ``same'' includes the scope. That is checked statically. As in C, it
|
|---|
| 470 | is only defined if the two pointers point to the same object. In
|
|---|
| 471 | CIVL-C, a runtime error will be thrown if they do not point to the
|
|---|
| 472 | same object.
|
|---|
| 473 |
|
|---|
| 474 | \section{Semantics of scopes and pointer types}
|
|---|
| 475 |
|
|---|
| 476 | A variable of type \cscope{} is treated like any other variable.
|
|---|
| 477 | It becomes part of the state when the scope in which it is declared
|
|---|
| 478 | is instantiated to form a dynamic scope. The variable is
|
|---|
| 479 | initialized at that time and its value cannot change.
|
|---|
| 480 |
|
|---|
| 481 | Each time a dynamic scope is instantiated, it is assigned a unique ID
|
|---|
| 482 | number. The exactly value of the ID number is not relevant, it just
|
|---|
| 483 | has to be distince from any other scope ID number that currently
|
|---|
| 484 | exists in the state. This is the value that is assigned to the scope
|
|---|
| 485 | variable. Therefore, if a static scope contains a scope variable, and
|
|---|
| 486 | that scope is instantiated twice to form two distinct dynamic scopes,
|
|---|
| 487 | the values assigned to the two variables will be distinct.
|
|---|
| 488 |
|
|---|
| 489 | A pointer value is an ordered pair $\langle \delta,r \rangle$, where
|
|---|
| 490 | $\delta$ is a dynamic scope ID and $r$ is a reference to a memory
|
|---|
| 491 | location in the static scope associated to $\delta$. (We will define
|
|---|
| 492 | the exact form of a reference later.)
|
|---|
| 493 |
|
|---|
| 494 | When a dynamic scope is instantiated, each new variable created is
|
|---|
| 495 | assigned a \emph{dynamic type}. This is a refinement of the static
|
|---|
| 496 | type associated to the static variable. Every dynamic type
|
|---|
| 497 | is an instance of exactly one static type. The dynamic
|
|---|
| 498 | type of the newly instantiated variable is an instance of the
|
|---|
| 499 | static type of the static variable.
|
|---|
| 500 |
|
|---|
| 501 | The dynamic pointer types have the form
|
|---|
| 502 | \emph{pointer-to-$t$-in-$\delta$}, where $t$ is a dynamic type and
|
|---|
| 503 | $\delta$ is a dynamic scope ID. For a program to be dynamically type
|
|---|
| 504 | safe, such a variable should hold only values of the form $\langle
|
|---|
| 505 | \delta, r\rangle$. In particular, the variable should never be
|
|---|
| 506 | assigned a value where the dynamic scope component is a different
|
|---|
| 507 | instance of the static scope $s$ associated to $\delta$.
|
|---|
| 508 |
|
|---|
| 509 | \section{Pointer casts}
|
|---|
| 510 |
|
|---|
| 511 | If scope $s_1$ is contained in scope $s_2$, an expression of type
|
|---|
| 512 | \emph{pointer-to-$T$-in-$s_1$} can always be cast to
|
|---|
| 513 | \emph{pointer-to-$T$-in-$s_2$},
|
|---|
| 514 | because the first is a subtype of the second. (As described above,
|
|---|
| 515 | the cast is unnecessary.)
|
|---|
| 516 |
|
|---|
| 517 | The cast in the other direction is also allowed, but the dynamic type
|
|---|
| 518 | safety of that cast will only be checked at runtime. In particular, a
|
|---|
| 519 | runtime error will result if the cast attempts to cast the pointer
|
|---|
| 520 | value to a dynamic scope which does not contain (is an ancestor of)
|
|---|
| 521 | the dynamic scope component of the pointer value.
|
|---|
| 522 |
|
|---|
| 523 | A type \emph{pointer-to-$T_1$-in-$s$} can be cast to a type
|
|---|
| 524 | \emph{pointer-to-$T_2$-in-$s$} according to the usual rules of C. In
|
|---|
| 525 | other words, usual casting rules apply as long as you don't change the
|
|---|
| 526 | scope.
|
|---|
| 527 |
|
|---|
| 528 |
|
|---|
| 529 |
|
|---|
| 530 | \section{Heaps}
|
|---|
| 531 |
|
|---|
| 532 | The standard CIVL-C library defines a type \cheap{} for explicit
|
|---|
| 533 | modeling of a heap. The default value of \cheap{} type is an empty
|
|---|
| 534 | heap, so you only need to declare a variable to have type \cheap{}
|
|---|
| 535 | in order to create a new heap:
|
|---|
| 536 | \begin{verbatim}
|
|---|
| 537 | $heap h; /* a new empty heap */
|
|---|
| 538 | \end{verbatim}
|
|---|
| 539 |
|
|---|
| 540 | The following functions are also defined:
|
|---|
| 541 | \begin{verbatim}
|
|---|
| 542 | void* $malloc($heap *h, int size);
|
|---|
| 543 | void memcpy(void *p, void *q, size_t size);
|
|---|
| 544 | void free(void *p)
|
|---|
| 545 | \end{verbatim}
|
|---|
| 546 | The first function is like C's \texttt{malloc}, except that you
|
|---|
| 547 | specify the heap in which the allocation takes place by passing a
|
|---|
| 548 | pointer to the heap as the first argument. This modifies the
|
|---|
| 549 | specified heap and returns a pointer to the new object. The function
|
|---|
| 550 | can only occur in a context in which the type of the object is
|
|---|
| 551 | specified, as in:
|
|---|
| 552 | \begin{verbatim}
|
|---|
| 553 | $heap h;
|
|---|
| 554 | int n = 10;
|
|---|
| 555 | double *p = (double*)$malloc(&h, n*sizeof(double));
|
|---|
| 556 | \end{verbatim}
|
|---|
| 557 | The second and third functions are exactly the same as in C. Note that
|
|---|
| 558 | \texttt{free} modifies the heap which was used to allocate \texttt{p}.
|
|---|
| 559 |
|
|---|
| 560 | Another pointer example:
|
|---|
| 561 | \begin{verbatim}
|
|---|
| 562 | { $heap h;
|
|---|
| 563 | { $scope s1;
|
|---|
| 564 | double x;
|
|---|
| 565 | { $scope s2;
|
|---|
| 566 | double y;
|
|---|
| 567 | double *<s1> p;
|
|---|
| 568 | /* p can only point to something in s1 or descendant,
|
|---|
| 569 | * for example, s2 */
|
|---|
| 570 | p = &x; // fine
|
|---|
| 571 | p = &y; // fine
|
|---|
| 572 | p = (double*)$malloc(&h,10*sizeof(double)); // static type error
|
|---|
| 573 | }
|
|---|
| 574 | }
|
|---|
| 575 | }
|
|---|
| 576 | \end{verbatim}
|
|---|
| 577 |
|
|---|
| 578 | \emph{Status}: Pointer type, \texttt{\&}, \texttt{*}, pointer addition
|
|---|
| 579 | all implemented. Type \cheap{}, \texttt{malloc}, \texttt{free}
|
|---|
| 580 | implemented. Scope-qualified pointers: parsed, type-checked, but
|
|---|
| 581 | information not currently used.
|
|---|
| 582 |
|
|---|
| 583 | \section{Scope-Parameterized Functions}
|
|---|
| 584 |
|
|---|
| 585 | Coming soon. (Parsed, type checked, not currently used otherwise.)
|
|---|
| 586 |
|
|---|
| 587 | \section{Scope-Parameterized Type Definitions}
|
|---|
| 588 |
|
|---|
| 589 | Coming soon. (Ditto.)
|
|---|
| 590 |
|
|---|
| 591 | \chapter{Some Translation Examples}
|
|---|
| 592 |
|
|---|
| 593 | \section{Structured parallelism}
|
|---|
| 594 | Structured \verb!parbegin!/\verb!parend! statements look like this:
|
|---|
| 595 | \begin{verbatim}
|
|---|
| 596 | $parbegin
|
|---|
| 597 | S1; S2; S2
|
|---|
| 598 | $parend
|
|---|
| 599 | \end{verbatim}
|
|---|
| 600 | (See Dijkstra, Cooperating Sequential Processes.) The meaning is: run
|
|---|
| 601 | the three statements in parallel, and block at the end until all have
|
|---|
| 602 | completed.
|
|---|
| 603 |
|
|---|
| 604 | This can be represented in CIVL-C as follows:
|
|---|
| 605 |
|
|---|
| 606 | \begin{verbatim}
|
|---|
| 607 | {
|
|---|
| 608 | void f_1() {S1}
|
|---|
| 609 | void f_2() {S2}
|
|---|
| 610 | void f_3() {S3}
|
|---|
| 611 | $proc tmp1 = $fork f_1(), tmp2=$fork f_2(), tmp3=$fork f_3();
|
|---|
| 612 | $join(tmp1); $join(tmp2); $join(tmp3);
|
|---|
| 613 | }
|
|---|
| 614 | \end{verbatim}
|
|---|
| 615 |
|
|---|
| 616 | \subsection{Parallel for loops}
|
|---|
| 617 | The standard parallel ``for'' loop looks like
|
|---|
| 618 | \begin{verbatim}
|
|---|
| 619 | $parfor(T i = e; cond; inc) S
|
|---|
| 620 | \end{verbatim}
|
|---|
| 621 | It indicates each iteration should be run concurrently, blocking
|
|---|
| 622 | at end until all complete. In CIVL-C:
|
|---|
| 623 |
|
|---|
| 624 | \begin{verbatim}
|
|---|
| 625 | {
|
|---|
| 626 | void f(T i) {S}
|
|---|
| 627 | T i = e;
|
|---|
| 628 | int c = 0;
|
|---|
| 629 | Vector<$proc> list;
|
|---|
| 630 |
|
|---|
| 631 | while (cond) {
|
|---|
| 632 | list.add($fork f());
|
|---|
| 633 | c++;
|
|---|
| 634 | inc;
|
|---|
| 635 | }
|
|---|
| 636 | for (int j=0; j<c; j++) $join(list.get(j));
|
|---|
| 637 | }
|
|---|
| 638 | \end{verbatim}
|
|---|
| 639 |
|
|---|
| 640 | (This is assuming we have some sort of Vector datatype. Need to think
|
|---|
| 641 | about that.)
|
|---|
| 642 |
|
|---|
| 643 | \subsection{Message Passing}
|
|---|
| 644 |
|
|---|
| 645 | There will be a bunch of standard libraries that can be included
|
|---|
| 646 | into CIVL-C. One of these will be the message-passing library.
|
|---|
| 647 | It will define a bunch of primitives that we will fill in shortly.
|
|---|
| 648 | Among them will be basic send and receive functions.
|
|---|
| 649 |
|
|---|
| 650 | The message-passing library can be defined entirely in CIVL-C.
|
|---|
| 651 | (See Figure \ref{fig:mp1}.)
|
|---|
| 652 |
|
|---|
| 653 | \begin{figure}
|
|---|
| 654 | \begin{verbatim}
|
|---|
| 655 | typedef struct _CIVL_Message {
|
|---|
| 656 | struct _CIVL_Message *next; // next message in this queue
|
|---|
| 657 | struct _CIVL_Message *prev; // previous message in this queue
|
|---|
| 658 | int tag; // message tag
|
|---|
| 659 | int size; // size of buffer
|
|---|
| 660 | void *data; // pointer to first element
|
|---|
| 661 | } *CIVL_Message;
|
|---|
| 662 |
|
|---|
| 663 | typedef struct _CIVL_Comm {
|
|---|
| 664 | $heap heap;
|
|---|
| 665 | int numProcs; // number of procs in this communicator
|
|---|
| 666 | $proc *procs; // array of length numProcs
|
|---|
| 667 | CIVL_Message buf_front[][]; // oldest element of each queue
|
|---|
| 668 | CIVL_Message buf_back[][]; // newest element of each queue
|
|---|
| 669 | } *CIVL_Comm;
|
|---|
| 670 | \end{verbatim}
|
|---|
| 671 | \caption{CIVL Message Passing library: basic definitions}
|
|---|
| 672 | \label{fig:mp1}
|
|---|
| 673 | \end{figure}
|
|---|
| 674 |
|
|---|
| 675 | Message passing functions may be defined with prototypes such as:
|
|---|
| 676 | \begin{verbatim}
|
|---|
| 677 | CIVL_Comm CIVL_Comm_create($proc procs[], int numProcs);
|
|---|
| 678 | void CIVL_send(int src, void *buf, int size, int dest,
|
|---|
| 679 | int tag, CIVL_Comm comm);
|
|---|
| 680 | void CIVL_recv(int dest, void *buf, int size, int src,
|
|---|
| 681 | int tag, CIVL_Comm comm);
|
|---|
| 682 | \end{verbatim}
|
|---|
| 683 |
|
|---|
| 684 | The arguments for \texttt{send} are:
|
|---|
| 685 | \begin{enumerate}
|
|---|
| 686 | \item rank of process issuing the send
|
|---|
| 687 | \item address of buffer containing data to be sent
|
|---|
| 688 | \item size of message
|
|---|
| 689 | \item an integer tag
|
|---|
| 690 | \item rank of destination process
|
|---|
| 691 | \item communicator
|
|---|
| 692 | \end{enumerate}
|
|---|
| 693 |
|
|---|
| 694 | The arguments for \texttt{recv} are:
|
|---|
| 695 | \begin{enumerate}
|
|---|
| 696 | \item rank of process issuing the receive
|
|---|
| 697 | \item address of receive buffer
|
|---|
| 698 | \item size of receive buffer (must be large enough to hold any incoming message)
|
|---|
| 699 | \item rank of source process or \code{CIVL{\U}ANY{\U}SOURCE}
|
|---|
| 700 | \item tag or \code{CIVL{\U}ANY{\U}TAG}
|
|---|
| 701 | \item communicator
|
|---|
| 702 | \end{enumerate}
|
|---|
| 703 |
|
|---|
| 704 | Notice one difference from MPI: we have to specify the process to
|
|---|
| 705 | which the send or receive is associated in the first argument. This is
|
|---|
| 706 | because we need to be more general than MPI. In MPI, that process is
|
|---|
| 707 | always the MPI process invoking the send or receive. In CIVL, you
|
|---|
| 708 | might want to have threads within processes (for example) and
|
|---|
| 709 | associate the message to the MPI process, even though the thread is
|
|---|
| 710 | actually invoking the send. Or you might want to associate it to
|
|---|
| 711 | something else in some other language/library/API.
|
|---|
| 712 |
|
|---|
| 713 | How they are implemented: \texttt{CIVL{\U}Comm{\U}create}
|
|---|
| 714 | mallocs a new object of type \texttt{struct {\U}CIVL{\U}Comm} and returns
|
|---|
| 715 | a pointer to it.
|
|---|
| 716 |
|
|---|
| 717 |
|
|---|
| 718 | \part{Semantics}
|
|---|
| 719 |
|
|---|
| 720 |
|
|---|
| 721 | \section{CIVL Model Syntax}
|
|---|
| 722 |
|
|---|
| 723 | \subsection{Notation and terminology}
|
|---|
| 724 | \label{sec:notation}
|
|---|
| 725 |
|
|---|
| 726 | Let $\B=\{\true,\false\}$ (the set of boolean values). Let
|
|---|
| 727 | $\N=\{0,1,2,\ldots\}$ (the set of natural numbers).
|
|---|
| 728 |
|
|---|
| 729 | Given a node $u$ in a tree, we let $\ancestors(u)$ denote the set of
|
|---|
| 730 | all ancestors of $u$, including $u$. We let $\descendants(u)$ denote
|
|---|
| 731 | the set of all descendants of $u$, including $u$.
|
|---|
| 732 |
|
|---|
| 733 | For any set $S$, let $S^*$ denote the set of all finite sequences of
|
|---|
| 734 | elements of $S$. The length of a sequence $\xi\in S^*$ is denoted
|
|---|
| 735 | $\len(\xi)$.
|
|---|
| 736 |
|
|---|
| 737 | % This is a lie:
|
|---|
| 738 | % The elements of the sequence are indexed from $0$ to
|
|---|
| 739 | % $\len(\xi)-1$.
|
|---|
| 740 |
|
|---|
| 741 | \subsection{Definition of Context}
|
|---|
| 742 | \label{sec:context}
|
|---|
| 743 |
|
|---|
| 744 | \begin{definition}
|
|---|
| 745 | A \emph{CIVL type system} is a tuple comprising the following
|
|---|
| 746 | components:
|
|---|
| 747 | \begin{enumerate}
|
|---|
| 748 | \item a set $\Type$ (the set of \emph{types}),
|
|---|
| 749 | \item a type $\bool\in\Type$ (the \emph{boolean type}),
|
|---|
| 750 | \item a type $\proc\in\Type$ (the \emph{process-reference type}),
|
|---|
| 751 | \item a set $\Var$ (the set of all \emph{typed variables}),
|
|---|
| 752 | \item a function $\vtype\colon \Var\ra\Type$ (which gives the
|
|---|
| 753 | type of each variable),
|
|---|
| 754 | \item a set $\Val$ (the set of all \emph{values}),
|
|---|
| 755 | \item a function which assigns to each $t\in\Type$ a subset
|
|---|
| 756 | $\Val_t\subseteq\Val$ (the set of values of type $t$)
|
|---|
| 757 | and which satisfies $\Val_{\bool}=\B$ and $\Val_{\proc}=\N$,
|
|---|
| 758 | \item a function which assigns to each $t\in\Type$ a value
|
|---|
| 759 | $\default_t\in\Val_t$.
|
|---|
| 760 | \end{enumerate}
|
|---|
| 761 | \end{definition}
|
|---|
| 762 |
|
|---|
| 763 | The default value will be used to give an initial value to any
|
|---|
| 764 | variable. It could represent something like ``an undefined value of
|
|---|
| 765 | type $t$'' or a reasonable initial value ($0$ for integers, etc.),
|
|---|
| 766 | depending on the language one is modeling.
|
|---|
| 767 |
|
|---|
| 768 | \begin{definition}
|
|---|
| 769 | Given a CIVL type system, a \emph{valuation} in that system is a
|
|---|
| 770 | function $\eta\colon\Var\ra\Val$ with the property that for any
|
|---|
| 771 | $v\in\Var$, $\eta(v)\in\Val_{\vtype(v)}$.
|
|---|
| 772 | \end{definition}
|
|---|
| 773 |
|
|---|
| 774 | Given a CIVL type system, we let $\Eval$ denote the set of all
|
|---|
| 775 | valuations in that system.
|
|---|
| 776 |
|
|---|
| 777 | \begin{definition}
|
|---|
| 778 | Given a CIVL type system, A \emph{CIVL expression system} for that
|
|---|
| 779 | type system is a tuple comprising the following components:
|
|---|
| 780 | \begin{enumerate}
|
|---|
| 781 | \item a set $\Expr$ (the set of all \emph{typed expressions} over
|
|---|
| 782 | $\Var$),
|
|---|
| 783 | \item a function $\etype\colon\Expr\ra\Type$ (giving the type
|
|---|
| 784 | of each expression),
|
|---|
| 785 | \item a function
|
|---|
| 786 | $\eval\colon\Expr\times\Eval\ra\Val$ (the \emph{evaluation
|
|---|
| 787 | function}), satisyfing
|
|---|
| 788 | \begin{itemize}
|
|---|
| 789 | \item for any $e\in\Expr$ and $\eta\in\Eval$,
|
|---|
| 790 | $\eval(e,\eta)\in\Val_{\etype(e)}$,
|
|---|
| 791 | \end{itemize}
|
|---|
| 792 | \item a function which associates to any $V\subseteq\Var$, a
|
|---|
| 793 | subset $\Expr(V)\subseteq\Expr$ (the set of
|
|---|
| 794 | \emph{expressions which involve only variables in $V$}) satisfying
|
|---|
| 795 | the following:
|
|---|
| 796 | \begin{itemize}
|
|---|
| 797 | \item for any $V\subseteq\Var$ and $\eta,\eta'\in\Eval$, if
|
|---|
| 798 | $\eta(v)=\eta'(v)$ for all $v\in V$, then for any $e\in\Expr(V)$,
|
|---|
| 799 | $\eval(e,\eta)=\eval(e,\eta')$
|
|---|
| 800 | \end{itemize}
|
|---|
| 801 | \end{enumerate}
|
|---|
| 802 | \end{definition}
|
|---|
| 803 |
|
|---|
| 804 | \begin{definition}
|
|---|
| 805 | A \emph{CIVL context} is a CIVL type system together with
|
|---|
| 806 | a CIVL expression system for that type system.
|
|---|
| 807 | \end{definition}
|
|---|
| 808 |
|
|---|
| 809 | \begin{figure}
|
|---|
| 810 | \notationtable
|
|---|
| 811 | \caption{Table of Notation Used to Define CIVL Model Syntax}
|
|---|
| 812 | \label{fig:notation}
|
|---|
| 813 | \end{figure}
|
|---|
| 814 |
|
|---|
| 815 | \subsection{Lexical scopes}
|
|---|
| 816 | \label{sec:scopes}
|
|---|
| 817 |
|
|---|
| 818 | \begin{definition}
|
|---|
| 819 | Given a CIVL context $\mathcal{C}$, a \emph{lexical scope system}
|
|---|
| 820 | over $\mathcal{C}$ is a tuple $(\Sigma,\rootscope,\sparent,\vars)$
|
|---|
| 821 | consisting of
|
|---|
| 822 | \begin{enumerate}
|
|---|
| 823 | \item a set $\Sigma$ (the set of \emph{static scopes}),
|
|---|
| 824 | \item a scope $\rootscope\in\Sigma$ (the \emph{root scope}),
|
|---|
| 825 | \item a function
|
|---|
| 826 | $\sparent\colon\Sigma\setminus\{\rootscope\}\rightarrow
|
|---|
| 827 | \Sigma$ such that
|
|---|
| 828 | \[\{(\sparent(\sigma),\sigma)\mid \sigma\in\Sigma\setminus\{\rootscope\}\}\]
|
|---|
| 829 | gives $\Sigma$ the structure of a rooted tree with root $\rootscope$,
|
|---|
| 830 | \item a function $\vars\colon\Sigma\rightarrow 2^{\Var}$
|
|---|
| 831 | (specifying the variables \emph{declared} in each scope) satisfying
|
|---|
| 832 | \begin{itemize}
|
|---|
| 833 | \item $\sigma\neq\tau\implies \vars(\sigma)\cap \vars(\tau)=\emptyset$.
|
|---|
| 834 | \end{itemize}
|
|---|
| 835 | \end{enumerate}
|
|---|
| 836 | \end{definition}
|
|---|
| 837 |
|
|---|
| 838 | \begin{definition}
|
|---|
| 839 | Given a CIVL context and scope $\sigma\in\Sigma$,
|
|---|
| 840 | the set of \emph{visible variables} in $\sigma$
|
|---|
| 841 | is $\bigcup_{\sigma'\in\ancestors(\sigma)}\vars(\sigma')$.
|
|---|
| 842 | \end{definition}
|
|---|
| 843 |
|
|---|
| 844 | One way this notion will be used: expressions used in a scope $\sigma$
|
|---|
| 845 | can only involve variables visible in $\sigma$.
|
|---|
| 846 |
|
|---|
| 847 | \subsection{Functions}
|
|---|
| 848 | \label{sec:functions}
|
|---|
| 849 |
|
|---|
| 850 | Fix a CIVL context $\mathcal{C}$ and lexical scope system
|
|---|
| 851 | \[\Lambda=(\Sigma,\rootscope,\sparent,\vars)\] over $\mathcal{C}$.
|
|---|
| 852 |
|
|---|
| 853 | We introduce a new type symbol $\void$, as in C, to use as the return
|
|---|
| 854 | type for a function that does not return a value. Let
|
|---|
| 855 | $\Type'=\Type\cup\{\void\}$.
|
|---|
| 856 |
|
|---|
| 857 | \begin{definition}
|
|---|
| 858 | A \emph{function prototype} for $\Lambda$ is a tuple
|
|---|
| 859 | $(\sigma, t, \xi)$ consisting of
|
|---|
| 860 | \begin{enumerate}
|
|---|
| 861 | \item a scope $\sigma\in\Sigma\setminus\{\rootscope\}$
|
|---|
| 862 | (the \emph{function scope}),
|
|---|
| 863 | \item a type $t\in\Type'$ (the \emph{return type}),
|
|---|
| 864 | \item a finite sequence $\xi=v_1v_2\cdots v_n\in\vars(\sigma)^*$
|
|---|
| 865 | consisting of variables declared in the function scope
|
|---|
| 866 | (the \emph{formal parameters}).
|
|---|
| 867 | \end{enumerate}
|
|---|
| 868 | \end{definition}
|
|---|
| 869 |
|
|---|
| 870 | \begin{definition}
|
|---|
| 871 | A \emph{CIVL function prototype system} consists of
|
|---|
| 872 | \begin{enumerate}
|
|---|
| 873 | \item a set $\Func$ (the \emph{function symbols}),
|
|---|
| 874 | \item a function which assigns to each $f\in\Func$ a
|
|---|
| 875 | function prototype, denoted
|
|---|
| 876 | \[
|
|---|
| 877 | (\fscope(f), \returntype(f), \params(f)),
|
|---|
| 878 | \]
|
|---|
| 879 | and satisfying
|
|---|
| 880 | \begin{itemize}
|
|---|
| 881 | \item for any $\sigma\in\Sigma$, there is at most
|
|---|
| 882 | one $f\in\Func$ such that $\sigma=\fscope(f)$, and
|
|---|
| 883 | \end{itemize}
|
|---|
| 884 | \item a \emph{root function} $f_0$ with $\fscope(f_0)=\rootscope$
|
|---|
| 885 | and which is the only function with root scope.
|
|---|
| 886 | \end{enumerate}
|
|---|
| 887 | \end{definition}
|
|---|
| 888 |
|
|---|
| 889 |
|
|---|
| 890 | \begin{definition}
|
|---|
| 891 | Given a CIVL function prototype system, and function symbol
|
|---|
| 892 | $f\in\Func\setminus\{f_0\}$, the \emph{declaration scope} of $f$ is
|
|---|
| 893 | the scope $\sigma=\sparent(\fscope(f))$. We also write \emph{$f$ is
|
|---|
| 894 | declared in $\sigma$.}
|
|---|
| 895 | \end{definition}
|
|---|
| 896 |
|
|---|
| 897 | Note the root function $f_0$ has no declaration scope.
|
|---|
| 898 |
|
|---|
| 899 | Just as every scope has a set of visible variables, there is also
|
|---|
| 900 | a set of visible functions:
|
|---|
| 901 | \begin{definition}
|
|---|
| 902 | The functions \emph{visible at scope $\sigma$} are
|
|---|
| 903 | those declared in $\sigma$ or an ancestor of $\sigma$.
|
|---|
| 904 | \end{definition}
|
|---|
| 905 | We will see that the variables and functions visible at $\sigma$ are
|
|---|
| 906 | the only variables and functions that can be referred to by statements
|
|---|
| 907 | and expressions used within $\sigma$.
|
|---|
| 908 |
|
|---|
| 909 | Note that only certain scopes are function scopes. There can be
|
|---|
| 910 | additional scopes (intuitively corresponding to block scopes in a
|
|---|
| 911 | source program). Every scope, however, must ``belong to'' exactly one
|
|---|
| 912 | function. The precise definition is as follows:
|
|---|
| 913 | \begin{definition}
|
|---|
| 914 | \label{def:func}
|
|---|
| 915 | Given a CIVL function prototype system, define
|
|---|
| 916 | \[
|
|---|
| 917 | \func \colon \Sigma \ra \Func
|
|---|
| 918 | \]
|
|---|
| 919 | by
|
|---|
| 920 | \[
|
|---|
| 921 | \func(\sigma)=
|
|---|
| 922 | \begin{cases}
|
|---|
| 923 | f & \text{if $\sigma=\fscope(f)$ for some $f\in\Func$}\\
|
|---|
| 924 | \func(\sparent(\sigma)) & \text{otherwise.}
|
|---|
| 925 | \end{cases}
|
|---|
| 926 | \]
|
|---|
| 927 | We say \emph{$\sigma$ belongs to $f$} when $\func(\sigma)=f$.
|
|---|
| 928 | \end{definition}
|
|---|
| 929 | Note that the recursion in Definition \ref{def:func} must stop as the
|
|---|
| 930 | root scope belongs to the root function and the scopes form a tree.
|
|---|
| 931 |
|
|---|
| 932 |
|
|---|
| 933 | \subsection{Statements}
|
|---|
| 934 |
|
|---|
| 935 | Fix a CIVL function prototype system. A \emph{CIVL statement} is
|
|---|
| 936 | defined to be a tuple of one of the forms described below.
|
|---|
| 937 | In each case, we give any restritions on the components of the tuple
|
|---|
| 938 | and a brief intuition on the statement's semantics. The precise
|
|---|
| 939 | semantics will be described in \S\ref{sec:semantics}.
|
|---|
| 940 |
|
|---|
| 941 | \begin{enumerate}
|
|---|
| 942 | \item $\langle\code{parassign},V_1,V_2,\psi\rangle$
|
|---|
| 943 | \begin{itemize}
|
|---|
| 944 | \item $V_1,V_2\subseteq\Var$
|
|---|
| 945 | \item $\psi\colon V_2\ra\Expr(V_1)$ satisfying
|
|---|
| 946 | $\etype(\psi(v))=\vtype(v)$ for all $v\in V_2$
|
|---|
| 947 | \item \emph{meaning}: parallel assignment, i.e., the assignment of new
|
|---|
| 948 | values to any or all of the variables in $V_2$. For each variable
|
|---|
| 949 | in $V_2$ an expression is given which will be evaluated in the old
|
|---|
| 950 | state to compute the new value for that variable. $V_1$ contains
|
|---|
| 951 | all the variables that may be used in those expressions. Hence
|
|---|
| 952 | $V_1$ is the ``read set'' and $V_2$ is the ``write set'' for the
|
|---|
| 953 | parallel assignment.
|
|---|
| 954 | \end{itemize}
|
|---|
| 955 | \item $\langle\code{assign},v,e\rangle$
|
|---|
| 956 | \begin{itemize}
|
|---|
| 957 | \item $v\in\Var$, $e\in\Expr$, $\etype(e)=\vtype(v)$
|
|---|
| 958 | \item \emph{meaning}: simple assignment: evaluate an expression $e$ and
|
|---|
| 959 | assign result to variable $v$. It is a special case of
|
|---|
| 960 | \code{parassign} but is provided for convenience.
|
|---|
| 961 | \end{itemize}
|
|---|
| 962 | \item $\langle\code{call},y,f,e_1,\ldots,e_n\rangle$
|
|---|
| 963 | \begin{itemize}
|
|---|
| 964 | \item $y\in\Var$, $f\in\Func$, $e_1,\ldots,e_n\in\Expr$
|
|---|
| 965 | \item $n=\numparams(f)$
|
|---|
| 966 | \item $\etype(e_i)=\vtype(v_i)$, where $\params(f)=v_1\cdots v_n$
|
|---|
| 967 | \item $\returntype(f)=\vtype(y)$
|
|---|
| 968 | \item \emph{meaning}: evaluate expressions $e_1,\ldots,e_n$; push
|
|---|
| 969 | frame on call stack and move control to guarded transition system
|
|---|
| 970 | (see \S\ref{sec:gts}) for function $f$; when $f$ returns, pop
|
|---|
| 971 | stack and store returned result in $y$
|
|---|
| 972 | \end{itemize}
|
|---|
| 973 | \item $\langle\code{call},f,e_1,\ldots,e_n\rangle$
|
|---|
| 974 | \begin{itemize}
|
|---|
| 975 | \item $f\in\Func$, $e_1,\ldots,e_n\in\Expr$
|
|---|
| 976 | \item $n=\numparams(f)$
|
|---|
| 977 | \item $\etype(e_i)=\vtype(v_i)$, where $\params(f)=v_1\cdots v_n$
|
|---|
| 978 | \item \emph{meaning}: like above, but return type may be \code{void}
|
|---|
| 979 | or returned value could just be ignored
|
|---|
| 980 | \end{itemize}
|
|---|
| 981 | \item $\langle\code{fork},p,f,e_1,\ldots,e_n\rangle$
|
|---|
| 982 | \begin{itemize}
|
|---|
| 983 | \item $p\in\Var$, $f\in\Func$, $e_1,\ldots,e_n\in\Expr$
|
|---|
| 984 | \item $n=\numparams(f)$
|
|---|
| 985 | \item $\etype(e_i)=\vtype(v_i)$, where $\params(f)=v_1\cdots v_n$
|
|---|
| 986 | \item $\returntype(f)=\void$
|
|---|
| 987 | \item $\vtype(p)=\proc$
|
|---|
| 988 | \item \emph{meaning}: evaluate expressions $e_1,\ldots,e_n$;
|
|---|
| 989 | create new process and invoke function $f$ in it;
|
|---|
| 990 | return, immediately, a reference to the new process and store
|
|---|
| 991 | that reference in $p$
|
|---|
| 992 | \end{itemize}
|
|---|
| 993 | \item $\langle\code{join},e\rangle$
|
|---|
| 994 | \begin{itemize}
|
|---|
| 995 | \item $e\in\Expr$
|
|---|
| 996 | \item $\etype(e)=\proc$
|
|---|
| 997 | \item \emph{meaning}: evaluate $e$ and wait for the referenced process to terminate
|
|---|
| 998 | \end{itemize}
|
|---|
| 999 | \item $\langle\code{return},e\rangle$
|
|---|
| 1000 | \begin{itemize}
|
|---|
| 1001 | \item $e\in\Expr$
|
|---|
| 1002 | \item \emph{meaning}: evaluate $e$, pop the call stack and return
|
|---|
| 1003 | control, along with the value, to caller
|
|---|
| 1004 | \end{itemize}
|
|---|
| 1005 | \item $\langle\code{return}\rangle$
|
|---|
| 1006 | \begin{itemize}
|
|---|
| 1007 | \item \emph{meaning}: pop the call stack and return control to caller;
|
|---|
| 1008 | only to be used in functions returning \code{void}
|
|---|
| 1009 | \end{itemize}
|
|---|
| 1010 | \item $\langle\code{write},e\rangle$
|
|---|
| 1011 | \begin{itemize}
|
|---|
| 1012 | \item $e\in\Expr$
|
|---|
| 1013 | \item \emph{meaning}: evaluate $e$ and send result to output
|
|---|
| 1014 | \end{itemize}
|
|---|
| 1015 | \item $\langle\code{noop}\rangle$
|
|---|
| 1016 | \begin{itemize}
|
|---|
| 1017 | \item \emph{meaning}: does nothing
|
|---|
| 1018 | \end{itemize}
|
|---|
| 1019 | \item $\langle\code{assert}, e\rangle$
|
|---|
| 1020 | \begin{itemize}
|
|---|
| 1021 | \item $e\in\Expr$, $\vtype(e)=\bool$
|
|---|
| 1022 | \item \emph{meaning}: evaluate $e$; if result is false, stop
|
|---|
| 1023 | execution and report error
|
|---|
| 1024 | \end{itemize}
|
|---|
| 1025 | \item $\langle\code{assume}, e\rangle$
|
|---|
| 1026 | \begin{itemize}
|
|---|
| 1027 | \item $e\in\Expr$, $\vtype(e)=\bool$
|
|---|
| 1028 | \item \emph{meaning}: assume $e$ holds (i.e., if $e$ does not hold,
|
|---|
| 1029 | the execution sequence is not a real execution)
|
|---|
| 1030 | \end{itemize}
|
|---|
| 1031 | \end{enumerate}
|
|---|
| 1032 |
|
|---|
| 1033 | \subsection{Remarks}
|
|---|
| 1034 |
|
|---|
| 1035 | The system described is sufficiently general to model pointers. There
|
|---|
| 1036 | can be (one or more) pointer types and corresponding values. The
|
|---|
| 1037 | parallel assignment statement can be used to model statements like
|
|---|
| 1038 | C's \texttt{*p=e;}. In the worst case (if no information is known
|
|---|
| 1039 | about where \texttt{p} could point), one can let $V_2=\Var$.
|
|---|
| 1040 | Similarly, expressions that involve \texttt{*p} as a right-hand
|
|---|
| 1041 | side subexpression can always take $V_1=\Var$.
|
|---|
| 1042 |
|
|---|
| 1043 | Heaps can also be modeled. A heap type may be defined and a variable
|
|---|
| 1044 | of that type declared. Expressions to modify and read from the heap
|
|---|
| 1045 | can be defined, as can pointers into the heap.
|
|---|
| 1046 |
|
|---|
| 1047 |
|
|---|
| 1048 | \subsection{Transition system representation of functions}
|
|---|
| 1049 | \label{sec:gts}
|
|---|
| 1050 |
|
|---|
| 1051 | \begin{definition}
|
|---|
| 1052 | Given a CIVL function prototype system and $f\in\Func$,
|
|---|
| 1053 | a \emph{guarded transition system} for $f$
|
|---|
| 1054 | is a tuple $(\Loc,\lscope,\start, T)$, where
|
|---|
| 1055 | \begin{itemize}
|
|---|
| 1056 | \item $\Loc$ is a set (the set of \emph{locations}),
|
|---|
| 1057 | \item $\lscope\colon\Loc\ra\Sigma$ is a function which associates
|
|---|
| 1058 | to each $l\in\Loc$ a scope $\lscope(l)\in\Sigma$ belonging to $f$,
|
|---|
| 1059 | \item $\start\in\Loc$ (the \emph{start location}),
|
|---|
| 1060 | \item $T$ is a set of \emph{guarded transitions}, each of which has
|
|---|
| 1061 | the form $\langle l,g,s,l'\rangle$, where
|
|---|
| 1062 | \begin{itemize}
|
|---|
| 1063 | \item $l,l'\in\Loc$ (the \emph{source} and \emph{target}
|
|---|
| 1064 | locations)
|
|---|
| 1065 | \item $g\in\Expr(V)$, where $V$ is the set of variables visible at
|
|---|
| 1066 | $\lscope(l)$, and $\etype(g)=\bool$ ($g$ is called the
|
|---|
| 1067 | \emph{guard}),
|
|---|
| 1068 | \item $s$ is a statment all of whose constituent variables,
|
|---|
| 1069 | expressions, and function symbols are visible at $\lscope(l)$.
|
|---|
| 1070 | \end{itemize}
|
|---|
| 1071 | \end{itemize}
|
|---|
| 1072 | Furthermore, if the guarded transition system contains a statement
|
|---|
| 1073 | of the form $\langle\code{return}\rangle$ then
|
|---|
| 1074 | $\returntype(f)=\void$. If it contains a statement of the form
|
|---|
| 1075 | $\langle\code{return},e\rangle$ then $\etype(e)=\returntype(f)$.
|
|---|
| 1076 | \end{definition}
|
|---|
| 1077 |
|
|---|
| 1078 | \begin{definition}
|
|---|
| 1079 | Given a CIVL prototype system, a \emph{CIVL model} $M$ for that
|
|---|
| 1080 | system assigns, to each $f\in\Func$, a guarded transition system
|
|---|
| 1081 | \[(\Loc_f,\lscope_f, \start_f,T_f)\] for $f$. Moreover, if $f\neq f'$
|
|---|
| 1082 | then
|
|---|
| 1083 | $\Loc_f\cap\Loc_{f'}=\emptyset$.
|
|---|
| 1084 | \end{definition}
|
|---|
| 1085 |
|
|---|
| 1086 | \begin{definition}
|
|---|
| 1087 | Given a CIVL model $M$, let $\Loc=\bigcup_{f\in\Func}\Loc_f$.
|
|---|
| 1088 | \end{definition}
|
|---|
| 1089 |
|
|---|
| 1090 | \section{CIVL Model Semantics}
|
|---|
| 1091 | \label{sec:semantics}
|
|---|
| 1092 |
|
|---|
| 1093 | \subsection{State}
|
|---|
| 1094 | \label{sec:state}
|
|---|
| 1095 |
|
|---|
| 1096 | Fix a CIVL model $M$. Recall that a valuation is a type-respecting
|
|---|
| 1097 | function from $\Var$ to $\Val$. Given a subset $V\subseteq\Var$ of
|
|---|
| 1098 | variables, we define a \emph{valuation on $V$} to be a type-respecting
|
|---|
| 1099 | function from $V$ to $\Val$. Let $\Eval(V)$ denote the set of all
|
|---|
| 1100 | valuations on $V$. Note that $\Eval(\Var)=\Eval$.
|
|---|
| 1101 |
|
|---|
| 1102 | \begin{definition}
|
|---|
| 1103 | \label{def:state}
|
|---|
| 1104 | A \emph{state} of a CIVL model $M$ is a tuple
|
|---|
| 1105 | \[
|
|---|
| 1106 | s=(\Delta, \droot, \dparent, \static, \deval, P, \stack),
|
|---|
| 1107 | \]
|
|---|
| 1108 | where
|
|---|
| 1109 | \begin{enumerate}
|
|---|
| 1110 | \item $\Delta$ is a finite set (the set of \emph{dynamic scopes} in
|
|---|
| 1111 | $s$),
|
|---|
| 1112 | \item $\droot\in\Delta$ (the \emph{root dynamic scope}),
|
|---|
| 1113 | \item $\dparent\colon \Delta\setminus\{\droot\}\ra\Delta$
|
|---|
| 1114 | is a function such that the set
|
|---|
| 1115 | \[
|
|---|
| 1116 | \{(\dparent(\delta),\delta)\mid \delta\in
|
|---|
| 1117 | \Delta\setminus\{\droot\}\}
|
|---|
| 1118 | \]
|
|---|
| 1119 | gives $\Delta$ the structure of a rooted tree with root $\droot$,
|
|---|
| 1120 | \item $\static\colon\Delta\ra\Sigma$,
|
|---|
| 1121 | \item $\static(\droot)=\rootscope$ and $\droot$ is the only
|
|---|
| 1122 | $\delta\in\Delta$ satisfying $\static(\delta)=\rootscope$,
|
|---|
| 1123 | \item $\static(\dparent(\delta))=\sparent(\static(\delta))$ for any
|
|---|
| 1124 | $\delta\in\Delta$,
|
|---|
| 1125 | \item $\deval$ is a function that assigns to each $\delta\in\Delta$
|
|---|
| 1126 | a valuation $\deval(\delta)\in\Eval(\vars(\static(\delta)))$,
|
|---|
| 1127 | \item $P$ (the set of \emph{process IDs} in $s$)
|
|---|
| 1128 | is a finite subset of $\Val_{\proc}$, and
|
|---|
| 1129 | \item $\stack\colon P\ra \Frame^*$, where
|
|---|
| 1130 | \[
|
|---|
| 1131 | \Frame=\{(\delta,l)\in\Delta\times\Loc\mid\lscope(l)=\static(\delta)\}.
|
|---|
| 1132 | \]
|
|---|
| 1133 | \end{enumerate}
|
|---|
| 1134 | Let $\State$ denote the set of all states of $M$.
|
|---|
| 1135 | \end{definition}
|
|---|
| 1136 |
|
|---|
| 1137 | % say entrance and exit from scopes does not have to be "structured".
|
|---|
| 1138 |
|
|---|
| 1139 | Remarks:
|
|---|
| 1140 | \begin{enumerate}
|
|---|
| 1141 | \item We will also refer to dynamic scopes as \emph{dyscopes}.
|
|---|
| 1142 | \item The elements of $\Delta$ contain no intrinsic information.
|
|---|
| 1143 | Instead, all of the information concerning dyscopes is encoded
|
|---|
| 1144 | in the functions that take elements of $\Delta$ as arguments. Hence
|
|---|
| 1145 | we might just as well call the elements of $\Delta$ ``dynamic scope
|
|---|
| 1146 | IDs'' (just as we call the elements of $P$ ``process IDs''). One
|
|---|
| 1147 | could use natural numbers for the dyscopes, just as one does
|
|---|
| 1148 | for processes.
|
|---|
| 1149 | \item The reason for using some form of ID for dyscopes and
|
|---|
| 1150 | processes, rather than just incorporating the data in the
|
|---|
| 1151 | appropriate part of the state, is that both kinds of objects may be
|
|---|
| 1152 | shared. There can be several components of the state that refer to
|
|---|
| 1153 | the same dyscope $d$: e.g., $d$ could have several children,
|
|---|
| 1154 | each of which has a parent reference to $d$, as well as a reference
|
|---|
| 1155 | from a frame. A process can be referred to by any number of
|
|---|
| 1156 | variables of type $\proc$.
|
|---|
| 1157 | \item If $\sigma=\static(\delta)$, we say that \emph{$\delta$ is an
|
|---|
| 1158 | instance of $\sigma$} or \emph{$\sigma$ is the static scope
|
|---|
| 1159 | associated to $\delta$}. In general, a static scope can have any
|
|---|
| 1160 | number (including 0) of dynamic instances. The exception is the root
|
|---|
| 1161 | scope $\rootscope$, which must have exactly one instance ($\droot$).
|
|---|
| 1162 | \item A valuation $\deval(\delta)$ assigns a value to each variable in
|
|---|
| 1163 | the static scope associated to $\delta$. The function $\deval$
|
|---|
| 1164 | thereby encodes the value of all variables ``in scope'' in state
|
|---|
| 1165 | $s$.
|
|---|
| 1166 | \item The sequence $\stack(p)$ encodes the state of the call stack of
|
|---|
| 1167 | process $p$. The elements of the sequence are called
|
|---|
| 1168 | \emph{activation frames}. The first frame in the sequence, i.e.,
|
|---|
| 1169 | the frame in position $0$, is the bottom of the stack; the last
|
|---|
| 1170 | frame is the top of the stack.
|
|---|
| 1171 | \item Each frame refers to a dyscope $\delta$ and a
|
|---|
| 1172 | location in the static scope associated to $\delta$.
|
|---|
| 1173 | \end{enumerate}
|
|---|
| 1174 |
|
|---|
| 1175 |
|
|---|
| 1176 | \begin{definition}
|
|---|
| 1177 | A dyscope $\delta\in\Delta$ is a \emph{function node}
|
|---|
| 1178 | if $\static(\delta)$ is the function scope of some function.
|
|---|
| 1179 | \end{definition}
|
|---|
| 1180 |
|
|---|
| 1181 | \begin{definition}
|
|---|
| 1182 | Given any $\delta\in\Delta$, $\fnode(\delta)\in\Delta$ is defined as
|
|---|
| 1183 | follows: if $\delta$ is a function node, then
|
|---|
| 1184 | $\fnode(\delta)=\delta$, else
|
|---|
| 1185 | $\fnode(\delta)=\fnode(\dparent(\delta))$. We call $\fnode(\delta)$
|
|---|
| 1186 | the \emph{function node associated to $\delta$}.
|
|---|
| 1187 | \end{definition}
|
|---|
| 1188 |
|
|---|
| 1189 | The relation $\{(\delta,\delta')\mid \fnode(\delta)=\fnode(\delta')\}$
|
|---|
| 1190 | is an equivalence relation $\sim$ on $\Delta$. Let
|
|---|
| 1191 | $\bar{\Delta}=\Delta/\sim$ and write $[\delta]$ for the equivalence
|
|---|
| 1192 | class containing $\delta$.
|
|---|
| 1193 |
|
|---|
| 1194 | The set of activation frames in a state $s$ may be identified with the
|
|---|
| 1195 | set
|
|---|
| 1196 | \[
|
|---|
| 1197 | AF(s)=\bigcup_{p\in P}\{p\}\times\{0,\ldots,\len(\stack(p))-1\}
|
|---|
| 1198 | \]
|
|---|
| 1199 | Namely, $(p,i)$ corresponds to the $i^{\text{th}}$ entry in the call
|
|---|
| 1200 | stack $\stack(p)$ (where the elements of the stacks are indexed from
|
|---|
| 1201 | $0$).
|
|---|
| 1202 |
|
|---|
| 1203 | Define $\Psi\colon AF(s)\ra \bar{\Delta}$ as follows: given $(p,i)$,
|
|---|
| 1204 | let $(\delta,l)$ be the corresponding frame; set $\Psi(p,i)=[\delta]$.
|
|---|
| 1205 |
|
|---|
| 1206 | % \begin{definition}
|
|---|
| 1207 | % A state $s$ is \emph{well-formed} if all of the following hold:
|
|---|
| 1208 | % \begin{enumerate}
|
|---|
| 1209 | % \item for any $\delta\in\Delta$, at most one child of $\delta$ is not
|
|---|
| 1210 | % a function node,
|
|---|
| 1211 | % \item the function $\Psi$ is a one-to-one correspondence,
|
|---|
| 1212 | % \item any $\delta$ occurring in the top frame of a call stack
|
|---|
| 1213 | % is a leaf node.
|
|---|
| 1214 | % \end{enumerate}
|
|---|
| 1215 | % \end{definition}
|
|---|
| 1216 |
|
|---|
| 1217 |
|
|---|
| 1218 | \subsection{Jump protocol}
|
|---|
| 1219 | \label{sec:jump}
|
|---|
| 1220 |
|
|---|
| 1221 | % can only jump if \delta is a leaf node.
|
|---|
| 1222 | % also no other frame can point to a dyscope between \delta
|
|---|
| 1223 | % and the dyscope corresponding to the function scope
|
|---|
| 1224 |
|
|---|
| 1225 | % in any state, a "region" of the dyscope tree can have at
|
|---|
| 1226 | % most one (exactly one?) stack frame pointing into it.
|
|---|
| 1227 |
|
|---|
| 1228 | % a region in a chain of nodes starting from a dyanmic scope corresonding
|
|---|
| 1229 | % to a function scopes and leading down until you reach another
|
|---|
| 1230 | % function scope.
|
|---|
| 1231 |
|
|---|
| 1232 | % whenever you have more than one child in the dynamic tree, all but
|
|---|
| 1233 | % 0 or 1 children must be a function scope
|
|---|
| 1234 |
|
|---|
| 1235 | % every dyscope is owned by at most one frame
|
|---|
| 1236 |
|
|---|
| 1237 | % can a frame point only to a leaf node? No, but all of its children
|
|---|
| 1238 | % must be function nodes
|
|---|
| 1239 |
|
|---|
| 1240 | % to find out which frame owns which dyscopes:
|
|---|
| 1241 |
|
|---|
| 1242 | % approach 1: start from a frame. frame owns the node it points to.
|
|---|
| 1243 | % move up parents until you hit a function scope and stop.
|
|---|
| 1244 | % that is that frame's region. No other frame can point into its
|
|---|
| 1245 | % region. Proof: true in initial state, invariant under
|
|---|
| 1246 | % call and fork.
|
|---|
| 1247 |
|
|---|
| 1248 | % invariant: every leaf node in the dyscope tree is pointed
|
|---|
| 1249 | % to by the top frame of the call stack of some process
|
|---|
| 1250 |
|
|---|
| 1251 | % Define a \emph{well-formed state}:
|
|---|
| 1252 |
|
|---|
| 1253 | % every dyscope node has at most one child which is not a function node
|
|---|
| 1254 |
|
|---|
| 1255 | % 1-1 correspondence between leaf nodes and top frames of stacks.
|
|---|
| 1256 |
|
|---|
| 1257 | % Define regions in the dyscope tree. (each region contains one
|
|---|
| 1258 | % function node)
|
|---|
| 1259 |
|
|---|
| 1260 | \newcommand{\lub}{\sigma_{\textsf{lub}}}
|
|---|
| 1261 |
|
|---|
| 1262 | \begin{figure}
|
|---|
| 1263 | \begin{algorithm}[H]
|
|---|
| 1264 | \Procedure{$\textsf{\textup{jump}}(s\colon\State, p\colon\Val_{\proc},
|
|---|
| 1265 | l'\colon\Loc)\colon\State$}{%
|
|---|
| 1266 | let $(\Delta, \droot, \dparent, \static, \deval, P, \stack)=s$\;
|
|---|
| 1267 | let $\delta$ be the dyscope of the last frame on $\stack(p)$\;
|
|---|
| 1268 | let $\sigma=\static(\delta)$\;
|
|---|
| 1269 | let $\sigma'=\lscope(l')$\;
|
|---|
| 1270 | let $\lub$ be the least upper bound of $\sigma$ and
|
|---|
| 1271 | $\sigma'$ in the tree $\Sigma$\;
|
|---|
| 1272 | let $m$ be the minimum integer such that
|
|---|
| 1273 | $\sparent^m(\sigma)=\lub$\;
|
|---|
| 1274 | let $\delta_{\textsf{lub}}=\dparent^m(\delta)$\;
|
|---|
| 1275 | let $n$ be the minimum integer such that
|
|---|
| 1276 | $\sparent^{n}(\sigma')=\lub$\;
|
|---|
| 1277 | let $\delta_0,\ldots,\delta_{n-1}$ be $n$ distinct objects not in $\Delta$\;
|
|---|
| 1278 | let
|
|---|
| 1279 | \( \displaystyle
|
|---|
| 1280 | \Delta'=\Delta
|
|---|
| 1281 | \cup \{ \delta_0,\ldots,\delta_{n-1} \}
|
|---|
| 1282 | %\setminus \{ \dparent^j(\delta)\mid 0\leq j<m\}
|
|---|
| 1283 | \)\;
|
|---|
| 1284 | define $\dparent'\colon\Delta'\setminus\{\droot\}\ra\Delta'$ by
|
|---|
| 1285 | \(
|
|---|
| 1286 | \dparent'(\delta')=
|
|---|
| 1287 | \begin{cases}
|
|---|
| 1288 | \dparent(\delta') & \text{if $\delta'\in\Delta$}\\
|
|---|
| 1289 | \delta_{i+1} & \text{if $\delta'=\delta_{i}$ for some $0\leq i<n-1$}\\
|
|---|
| 1290 | \delta_{\textsf{lub}} & \text{if $n\geq 1$ and $\delta'=\delta_{n-1}$}
|
|---|
| 1291 | \end{cases}
|
|---|
| 1292 | \)\;
|
|---|
| 1293 | define $\static'\colon\Delta'\ra\Sigma$ by
|
|---|
| 1294 | \(
|
|---|
| 1295 | \static'(\delta')=
|
|---|
| 1296 | \begin{cases}
|
|---|
| 1297 | \static(\delta') & \text{if $\delta'\in\Delta$}\\
|
|---|
| 1298 | \sparent^i(\sigma') & \text{if $\delta'=\delta_i$ for some $0\leq i<n$}
|
|---|
| 1299 | \end{cases}
|
|---|
| 1300 | \)\;
|
|---|
| 1301 | for $\delta'\in\Delta'$ and $v\in\vars(\static(\delta'))$,
|
|---|
| 1302 | let
|
|---|
| 1303 | \(
|
|---|
| 1304 | \deval'(\delta')(v) =
|
|---|
| 1305 | \begin{cases}
|
|---|
| 1306 | \deval(\delta')(v) & \text{if $\delta'\in\Delta$}\\
|
|---|
| 1307 | \default_t & \text{otherwise}
|
|---|
| 1308 | \end{cases}
|
|---|
| 1309 | \)\;
|
|---|
| 1310 | define $\stack'$ to be the same as $\stack$ except that
|
|---|
| 1311 | the last frame on $\stack'(p)$ is replaced with
|
|---|
| 1312 | $(\delta_0,l')$ if $n\geq 1$, or with $(\delta_{\textsf{lub}},l')$
|
|---|
| 1313 | if $n=0$\;
|
|---|
| 1314 | let $s'(\Delta',\droot,\dparent',\static',\deval',P,\stack')$\;
|
|---|
| 1315 | return the result of removing all unreachable dyscopes from $s'$\;
|
|---|
| 1316 | }
|
|---|
| 1317 | \end{algorithm}
|
|---|
| 1318 | \caption{Jump protocol: how the state changes when control moves
|
|---|
| 1319 | to a new location within a function. The procedure may only
|
|---|
| 1320 | be called if $\func(\sigma)=\func(\sigma')$, i.e., the jump
|
|---|
| 1321 | is contained within one function.}
|
|---|
| 1322 | \label{fig:jump}
|
|---|
| 1323 | \end{figure}
|
|---|
| 1324 |
|
|---|
| 1325 | When control moves from one location to another within a function's
|
|---|
| 1326 | transition system, dyscopes may be added, because you can jump out of
|
|---|
| 1327 | scope nests and into new scope nests. The motivating idea is that you
|
|---|
| 1328 | have to move up the dyscope tree every time you move past a right
|
|---|
| 1329 | curly brace (i.e., leave a scope) and then push on a new scope for
|
|---|
| 1330 | each left curly brace you move past. So there is a sequence of upward
|
|---|
| 1331 | moves followed by a sequence of pushes to get to the new
|
|---|
| 1332 | location. (And either or both sequences could be empty.) At the end,
|
|---|
| 1333 | if any dyscopes become unreachable, they are removed from the state.
|
|---|
| 1334 |
|
|---|
| 1335 | Note however, that we do not assume that scopes are associated to
|
|---|
| 1336 | locations in a nice lexical pattern (or any pattern at all). The
|
|---|
| 1337 | protocol described here works for any arbitrary assignment of scopes
|
|---|
| 1338 | to locations.
|
|---|
| 1339 |
|
|---|
| 1340 | The precise protocol is described in Figure \ref{fig:jump}. The
|
|---|
| 1341 | algorithm shown there takes as input a well-formed state, a process
|
|---|
| 1342 | ID, and a location $l'$ for the function that $p$ is currently in.
|
|---|
| 1343 | Say the current dyscope for $p$ is $\delta$, and $l'$ is in
|
|---|
| 1344 | static scope $\sigma'$. Let $\sigma=\static(\delta)$. Hence the
|
|---|
| 1345 | current static scope is $\sigma$ and the new static scope will be $\sigma'$.
|
|---|
| 1346 |
|
|---|
| 1347 | First, you have to find the \emph{least upper bound} $\lub$ of
|
|---|
| 1348 | $\sigma$ and $\sigma'$ in the static scope tree. (Hence $\lub$ is a
|
|---|
| 1349 | common anecestor of $\sigma$ and $\sigma'$, and if $\sigma''$ is any
|
|---|
| 1350 | common ancestor of $\sigma$ and $\sigma'$ then $\sigma''$ is an
|
|---|
| 1351 | ancestor or equal to $\lub$.) Note that the least upper bound must
|
|---|
| 1352 | exist since the function scope is a common ancestor of $\sigma$ and
|
|---|
| 1353 | $\sigma'$. There is a chain of static scopes from $\sigma$ up to
|
|---|
| 1354 | $\lub$ and a corresponding chain
|
|---|
| 1355 | $\delta,\dparent(\delta),\ldots,\dparent^m(\delta)$ in the dynamic
|
|---|
| 1356 | scope tree. Let $\delta_{\textsf{lub}}=\dparent^m(\delta)$. This
|
|---|
| 1357 | will become the least upper bound of $\delta$ and the new dynamic
|
|---|
| 1358 | scope corresponding to $\sigma'$ that will be added to the state.
|
|---|
| 1359 |
|
|---|
| 1360 | Next you add new dyscopes corresponding to the chain of static
|
|---|
| 1361 | scopes leading from $\lub$ down to $\sigma'$. The variables in the
|
|---|
| 1362 | new scopes are assigned the default values for their respective types.
|
|---|
| 1363 | The $\dparent$, $\static$, and $\deval$ maps are adjusted
|
|---|
| 1364 | accordingly. Finally, the stack is modified by replacing the last
|
|---|
| 1365 | activation frame with a frame referring to the (possibly) new dynamic
|
|---|
| 1366 | scope and new location $l'$.
|
|---|
| 1367 |
|
|---|
| 1368 | This protocol is executed every time control moves from one location
|
|---|
| 1369 | to another.
|
|---|
| 1370 |
|
|---|
| 1371 | Note that in CIVL all jumps stay within a function. There is no
|
|---|
| 1372 | way to jump from one function to another (without returning).
|
|---|
| 1373 |
|
|---|
| 1374 | A small variation is the protocol for moving to the start location of
|
|---|
| 1375 | a function when the function is first pushed on the stack. Since the
|
|---|
| 1376 | start location is not necessarily in the function scope (it may be a
|
|---|
| 1377 | proper descendant of that scope), you have to execute the second half
|
|---|
| 1378 | of the protocol to push a sequence of scopes from the function scope
|
|---|
| 1379 | to the scope of the start location.
|
|---|
| 1380 |
|
|---|
| 1381 | \subsection{Initial State}
|
|---|
| 1382 |
|
|---|
| 1383 | The \emph{initial state} for $M$ is obtained by creating one process
|
|---|
| 1384 | (let $P=\{0\}$) and having it call the root function $f_0$.
|
|---|
| 1385 | Hence start with the state $s$ in which $P=\{0\}$, $\ldots$.
|
|---|
| 1386 | The initial state is $\textsf{jump}(s,0,\start_{f_0})$.
|
|---|
| 1387 |
|
|---|
| 1388 | \subsection{Transitions}
|
|---|
| 1389 |
|
|---|
| 1390 | The transitions follow the usual ``interleaving'' semantics. Given a
|
|---|
| 1391 | state $\sigma$, one defines the set of enabled transitions in $\sigma$
|
|---|
| 1392 | as follows. Let $p\in P$. Look at the last frame $(d,l)$ of
|
|---|
| 1393 | $\stack(p)$ (i.e., the top of the call stack), assuming the stack is
|
|---|
| 1394 | nonempty. Look at all guarded transitions emanating from $l$. For each
|
|---|
| 1395 | such transition, evaluate the guard using the valuation formed by
|
|---|
| 1396 | taking the union of the valuations of all ancestors of $d$ (including
|
|---|
| 1397 | $d$). In other words, follow the standard ``lexical scoping'' protocol
|
|---|
| 1398 | to determine the value of any variable that could occur at this point.
|
|---|
| 1399 | Those transitions whose guard evaluates to $\emph{true}$ are enabled.
|
|---|
| 1400 |
|
|---|
| 1401 | For each enabled transition, a new state is generated by executing
|
|---|
| 1402 | the transition's statement. For the most part, the semantics are obvious,
|
|---|
| 1403 | but there are a few details that are a bit subtle.
|
|---|
| 1404 |
|
|---|
| 1405 | \subsection{Calls and Forks}
|
|---|
| 1406 |
|
|---|
| 1407 | Both calls and forks of a function $f$ entail the creation of a new
|
|---|
| 1408 | frame. First, a new dyscope $d$ corresponding to $\fscope(f)$ is
|
|---|
| 1409 | created. To find out where to stick that new scope in the dynamic
|
|---|
| 1410 | scope tree, proceed as follows: begin in the dyscope for the
|
|---|
| 1411 | process invoking the fork or call and start moving up its parent
|
|---|
| 1412 | sequence until you reach the first dyscope $d'$ whose associated
|
|---|
| 1413 | static scope is the defining scope of $f$. (You must reach such a
|
|---|
| 1414 | scope, or else $f$ would not be visible, and the model would have a
|
|---|
| 1415 | syntax error!) Insert $d$ right under $d'$, i.e.,
|
|---|
| 1416 | $\dparent(d)=d'$. This preserves the required correspondence between
|
|---|
| 1417 | static scopes and dyscopes. Now you move to the start location,
|
|---|
| 1418 | using the jump protocol, which may involve the creation of additional
|
|---|
| 1419 | dyscopes under $d$. The new frame references the last dynamic
|
|---|
| 1420 | scope you created, and the location is the start location of $f$.
|
|---|
| 1421 | Variables are given their initial values in all the newly created
|
|---|
| 1422 | dyscopes (however that is done).
|
|---|
| 1423 |
|
|---|
| 1424 | All of that is the same whether the statement is a fork or call. The
|
|---|
| 1425 | only difference is what happens next: for a call, the new frame is
|
|---|
| 1426 | pushed onto the calling process' call stack. For a fork, a new process
|
|---|
| 1427 | is ``created'', i.e., you pick a natural number not in $P$ and
|
|---|
| 1428 | add it to $P$, and push the frame onto the new stack. To be totally
|
|---|
| 1429 | deterministic, you could pick the least natural number not in $P$.
|
|---|
| 1430 |
|
|---|
| 1431 | \subsection{Garbage collection}
|
|---|
| 1432 |
|
|---|
| 1433 | In a state $s$, a dyscope is unreachable if there is no path
|
|---|
| 1434 | from a frame in a call stack to that dyscope (following the
|
|---|
| 1435 | $\dparent$ edges). You can remove all unreachable dyscopes.
|
|---|
| 1436 |
|
|---|
| 1437 | If a process has terminated (has empty stack) and \emph{there are no
|
|---|
| 1438 | references to that process} in the state, you can just remove the process
|
|---|
| 1439 | from the state.
|
|---|
| 1440 |
|
|---|
| 1441 | In any state, you can renumber the processes (and update the
|
|---|
| 1442 | references accordingly) however you want, to get rid of gaps, put them
|
|---|
| 1443 | in a canonic order, etc.
|
|---|
| 1444 |
|
|---|
| 1445 |
|
|---|
| 1446 | \part{Tools}
|
|---|
| 1447 |
|
|---|
| 1448 | Current tools allow one to \emph{run} a CIVL program using random
|
|---|
| 1449 | choice to resolve nondeterministic choices; \emph{verify} a program
|
|---|
| 1450 | using model checking to explore all states of the program;
|
|---|
| 1451 | \emph{replay} a trace if an error is found.
|
|---|
| 1452 |
|
|---|
| 1453 | The properties checked are assertion violations, division by zero,
|
|---|
| 1454 | illegal pointer accesses, etc.
|
|---|
| 1455 |
|
|---|
| 1456 | The available tools and options are summarized by the \texttt{civl
|
|---|
| 1457 | help} command:
|
|---|
| 1458 |
|
|---|
| 1459 | \begin{verbatim}
|
|---|
| 1460 | Usage: civl <command> <options> filename ...
|
|---|
| 1461 | Commands:
|
|---|
| 1462 | verify : verify program filename
|
|---|
| 1463 | run : run program filename
|
|---|
| 1464 | help : print this message
|
|---|
| 1465 | replay : replay trace for program filename
|
|---|
| 1466 | parse : show result of preprocessing and parsing filename
|
|---|
| 1467 | preprocess : show result of preprocessing filename
|
|---|
| 1468 | Options:
|
|---|
| 1469 | -debug or -debug=BOOLEAN (default: false)
|
|---|
| 1470 | debug mode: print very detailed information
|
|---|
| 1471 | -errorBound=INTEGER (default: 1)
|
|---|
| 1472 | stop after finding this many errors
|
|---|
| 1473 | -guided or -guided=BOOLEAN
|
|---|
| 1474 | user guided simulation; applies only to run, ignored
|
|---|
| 1475 | for all other commands
|
|---|
| 1476 | -id=INTEGER (default: 0)
|
|---|
| 1477 | ID number of trace to replay
|
|---|
| 1478 | -inputKEY=VALUE
|
|---|
| 1479 | initialize input variable KEY to VALUE
|
|---|
| 1480 | -maxdepth=INTEGER (default: 2147483647)
|
|---|
| 1481 | bound on search depth
|
|---|
| 1482 | -min or -min=BOOLEAN (default: false)
|
|---|
| 1483 | search for minimal counterexample
|
|---|
| 1484 | -por=STRING (default: std)
|
|---|
| 1485 | partial order reduction (por) choices:
|
|---|
| 1486 | std (standard por) or scp (scoped por)
|
|---|
| 1487 | -random or -random=BOOLEAN
|
|---|
| 1488 | select enabled transitions randomly; default for run,
|
|---|
| 1489 | ignored for all other commands
|
|---|
| 1490 | -saveStates or -saveStates=BOOLEAN (default: true)
|
|---|
| 1491 | save states during depth-first search
|
|---|
| 1492 | -seed=STRING
|
|---|
| 1493 | set the random seed; applies only to run
|
|---|
| 1494 | -showModel or -showModel=BOOLEAN (default: false)
|
|---|
| 1495 | print the model
|
|---|
| 1496 | -showProverQueries or -showProverQueries=BOOLEAN (default: false)
|
|---|
| 1497 | print theorem prover queries only
|
|---|
| 1498 | -showQueries or -showQueries=BOOLEAN (default: false)
|
|---|
| 1499 | print all queries
|
|---|
| 1500 | -showSavedStates or -showSavedStates=BOOLEAN (default: false)
|
|---|
| 1501 | print saved states only
|
|---|
| 1502 | -showStates or -showStates=BOOLEAN (default: false)
|
|---|
| 1503 | print all states
|
|---|
| 1504 | -showTransitions or -showTransitions=BOOLEAN (default: false)
|
|---|
| 1505 | print transitions
|
|---|
| 1506 | -simplify or -simplify=BOOLEAN (default: true)
|
|---|
| 1507 | simplify states?
|
|---|
| 1508 | -solve or -solve=BOOLEAN (default: false)
|
|---|
| 1509 | try to solve for concrete counterexample
|
|---|
| 1510 | -sysIncludePath=STRING
|
|---|
| 1511 | set the user include path
|
|---|
| 1512 | -trace=STRING
|
|---|
| 1513 | filename of trace to replay
|
|---|
| 1514 | -userIncludePath=STRING
|
|---|
| 1515 | set the user include path
|
|---|
| 1516 | -verbose or -verbose=BOOLEAN (default: false)
|
|---|
| 1517 | verbose mode
|
|---|
| 1518 | \end{verbatim}
|
|---|
| 1519 |
|
|---|
| 1520 |
|
|---|
| 1521 |
|
|---|
| 1522 | % \subsection{Example 1}
|
|---|
| 1523 |
|
|---|
| 1524 | % Here is a simple example based on a tricky MPI+Pthreads example given
|
|---|
| 1525 | % to us once by Rajeev Thakur at Argonne. It has nondeterministic
|
|---|
| 1526 | % behavior which can lead to a deadlock for certain interleavings, even
|
|---|
| 1527 | % though it does not use wildcards (\code{ANY{\U}SOURCE}). Very subtle
|
|---|
| 1528 | % bug. I can show you MPI-Spin finding the bug if you are interested. I
|
|---|
| 1529 | % don't actually have the original code, but could probably dig it up.
|
|---|
| 1530 |
|
|---|
| 1531 | % \begin{verbatim}
|
|---|
| 1532 | % #include <mp.civl> /* includes basic message-passing library */
|
|---|
| 1533 |
|
|---|
| 1534 | % void System() {
|
|---|
| 1535 | % proc procs[2];
|
|---|
| 1536 |
|
|---|
| 1537 | % void MPI_Process(int pid) {
|
|---|
| 1538 | % proc threads[2];
|
|---|
| 1539 |
|
|---|
| 1540 | % void Thread(int tid) {
|
|---|
| 1541 | % int x=0, y=0;
|
|---|
| 1542 |
|
|---|
| 1543 | % for (int j=0; j<2; j++) {
|
|---|
| 1544 | % if (pid == 1) {
|
|---|
| 1545 | % for (int i=0; i<3; i++) send(procs[pid], &x, 1, procs[1-pid], 0);
|
|---|
| 1546 | % for (int i=0; i<3; i++) recv(procs[pid], &y, 1, procs[1-pid], 0);
|
|---|
| 1547 | % } else { /* pid==0 */
|
|---|
| 1548 | % for (int i=0; i<3; i++) recv(procs[pid], &y, 1, procs[1-pid], 0);
|
|---|
| 1549 | % for (int i=0; i<3; i++) send(procs[pid], &x, 1, procs[1-pid], 0);
|
|---|
| 1550 | % }
|
|---|
| 1551 | % }
|
|---|
| 1552 | % }
|
|---|
| 1553 |
|
|---|
| 1554 | % for (int i=0; i<2; i++) threads[i] = fork Thread(i);
|
|---|
| 1555 | % for (int i=0; i<2; i++) join threads[i];
|
|---|
| 1556 | % }
|
|---|
| 1557 |
|
|---|
| 1558 | % for (int i=0; i<2; i++) procs[i] = fork MPI_Process(i);
|
|---|
| 1559 | % for (int i=0; i<2; i++) join procs[i];
|
|---|
| 1560 | % }
|
|---|
| 1561 | % \end{verbatim}
|
|---|
| 1562 |
|
|---|
| 1563 | \appendix
|
|---|
| 1564 |
|
|---|
| 1565 |
|
|---|
| 1566 | \end{document}
|
|---|
| 1567 |
|
|---|
| 1568 |
|
|---|
| 1569 | OpenMP loop?
|
|---|
| 1570 | \begin{verbatim}
|
|---|
| 1571 | T1 x1; ... // private
|
|---|
| 1572 | U1 y1; ... // shared
|
|---|
| 1573 | #pragma omp parallel private(x1,...)
|
|---|
| 1574 | S(x1,...,y1,...);
|
|---|
| 1575 |
|
|---|
| 1576 | =>
|
|---|
| 1577 |
|
|---|
| 1578 | T1 x1; ...
|
|---|
| 1579 | U1 y1; ...
|
|---|
| 1580 | {
|
|---|
| 1581 | void _tmp(int _tid) {
|
|---|
| 1582 | T1 _x1; ...
|
|---|
| 1583 | S(_x1,...,y1,...);
|
|---|
| 1584 | }
|
|---|
| 1585 | int numThreads = $choose_int(THREAD_MAX);
|
|---|
| 1586 | $proc _threads[numThreads];
|
|---|
| 1587 | int i;
|
|---|
| 1588 |
|
|---|
| 1589 | for (i=0; i<numThreads; i++)
|
|---|
| 1590 | _threads[i] = $spawn _tmp(i);
|
|---|
| 1591 | for (i=0; i<numThreads; i++)
|
|---|
| 1592 | $wait _threads[i];
|
|---|
| 1593 | }
|
|---|
| 1594 |
|
|---|
| 1595 | --
|
|---|
| 1596 |
|
|---|
| 1597 | #pragma parallel
|
|---|
| 1598 | { ...
|
|---|
| 1599 | int i; ...
|
|---|
| 1600 | #pragma for
|
|---|
| 1601 | for (i=...) S(i)
|
|---|
| 1602 | }
|
|---|
| 1603 |
|
|---|
| 1604 | =>
|
|---|
| 1605 |
|
|---|
| 1606 | {
|
|---|
| 1607 | void _tmp1(int _tid) {
|
|---|
| 1608 | int i; ...
|
|---|
| 1609 | {
|
|---|
| 1610 | void _tmp2(int _i) { S(_i) }
|
|---|
| 1611 | int j;
|
|---|
| 1612 | for (j=...) {
|
|---|
| 1613 | int w = $choose_int(numThreads);
|
|---|
| 1614 | }
|
|---|
| 1615 | }
|
|---|
| 1616 | }
|
|---|
| 1617 |
|
|---|
| 1618 |
|
|---|
| 1619 | \end{verbatim}
|
|---|