\subsection{Specification under sequential consistency} \label{sec:queue:spec:sc} We now consider a situation where several threads can access the queue concurrently. Let us assume for now that the memory model is sequentially consistent~\cite{lamport-79}. % In a seminal work, \citet{brookes-04} and \citet{ohearn-07} devised \CSL, an extension of \SL which enables to reason about programs where several threads can access a same piece of memory. Though the original logic achieves sharing through hard-wired ``conditional critical regions'', it has spawned a variety of descendants lifting this limitation and pushing further the applicability of such separation logics. % applicability / expressiveness / generality In this work, we use Iris~\cite{iris}, a modular framework for building separation logics. In a derivative of \CSL, we may retain the exact same specification as is presented in~\fref{fig:queue:spec:seq}, recalling that $\isQueueSEQ\elemList$ is an exclusive assertion: a thread that has this assertion can safely assume to be the only one allowed to operate on the queue. % A client application can transfer this assertion between threads via some means of synchronization: for instance, it may use a lock to guard all operations on the shared queue, following the approach of \CSL. % However this coarse grain concurrency has a run-time penalty, and it also creates some contention on the use of the queue. % These costs are often unnecessary, as many data~structures are designed specifically to support concurrent accesses. In this paper, as stated, we wish to prove the correctness of a MRMW~queue implementation, which should thus ensure, by itself, thread safety. % Hence we can achieve finer-grain concurrency, where operating on a queue does not require its exclusive ownership. In this context, another option is for the client to share this ownership among several threads, logically. In an Iris-like logic, one would typically place the exclusive ownership in an \emph{invariant}. %---alongside the properties about the public state which are needed by the particular application. An invariant is an assertion which is agreed upon by all threads, and is owned by anyone; it remains true forever. % % GLEN: digression (on introduit le vocabulaire "public state" ici): As the public state of the queue---the list $\elemList$ of currently stored items---would only be known from that invariant, the client would also express in there the properties about this state that their particular application needs. % Then, when one of the threads needs to access the shared resource, it can \emph{open} the invariant, get the assertions it contains, perform the desired operation on the shared state, reestablish the invariant, and finally close it. % However, to ensure soundness in the face of concurrency, the use of invariants in Iris obeys a strict constraint: they can remain open during at most a single step of execution. Unfortunately, $\enqueue$ and $\dequeue$ are complex operations which, \emph{a~priori}, take more than one step of execution. Hence a client would be unable to open their invariant around the triples shown in~\fref{fig:queue:spec:seq}. Yet these operations are ``atomic'' in some empirical sense. The concept of logical atomicity~\cite[\S7]{jung-slides-2019,iris-15} aims at addressing that difficulty. To use it, we substitute ordinary Hoare triples with \emph{logically atomic triples}. Just like ordinary triples, they specify a program fragment with a precondition and a postcondition. The core difference is that invariants can be opened around a logically atomic triple, regardless of the number of execution steps of the program fragment: in a sense, when a function is specified using a logically atomic triple, one states that said function behaves as if it were atomic. % The definition of logically atomic triples is further discussed in~\sref{sec:queue:proof:la} and given with detail in previous work~\cite[\S7]{jung-slides-2019,iris-15}. We now try to give an intuition on that concept: a logically atomic triple $\lahoare{P}{e}{Q}$ states, roughly, that the expression $e$ contains a linearization point which has $P$ as a precondition and $Q$ as a postcondition. The triple then allows the opening of invariants around that linearization point because it is an atomic instruction. % \begin{mathpar} % \infer[LAHoare]{% using the rule names from \cite{iris-15} \lahoare {P} {e} {Q} }{% \Forall x. \hoare {P} {e} {Q} } \infer[LAInv]{% using the rule names from \cite{iris-15} \lahoare {\later I \isep P} {e} {\later I \isep Q} }{% \knowInv{}{I} \vdash \lahoare {P} {e} {Q} } % \end{mathpar} % TODO: faire référence aux règles ci-dessus dans le texte. % mentionner qu’un triplet log. atomique implique le triplet usuel ? (1re règle) % peut-être enlever le binder à cet endroit. % TODO : expliquer la syntaxe des invariants, dire que \later est une technicité d'Iris % JH : le mieux, c'est peut-être de mettre ces règles dasn une figure, et de s'y référer à plusieurs endroits: % 1- regardez, on peut ouvrir des invariants autour d'un triplet logiquement atomique (oubliez le binder pour l'instant) % 2- maintenant que je vous ai expliqué ce que c'est ce binder, vous voyez, il apparaît dans la syntax % 3- tout à la fin de 2.2.2, on peut parler de transformer un triplet logiquement atomique en triplet de Hoare au moment où on parle de déduire la spec à base de \Phi. % 3bis- Si on décide de ne pas parler de la spec à base de \Phi au début du paragraphe, soit on en parle à la fn de 2.2.2, parce que ça fait un bon exemple Using logically atomic triples, the specification can be written as shown in~\fref{fig:queue:spec:sc}. It closely resembles that of the sequential setting (\fref{fig:queue:spec:seq}). The first noticeable difference is the use of angle brackets~$\anglebracket{\ldots}$ denoting logically atomic triples instead of curly brackets~$\curlybracket{\ldots}$ for ordinary Hoare triples. Another difference is the presence, in the syntax of logically atomic triples, of an explicit binder for some variables ($\nbelems, \elemList*[]$). This binder addresses a subtlety of logical atomicity: a client calling \enqueue or \dequeue does not know in advance the state of the queue at the linearization point, which is when the precondition and postcondition are to be interpreted. Hence, both formulas have to be parameterized by said shared state. Said otherwise, a logically atomic triple provides a \emph{family} of pre/postcondition pairs covering every possible shared state at the linearization point. The last departure from the sequential specification is that the representation predicate is split into two parts: a persistent assertion~$\queueInv$ and an exclusive assertion $\isQueueSC\elemList$, connected by a ghost name~$\gqueue$. That splitting is an artifact of our correctness proof technique, which we detail in~\sref{sec:queue:proof}. % GLEN: 1re fois qu’on parle d’assertions persistantes , définir le terme ici. % Note that this does not complicate the use of the queue by the client: both assertions are produced when creating the queue, and while the exclusive component can be put in an invariant as before, the persistent component can be directly duplicated and distributed to all threads. % TODO : pour après la soumission : expliquer pourquoi QueueInv n'est pas caché dans IsQueue (footnote pour les experts d'Iris : ça rendrait IsQueue non timeless, et on aurait une étape "abort" au début de enqueue/dequeue => pas impossible, mais plus compliqué) The use of such a specification in a concrete example will be detailed in~\sref{sec:pipeline:proof}. For now, we illustrate how a weaker specification can be easily deduced from this one. % ------------------------------------------------------------------------------ \subsubsection{A Persistent Specification} \label{sec:queue:spec:sc:persistent} If it were not for logical atomicity, and we still wanted to share the ownership of the queue, we would have little choice left than renouncing to an exclusive representation predicate. Only a persistent assertion would be provided, because the description of the public state has to be stable in the face of interference by other threads. The resulting specification would be much weaker. % For example, we may merely specify that all of the elements stored in the queue satisfy some predicate~$\Phi$. In doing so, we lose most structural properties of a queue: the same specification could also describe a stack or a bag. % \begin{mathpar} % \infer{~}{% \persistent{\isQueuePers\Phi} } \quad \infer{% \isQueuePers\Phi }{% \hoare {\Phi\,\elem} {\enqueue~\queue~\elem} {\Lam \Unit. \TRUE} } \quad \infer{% \isQueuePers\Phi }{% \hoare {\TRUE} {\dequeue~\queue} {\Lam \elem. \Phi\,\elem} } % \end{mathpar} To derive these Hoare triples from the ones of~\fref{fig:queue:spec:sc}, one simply defines the persistent assertion as follows, where the boxed assertion is an Iris invariant: % \[ \isQueuePers\Phi \;\eqdef\; \Exists\gqueue. \ISep{% \queueInv \\ \knowInv{}{\Exists \nbelems, \elemList*[]. \isQueueSC\elemList \isep \Phi\,\nthElem{0} \isep \cdots \isep \Phi\,\nthElem{\nbelems-1}} } \] This assertion is trivial to produce at the creation of the queue, when \make hands us the assertions $\queueInv$ and $\isQueueSC{[]}$. Then, for proving the weaker specification of $\enqueue$ and $\dequeue$, one opens the invariant around the associated logically atomic triples.