Skip to content
Snippets Groups Projects
Commit 6e00aa34 authored by Ralf Jung's avatar Ralf Jung
Browse files

docs: finalize non-atomic invariants

parent 1db37236
No related branches found
No related tags found
No related merge requests found
\section{Derived constructions} \section{Derived constructions}
\subsection{Non-atomic invariants} \subsection{Non-atomic (``thread-local'') invariants}
Sometimes it is necessary to maintain invariants that we need to open non-atomically. Sometimes it is necessary to maintain invariants that we need to open non-atomically.
Clearly, for this mechanism to be sound we need something that prevents us from opening the same invariant twice. Clearly, for this mechanism to be sound we need something that prevents us from opening the same invariant twice, something like the masks that avoid reentrancy on the ``normal'', atomic invariants.
Access to these \emph{non-atomic invariants} is thus guarded by tokens that take the role that masks play for ``normal'', atomic invariants. The idea is to use tokens\footnote{Very much like the tokens that are used to encode ``normal'', atomic invariants} that guard access to non-atomic invariants.
Having the token $\NaTokE\pid\mask$ indicates that we can open all invariants in $\mask$.
One way to think about them is as ``thread-local invariants''. The $\pid$ here is the name of the \emph{invariant pool}.
For every thread, we have a set of \emph{tokens}. This mechanism allows us to have multiple, independent pools of invariants that all have their own namespaces.
By giving up a token, you can obtain the invariant, and vice versa.
Such invariants can only be opened by their respective thread, and as a consequence they can be kept open around any sequence of expressions (\ie there is no restriction to atomic expressions). One way to think about non-atomic invariants is as ``thread-local invariants'',
To tie the threads and the tokens together, every thread is assigned a \emph{thread ID}. where every pool is a thread.
Note that these thread IDs are completely fictional, there is no operational aspect to them. Every thread thus has its own, independent set of invariants.
In principle, the tokens could move between threads; that's not an issue at all. Every thread threads through all the tokens for its own pool, so that each invariant can only be opened in the thread it belongs to.
As a consequence, they can be kept open around any sequence of expressions (\ie there is no restriction to atomic expressions) -- after all, there cannot be any races with other threads.
Concretely, this is the monoid structure we need: Concretely, this is the monoid structure we need:
\begin{align*} \begin{align*}
\textdom{TId} \eqdef{}& \nat \\ \textdom{PId} \eqdef{}& \GName \\
\textmon{TTok} \eqdef{}& \textdom{TId} \fpfn \pset{\textdom{InvName}}\\ \textmon{NaTok} \eqdef{}& \finpset{\InvName} \times \pset{\InvName}
\textmon{TDis} \eqdef{}& \textdom{TId} \fpfn \finpset{\textdom{InvName}}
\end{align*} \end{align*}
For every thread, there is a set of tokens designating which invariants are \emph{enabled} (closed). For every pool, there is a set of tokens designating which invariants are \emph{enabled} (closed).
This corresponds to the mask of ``normal'' invariants. This corresponds to the mask of ``normal'' invariants.
We re-use the structure given by namespaces for non-atomic invariants. We re-use the structure given by namespaces for non-atomic invariants.
Furthermore, there is a \emph{finite} set of invariants that is \emph{disabled} (open). Furthermore, there is a \emph{finite} set of invariants that is \emph{disabled} (open).
We assume a global instance $\Gttok$ of \textmon{TTok}, and an instance $\Gtdis$ of $\textmon{TDis}$. Owning tokens is defined as follows:
Then we can define some sugar for owning tokens:
\begin{align*} \begin{align*}
\TTokE\tid\mask \eqdef{}& \ownGhost{\Gttok}{ \mapsingleton\tid\mask : \textmon{TTok} } \\ \NaTokE\pid\mask \eqdef{}& \ownGhost{\pid}{ (\emptyset, \mask) } \\
\TTok\tid \eqdef{}& \TTokE\tid\top \NaTok\pid \eqdef{}& \NaTokE\pid\top
\end{align*} \end{align*}
Next, we define non-atomic invariants. Next, we define non-atomic invariants.
To simplify this construction,we piggy-back into ``normal'' invariants. To simplify this construction,we piggy-back into ``normal'' invariants.
\begin{align*} \begin{align*}
\NaInv\tid\namesp\prop \eqdef{}& \Exists \iname\in\namesp. \knowInv\namesp{\prop * \ownGhost\Gtdis{\set{\iname}} \lor \TTokE\tid{\set{\iname}}} \NaInv\pid\namesp\prop \eqdef{}& \Exists \iname\in\namesp. \knowInv\namesp{\prop * \ownGhost\pid{(\set{\iname},\emptyset)} \lor \NaTokE\pid{\set{\iname}}}
\end{align*} \end{align*}
We easily obtain: We easily obtain:
\begin{mathpar} \begin{mathpar}
\axiom \axiom
{\TRUE \vs[\bot] \Exists\tid. \TTok\tid} {\TRUE \vs[\bot] \Exists\pid. \NaTok\pid}
\axiom \axiom
{\TTokE\tid{\mask_1 \uplus \mask_2} \Lra \TTokE\tid{\mask_1} * \TTokE\tid{\mask_2}} {\NaTokE\pid{\mask_1 \uplus \mask_2} \Lra \NaTokE\pid{\mask_1} * \NaTokE\pid{\mask_2}}
\axiom \axiom
{\later\prop \vs[\namesp] \always\NaInv\tid\namesp\prop} {\later\prop \vs[\namesp] \always\NaInv\pid\namesp\prop}
\axiom \axiom
{\NaInv\tid\namesp\prop \proves \Acc[\namesp]{\TTokE\tid\namesp}{\later\prop}} {\NaInv\pid\namesp\prop \proves \Acc[\namesp]{\NaTokE\pid\namesp}{\later\prop}}
\end{mathpar} \end{mathpar}
from which we can derive from which we can derive
\begin{mathpar} \begin{mathpar}
\infer \infer
{\namesp \subseteq \mask} {\namesp \subseteq \mask}
{\NaInv\tid\namesp\prop \proves \Acc[\namesp]{\TTokE\tid\mask}{\later\prop * \TTokE\tid{\mask \setminus \namesp}}} {\NaInv\pid\namesp\prop \proves \Acc[\namesp]{\NaTokE\pid\mask}{\later\prop * \NaTokE\pid{\mask \setminus \namesp}}}
\end{mathpar} \end{mathpar}
......
...@@ -339,6 +339,9 @@ ...@@ -339,6 +339,9 @@
\newcommand{\physatomic}[1]{\textlog{atomic}($#1$)} \newcommand{\physatomic}[1]{\textlog{atomic}($#1$)}
\newcommand{\infinite}{\textlog{infinite}} \newcommand{\infinite}{\textlog{infinite}}
\newcommand\InvName{\textdom{InvName}}
\newcommand\GName{\textdom{GName}}
\newcommand{\Prop}{\textlog{Prop}} \newcommand{\Prop}{\textlog{Prop}}
\newcommand{\Pred}{\textlog{Pred}} \newcommand{\Pred}{\textlog{Pred}}
...@@ -427,13 +430,11 @@ ...@@ -427,13 +430,11 @@
\newcommand{\mapstoprop}{\mathrel{\kern-0.5ex\tikz[baseline=(m)]{\node at (0,0) (m){}; \draw[line cap=round] (0,0.16) -- (0,-0.004);}\kern-1.5ex\Ra}} \newcommand{\mapstoprop}{\mathrel{\kern-0.5ex\tikz[baseline=(m)]{\node at (0,0) (m){}; \draw[line cap=round] (0,0.16) -- (0,-0.004);}\kern-1.5ex\Ra}}
% Non-atomic invariants % Non-atomic invariants
\newcommand*\Gttok{\gname_\textrm{TTok}} \newcommand*\pid{p}
\newcommand*\Gtdis{\gname_\textrm{TDis}} \newcommand\NaInv[3]{\textlog{NaInv}^{#1.#2}(#3)}
\newcommand*\tid{t}
\newcommand\NaInv[3]{\textlog{NAInv}^{#1.#2}(#3)}
\newcommand*\TTok[1]{{[}\textrm{T}:#1{]}} \newcommand*\NaTok[1]{{[}\textrm{NaInv}:#1{]}}
\newcommand*\TTokE[2]{{[}\textrm{T}:#1.#2{]}} \newcommand*\NaTokE[2]{{[}\textrm{NaInv}:#1.#2{]}}
\endinput \endinput
...@@ -27,8 +27,8 @@ To instantiate the program logic, the user picks a family of locally contractive ...@@ -27,8 +27,8 @@ To instantiate the program logic, the user picks a family of locally contractive
From this, we construct the bifunctor defining the overall resources as follows: From this, we construct the bifunctor defining the overall resources as follows:
\begin{align*} \begin{align*}
\mathcal G \eqdef{}& \nat \\ \GName \eqdef{}& \nat \\
\textdom{ResF}(\ofe^\op, \ofe) \eqdef{}& \prod_{i \in \mathcal I} \mathcal G \fpfn \iFunc_i(\ofe^\op, \ofe) \textdom{ResF}(\ofe^\op, \ofe) \eqdef{}& \prod_{i \in \mathcal I} \GName \fpfn \iFunc_i(\ofe^\op, \ofe)
\end{align*} \end{align*}
We will motivate both the use of a product and the finite partial function below. We will motivate both the use of a product and the finite partial function below.
$\textdom{ResF}(\ofe^\op, \ofe)$ is a CMRA by lifting the individual CMRAs pointwise, and it has a unit (using the empty finite partial functions). $\textdom{ResF}(\ofe^\op, \ofe)$ is a CMRA by lifting the individual CMRAs pointwise, and it has a unit (using the empty finite partial functions).
...@@ -112,10 +112,10 @@ To this end, we use tokens that manage which invariants are currently enabled. ...@@ -112,10 +112,10 @@ To this end, we use tokens that manage which invariants are currently enabled.
We assume to have the following four CMRAs available: We assume to have the following four CMRAs available:
\begin{align*} \begin{align*}
\mathcal I \eqdef{}& \nat \\ \InvName \eqdef{}& \nat \\
\textmon{Inv} \eqdef{}& \authm(\mathcal I \fpfn \agm(\latert \iPreProp)) \\ \textmon{Inv} \eqdef{}& \authm(\InvName \fpfn \agm(\latert \iPreProp)) \\
\textmon{En} \eqdef{}& \pset{\mathcal I} \\ \textmon{En} \eqdef{}& \pset{\InvName} \\
\textmon{Dis} \eqdef{}& \finpset{\mathcal I} \\ \textmon{Dis} \eqdef{}& \finpset{\InvName} \\
\textmon{State} \eqdef{}& \authm(\maybe{\exm(\State)}) \textmon{State} \eqdef{}& \authm(\maybe{\exm(\State)})
\end{align*} \end{align*}
The last two are the tokens used for managing invariants, $\textmon{Inv}$ is the monoid used to manage the invariants themselves. The last two are the tokens used for managing invariants, $\textmon{Inv}$ is the monoid used to manage the invariants themselves.
...@@ -126,7 +126,7 @@ We assume that at the beginning of the verification, instances named $\gname_{\t ...@@ -126,7 +126,7 @@ We assume that at the beginning of the verification, instances named $\gname_{\t
\paragraph{World Satisfaction.} \paragraph{World Satisfaction.}
We can now define the assertion $W$ (\emph{world satisfaction}) which ensures that the enabled invariants are actually maintained: We can now define the assertion $W$ (\emph{world satisfaction}) which ensures that the enabled invariants are actually maintained:
\begin{align*} \begin{align*}
W \eqdef{}& \Exists I : \mathcal I \fpfn \Prop. W \eqdef{}& \Exists I : \InvName \fpfn \Prop.
\begin{array}[t]{@{} l} \begin{array}[t]{@{} l}
\ownGhost{\gname_{\textmon{Inv}}}{\authfull \ownGhost{\gname_{\textmon{Inv}}}{\authfull
\mapComp {\iname} \mapComp {\iname}
...@@ -471,8 +471,8 @@ We use the notation $\namesp.\iname$ for the namespace $[\iname] \dplus \namesp$ ...@@ -471,8 +471,8 @@ We use the notation $\namesp.\iname$ for the namespace $[\iname] \dplus \namesp$
The elements of a namespaces are \emph{structured invariant names} (think: Java fully qualified class name). The elements of a namespaces are \emph{structured invariant names} (think: Java fully qualified class name).
They, too, are lists of $\nat$, the same type as namespaces. They, too, are lists of $\nat$, the same type as namespaces.
In order to connect this up to the definitions of \Sref{sec:invariants}, we need a way to map structued invariant names to $\mathcal I$, the type of ``plain'' invariant names. In order to connect this up to the definitions of \Sref{sec:invariants}, we need a way to map structued invariant names to $\InvName$, the type of ``plain'' invariant names.
Any injective mapping $\textlog{namesp\_inj}$ will do; and such a mapping has to exist because $\List(\nat)$ is countable and $\mathcal I$ is infinite. Any injective mapping $\textlog{namesp\_inj}$ will do; and such a mapping has to exist because $\List(\nat)$ is countable and $\InvName$ is infinite.
Whenever needed, we (usually implicitly) coerce $\namesp$ to its encoded suffix-closure, \ie to the set of encoded structured invariant names contained in the namespace: \[\namecl\namesp \eqdef \setComp{\iname}{\Exists \namesp'. \iname = \textlog{namesp\_inj}(\namesp' \dplus \namesp)}\] Whenever needed, we (usually implicitly) coerce $\namesp$ to its encoded suffix-closure, \ie to the set of encoded structured invariant names contained in the namespace: \[\namecl\namesp \eqdef \setComp{\iname}{\Exists \namesp'. \iname = \textlog{namesp\_inj}(\namesp' \dplus \namesp)}\]
We will overload the notation for invariant assertions for using namespaces instead of names: We will overload the notation for invariant assertions for using namespaces instead of names:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment