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