Verification of Durable Linearizability of a Persistent Queue

This Website documents KIV-proofs done for the paper [FM19].

The formal proofs make use of a library that contains a formalization of much of the refinement theory of IO-Automata from [LV95]. The specifications imported from this library contain

.

The proofs benefit from an automated transformation of programs to a standard IO-Automaton, that is programmed in KIV. Based on this transformation, the proofs consist of three major parts, that are part of the main project.

We describe the construction of the automaton, and the three proof steps in the following subsections.

Construction of a standard automaton from programs

The main part of the specification DMSQaux is the definition of two procedures ENQ and DEQ that follow the description of Algorithm 2 in [FM19]. Please ignore the RUN routine. It is defined solely to introduce the three extra program counter values S, I and C (the final automaton constructed will override the steps of RUN). Note that the line numbers (= program counter values) are slightly different than the ones given in the paper. Assertions which hold at a specific line number are given with /* and */ or below the code if they hold for ranges of program counter values. The syntax is similar to the one of the paper, but there are some small discrepancies. The declaration of the programs generates an IO Automaton with the following components (the generated specifications are all shown below the main specification).

Proof obligations for assertions in the programs

The lines of the programs are annotated with assertions. The assertions are combined with the invariants given below the code. Invariants without a list of pc's are added (by conjunction) to all assertions. They are global invariants that are proven to hold in every state reachable by the automaton (even when no thread is currently executing one of the programs), so they depend on global state only. They are collected in the definition of predicate "DMSQauxGInv". Assertions with a range of pc's are added to the assertion of each pc within the range. Note that assertions are checked to mention only those local variables, which are defined at the respective program line. The assertions are collected to define a (rather large) predicate "DMSQauxLinv(gs, ls, pc)". Its definition is a big conjunction of formulas of the form "pc = <pcvalue> -> <assertion at pcvalue>". The generated proof obligations guarantee that "DMSQauxLinv(gs, lsf(tid), pcf(tid))" holds for all threads in every state of the automaton (together the full invariant "DMSQauxInv(gs, lsf, pcf)" is implied to hold in every reachable state. Below the program and the invariants a rely condition is specified. From this formula the definition for predicate "DMSQauxRely(gs, tid, gs0)" is generated. Using a rely condition avoids the quadratic complexity inherent in Owicki-Gries style proofs. The following proof obligations are generated in the theorembase of specification DMSQaux for every step of the program, to ensure that DMSQauxInv holds: For the concrete algorithm, the relevant predicates needed to define its invariants and rely condition are defined at the beginning of the specification. We give an informal description of the main "listp" -predicate first (for a pictorial description see also Fig. 2 in [FM19]), and then go through the other predicates.

Augmenting the automaton with global steps

The automaton DMSQaux defined above has program steps only. It does not have crashes or flushing steps done by the operating system. The actions of DMSQaux also do not match the actions of the abstract specification. We therefore define a new automaton DMSQ with a step relation, that augments the one of DMSQaux with global steps. To enable an elegant refinement proof, where steps of the concrete automaton match abstract actions 1:1, so an elegant refinement proof becomes possible, we also change the actions to match the actions of the abstract specification. Note that the modifications affect internal actions only (which do not affect, whether refinement holds), the external invoke- and return-actions for ENQ and DEQ remain untouched. To describe DMSQ we first give a short description of the abstract specification DQ, which is also described as automaton IDQ in Fig. 3 of [FM19]. The specification defines a state with three components Its actions as specified in DQaction are as in [FM19], except for notation: "res_t(Deq,v)" is written retDeq(tid, Val(v))" for a nonempty value v here. The step relation "DQstep" defined in DQ consists of a global part for stuttering steps and crashes, and a local part for steps done by a single thread. Since the local step relation is very simple for each action, we directly specify a relation "DQlstep" without splitting into a precondition and an effect as in the paper.

The actions of DQ are also used in DMSQ. To this purpose we map the original actions "ca" of DMSQaux with "ca.toQ(gs,ps,ls)" to actions of DQ. invoke and return actions for ENQ and DEQ are mapped by identity. Actions "invRun" and "retRun" (and their corresponding steps) are deleted and replaced with the run(tid) and crash steps. For all the internal steps function the axiom for ".toQ" has to carefully specify the action needed at persistence points:

The steps of DMSQ are The initialisation predicate DMSQinit is the same as the one of DMSQaux except that all threads with pcf(tid) = S (aka "idle"). The main theorem proven is that like DMSQaux, DMSQ also satisfies the invariant DMSQauxINV.

Refinement proof

The refinement proof uses the forward simulation (the general definition allows one concrete step to match several abstract ones, as long as the external actions are the same; we do not need this generality here, since we have ensured internal actions match 1:1) defined in specification abs. The definition of predicate abs specifies four properties: The simulation proof in DMSQ-refines-DQ consists of proving the (trivial) initialization condition and the (complex) proof of a commuting diagram for each step. This proof is broken down into several subproofs:

Back to the overview of all KIV projects.
For general informations on KIV and a download site for the whole system refer to this page.


Bibliography

[FM19] J. Derrick, S. Doherty, B. Dongol, G. Schellhorn, H. Wehrheim.
Verifying Correctness of Persistent Concurrent Data Structures
(FM 2019, Springer LNCS)

[PPoPP18]    M. Friedman, M. Herlihy, V. J. Marathe, E. Petrank.
A persistent lock-free queue for non-volatile memory.
(PPoPP 2018, pp. 28--40, ACM)

[LV95] N. Lynch, F. Vaandrager
Forward and Backward Simulations -- Part I: Untimed systems
(Information and Computation 1995, vol. 121(2), p. 214--233)