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