A Separation Logic to Verify Termination of Busy-Waiting for Abrupt Program Exit: Technical Report
AA Separation Logic to Verify Termination ofBusy-Waiting for Abrupt Program Exit:Technical Report
Tobias ReinhardKU Leuven Amin TimanyAarhus University Bart JacobsKU Leuven22nd July 2020
Abstract
Programs for multiprocessor machines commonly perform busy-waitingfor synchronisation. In this paper, we make a first step towards provingtermination of such programs. We approximate (i) arbitrary waitableevents by abrupt program termination and (ii) busy-waiting for events bybusy-waiting to be abruptly terminated.We propose a separation logic for modularly verifying termination (un-der fair scheduling) of programs where some threads eventually abruptlyterminate the program, and other threads busy-wait for this to happen.
Contents a r X i v : . [ c s . L O ] J u l Introduction
Programs for multiprocessor machines commonly perform busy-waiting for syn-chronisation M¨uhlemann [1980], Mellor-Crummey and Scott [1991], Rahman[2012]. In this paper, we make a first step towards proving termination of suchprograms. Specifically, we propose a separation logic Reynolds [2002], O’Hearnet al. [2001] for modularly verifying termination (under fair scheduling) of pro-grams where some threads eventually abruptly terminate the program, and otherthreads busy-wait for this to happen.Here, by modular we mean that we reason about each thread and eachfunction in isolation. That is, we do not reason about thread scheduling orinterleavings. We only consider these issues when proving the soundness of ourlogic.In this work, we approximate (i) arbitrary events that a program might waitfor by abrupt termination and (ii) busy-waiting for events by busy-waiting to beabruptly terminated. In Section 6, we sketch preliminary ideas for generalizingthis to verifying termination of busy-waiting for arbitrary events, and how thiswork may also be directly relevant to verifying liveness properties of a program’sI/O behaviour.Throughout this paper we use a very simple programming language to illus-trate our verification approach. Its simplicity would allow us to verify termin-ation of busy-waiting for abrupt termination via a static analysis significantlysimpler than the proposed separation logic. However, in contrast to such ananalysis, our approach is also applicable to realistic languages. Furthermore,we are confident that the logic we propose can be combined with existing con-current separation logics like Iris Jung et al. [2018] to verify termination ofbusy-waiting.We start by introducing the programming language in Section 2 and continuein Section 3 with presenting the separation logic and so-called obligations and credits
Hamin and Jacobs [2019, 2018], Leino et al. [2010], Kobayashi [2006],which we use to reason about termination of busy-waiting. In Section 4 wepresent our verification approach in the form of a set of proof rules and illustratetheir application. Afterwards, we prove the soundness of our proof system inSection 5. We conclude by outlining our plans for future work, comparing ourapproach to related work and reflecting on our approach in Sections 6, 7 and 8.
We consider a simple programming language with an exit command that ab-ruptly terminates all running threads, a fork command, a looping construct loop skip to express infinite busy-waiting loops and sequencing c ; c . Definition 2.1 (Commands and Continuations) . We denote the sets of com-mands c and continuations κ as defined by the grammar presented in Figure 1by Cmds and K . We consider sequencing · ; · as defined in the grammars ofcommands and continuations to be right-associative. ∈ Cmds ::= exit | loop skip | fork c | c ; cκ ∈ K ::= done | c ; κ Figure 1: SyntaxWe use commands and continuations to represent programs and single threads,respectively, as well as natural numbers for thread IDs. Continuation done marks the end of a thread’s execution. We consider thread pools to be func-tions mapping a finite set of thread IDs to continuations.
Definition 2.2 (Thread Pools) . We define the set of thread pools TP as follows TP := { P : Θ → K | Θ ⊂ fin N } . We denote thread pools by P , thread IDs by θ and the empty thread pool by ∅ tp : ∅ → K . Definition 2.3 (Thread Pool Extension) . Let P : Θ → K ∈ TP be a threadpool. We define: • P + tp ∅ := P , • P + tp { κ } : Θ ∪ { max(Θ) + 1 } → K with ( P + tp { κ } )( θ ) = P ( θ ) for all θ ∈ Θ and ( P + tp { κ } )(max(Θ) + 1) = κ , • P − tp θ (cid:48) : Θ \ { θ (cid:48) } → K with ( P − tp θ (cid:48) )( θ ) = P ( θ )We consider a standard small-step operational semantics for our languagedefined in terms of two reduction relations: (i) (cid:32) st for single thread reductionsteps and (ii) (cid:32) tp for thread pool reduction steps. Definition 2.4 (Single-Thread Reduction Relation) . We define a single-threadreduction relation (cid:32) st according to the rules presented in Figure 2. A reductionstep has the form κ (cid:32) st κ (cid:48) , T for a set of forked threads T ⊂ K with | T | ≤ . Definition 2.5 (Thread Pool Reduction Relation) . We define a thread poolreduction relation (cid:32) tp according to the rules presented in Figure 3. A reductionstep has the form P θ (cid:32) tp P (cid:48) for a thread ID θ ∈ dom( P ) . edST-Loop loop skip ; κ (cid:32) st loop skip ; κ, ∅ RedST-Fork fork c ; κ (cid:32) st κ, { c ; done } RedST-Seq ( c ; c ); κ (cid:32) st c ; ( c ; κ ) , ∅ Figure 2: Reduction rules for single threads.
RedTP-Lift θ ∈ dom( P ) P ( θ ) = κ κ (cid:32) st κ (cid:48) , TP θ (cid:32) tp P [ θ := κ (cid:48) ] + tp T RedTP-Exit θ ∈ dom( P ) P ( θ ) = exit ; κP θ (cid:32) tp ∅ tp RedTP-ThreadTerm θ ∈ dom( P ) P ( θ ) = done P θ (cid:32) tp P − tp θ Figure 3: Reduction rules for thread pools.
Termination Terminology
According to reduction rule
RedTP-Exit , com-mand exit terminates all running threads by clearing the entire thread pool. Wecall this abrupt termination to differentiate it from normal termination when athread first reduces to done and is then removed from the thread pool via rule
RedTP-ThreadTerm . The term termination encompasses both abrupt and normal termination.Figure 4 illustrates the type of programs we aim to verify. The code snip-pet spawns a new thread which will abruptly terminate the entire program andthen busy-waits for the program to be terminated. The operational semanticsdefined above is non-deterministic in regard to when and if threads are sched-uled. Meanwhile, the presented program only terminates if the exiting threadis eventually scheduled. Hence, we need to assume fair scheduling.
Definition 2.6 (Reduction Sequence) . Let ( P i ) i ∈ N be a sequence of thread poolssuch that P i θ i (cid:32) tp P i +1 holds for all i ∈ N and some sequence ( θ i ) i ∈ N of threadIDs. Then we call ( P i ) i ∈ N a reduction sequence . Note that according to this definition, all reduction sequences are implicitlyinfinite. fork exit ; loop skip Figure 4: Example program with two threads: An exiting thread and one wait-ing for the program to be abruptly terminated.4 ∈ A ::=
True | False | a ∗ a | obs ( n ) | credit n ∈ N Figure 5: Syntax of assertions.
Definition 2.7 (Fairness) . We call a reduction sequence ( P i ) i ∈ N fair iff for all k ∈ N and θ k ∈ dom( P k ) there exists j ≥ k such that P j θ k (cid:32) tp P j +1 . In this paper, we develop a separation logic to reason about termination of busy-waiting programs. Separation logic is designed for reasoning about programresources as well as ghost resources Reynolds [2002], O’Hearn et al. [2001]. Thelatter is information attached to program executions for the purpose of programverification, e.g., a resource tracking how many threads have access to a sharedmemory location Jung et al. [2016]. Here, we use ghost resources to track whichthread will eventually exit , i.e., abruptly terminate the entire program.
Obligations & Credits
Remember that exit terminates all running threads.Therefore, in order to modularly reason about program termination we needinformation about other threads performing exit .For this purpose, we introduce two kinds of ghost resources: obligations and credits . Threads holding an obligation are required to discharge it by performing exit while threads holding a credit are allowed to busy-wait for another threadto exit . As seen in the next section we ensure that no thread (directly orindirectly) waits for itself.We aggregate obligations into obligations chunks, where each obligationschunk collects the held obligations of a single thread.
Assertions
The language of assertions defined in the following allows us toexpress knowledge and assumptions about held obligations and credits. Thelanguage contains the standard separating conjunction · ∗ · as well as two non-standard predicates obs and credit to express the possession of ghost resources.(i) obs ( n ) expresses the possession of one obligations chunk containing n exit obligations; i.e., it expresses that the current thread holds n exit obligations .(ii) credit expresses the possession of an exit credit that can be used to busy-waitfor another thread to exit . Definition 3.1 (Assertions) . Figure 5 defines the set of assertions A . As outlined in Section 6, we plan to extend this logic to one where threads are obligedto set ghost signals. This makes it necessary to track the number of signals that remain to beset. Hence, we track the number of obligations. (cid:15) A True R (cid:15) A a ∗ a iff ∃ R , R ∈ R . R = R (cid:93) R R ∧ R (cid:15) A a ∧ R (cid:15) A a ( O, χ ) (cid:15) A obs ( o ) iff o ∈ O ( O, χ ) (cid:15) A credit iff χ ≥ obs -predicate captures a full obligations chunk and that this chunk can only besplit when obligations are passed to a newly forked thread. We represent theinformation about the held obligations chunks and credits by resource bundles( O, χ ). Definition 3.2 (Resource Bundles) . We define the set of resource bundles R as R := Bags ( N ) × N . Let ( O , χ ) , ( O , χ ) ∈ R . We define ( O , χ ) (cid:93) R ( O , χ ) := ( O (cid:93) O , χ + χ ) . Threads hold exactly one obligations chunk, i.e., resources (
O, χ ) with | O | =1. We call such resource bundles complete . Definition 3.3 (Complete Resource Bundles) . We call a resource bundle ( O, χ ) ∈R complete if | O | = 1 holds and write complete (( O, χ )) . Note that the following definition indeed ensures that the obs -predicate cap-tures a full obligations-chunk. Hence, no bundle with one obligations chunk cansatisfy an assertion of the form obs ( n ) ∗ obs ( n (cid:48) ). Definition 3.4 (Assertion Model Relation) . Figure 6 defines the assertionmodel relation (cid:15) A ⊆ R × A . We write R (cid:15) A a to express that resource bundle R ∈ R models assertion a ∈ A . In this section we present the proof system we propose for verifying terminationof programs with busy-waiting for abrupt program exit and illustrate its ap-plication. Further, we present a soundness theorem stating that every program,which provably discharges all its exit obligations and starts without credits,terminates. 6
S-ObCred obs ( o ) (cid:87)(cid:86) obs ( o + 1) ∗ credit VS-SemImp ∀ R. R (cid:15) A A → R (cid:15) A BA (cid:86) B VS-Trans A (cid:86) C C (cid:86) BA (cid:86) B Figure 7: View shift rules.
Hoare Triples
We use Hoare triples { A } c { B } Hoare [1968] to specify thebehaviour of programs. Such a triple expresses that given precondition A , com-mand c can be reduced without getting stuck and if this reduction terminates,then postcondition B holds afterwards. In particular, a triple { A } c { False } expresses that c diverges or exits abruptly. Ghost Steps
When verifying the termination of a program c , we consider it tostart without any obligations or credits, i.e., { obs (0) } c { B } . Obligation-creditpairs can, however, be generated during so-called ghost steps . These are stepsthat exclusively exist on the verification level and only affect ghost resources,but not the program’s behaviour Jung et al. [2018], Filliˆatre et al. [2016]. Acredit can also be cancelled against an obligation. View Shift
In our proofs, we need to capture ghost steps as well as drawingconclusions from assertions, e.g., rewriting A ∗ B into B ∗ A and concluding obs (0) from the assumption False . We ensure this by introducing a view shiftrelation (cid:86)
Jung et al. [2018]. A view shift A (cid:86) B expresses that whenever A holds, then either (i) B also holds or (ii) B can be established by performingghost steps. A (cid:87)(cid:86) B stands for A (cid:86) B ∧ B (cid:86) A . Definition 4.1 (View Shift) . We define the view shift relation (cid:86) ⊂ A × A according to the rules presented in Figure 7.
Note that view shifts only allow to spawn or remove obligations and creditssimultaneously. This way, we ensure that the number of obligations and cred-its in the system remains equal at any time (provided this also holds for theprogram’s initial state).
Proof Rules
We verify program specifications { A } c { B } via a proof relation (cid:96) defined by a set of proof rules. These rules are designed to prove that everycommand c , which provably discharges its obligations, i.e., (cid:96) { obs ( n ) } c { obs (0) } ,terminates under fair scheduling. Definition 4.2 (Proof Relation) . We define a proof relation (cid:96) for Hoare triples { A } c { B } according to the rules presented in Figure 8. Obligation-credit pairs can be generated and removed via a ghost step byapplying
PR-ViewShift plus
VS-ObCred . The only way to discharge anobligation, i.e., removing it without simultaneously removing a credit, is via7
R-Frame (cid:96) { A } c { B }(cid:96) { A ∗ F } c { B ∗ F } PR-Exit (cid:96) { A } exit { False } PR-Loop (cid:96) { obs (0) ∗ credit } loop skip { False } PR-Fork (cid:96) { obs ( o f ) ∗ A } c { obs (0) }(cid:96) { obs ( o m + o f ) ∗ A } fork c { obs ( o m ) } PR-Seq (cid:96) { A } c { B } (cid:96) { B } c { C }(cid:96) { A } c ; c { C } PR-ViewShift A (cid:86) A (cid:48) (cid:96) { A (cid:48) } c { B (cid:48) } B (cid:48) (cid:86) B (cid:96) { A } c { B } Figure 8: Proof rules.rule
PR-Exit . That is, a discharging program (cid:96) { obs (1) } c { obs (0) } , mustinvolve an abrupt exit at some point.We can pass obligations and credits to newly forked threads by applying PR-Fork . However, note that in order to prove anything about a command fork c , we need to prove that the forked thread discharges or cancels all of itsobligations.The only way to justify busy-waiting is via PR-Loop , which requires thepossession of a credit. Note that the rule forbids the looping thread to hold anyobligations. This ensures that threads do not busy-wait for themselves to exit . Example
Consider the program c ex = fork exit ; loop skip presented in Fig-ure 4. It forks a new thread instructed to exit and busy-waits for it to do so. Wecan verify its termination under fair scheduling by proving (cid:96) { obs (0) } c ex { obs (0) } .Figure 9 sketches this proof. Note that the assumption of fair scheduling is es-sential, since otherwise we would have no guarantees that the exiting thread isever executed.The following soundness theorem states that we can prove termination ofa program c under fair scheduling by proving that it discharging all its exit obligations, i.e., (cid:96) { obs ( n ) } c { obs (0) } . By such a proof we verify that nofair infinite reduction sequence of c exists. That is, the reduction eventuallyterminates, either abruptly via exit or normally. Theorem 4.3 (Soundness) . Let (cid:96) { obs ( n ) } c { obs (0) } . There exists no fairreduction sequence ( P i ) i ∈ N starting with P = { ( θ , c ; done ) } for any θ ∈ N . obs (0) }{ obs (1) ∗ credit } PR-ViewShift + VS-ObCred fork
PR-Fork { obs (1) } exit ; PR-Exit { False }{ obs (0) } PR-ViewShift + VS-SemImp { obs (0) ∗ credit } loop skip PR-Loop { False }{ obs (0) } PR-ViewShift + VS-SemImp
Figure 9: Verification sketch for a program with two threads: An exiting threadand one busy-waiting for abrupt termination. Applied proof rules are high-lighted in violet.
Proving Soundness Theorem 4.3 requires us to establish a connection betweenour proof relation (cid:96) and the operational semantics, i.e., the thread pool reduc-tion relation (cid:32) tp . Bridging the Gap
According to our proof rules, ghost resources are notstatic but affected by the commands occurring in a program. For instance,forking allows us to pass resources to the newly forked thread and exiting dis-charges obligations (cf. proof rules
PR-Fork and
PR-Exit + PR-ViewShift in Figures 8 and 7). We capture the connection between ghost resources andprogram executions by annotating threads with resource bundles and introdu-cing an annotated operational semantics mimicking the resource manipulationapparent in our proof rules.In our proof rules we used Hoare triples { A } c { B } to specify the behaviour ofa program c . We interpret such triples in a model relation (cid:15) H , which we define interms of the annotated semantics. Intuitively, (cid:15) H { A } c { B } expresses that givenany resource bundle fulfilling precondition A , we can reduce command c in theannotated semantics without getting stuck. In case the reduction terminatesnormally (i.e., in case it neither diverges nor exits abruptly), postcondition B holds afterwards. Note that this interpretation complies with the intuitionbehind our proof rules.We prove our proof relation (cid:96) sound with respect to our model relation (cid:15) H ,i.e., we show that (cid:96) { A } c { B } implies (cid:15) H { A } c { B } , and establish a connectionbetween the annotated and the plain semantics. This establishes the missinglink between our proof rules and program executions and thereby allows us toprove the soundness theorem. 9 .1 Annotated Executions We use ghost resources to track which threads are obliged to exit , and which areallowed to busy-wait for another thread to do so. In order to associate threadswith their respective ghost resources, we introduce an annotated version ofthread pools.
Definition 5.1 (Annotated Thread Pools) . We define the set of annotatedthread pools TP a as follows TP a := { P a : Θ → R × K | Θ ⊂ fin N } . We denote annotated thread pools by P a and the empty annotated thread pool by ∅ atp : ∅ → R × K . Furthermore, we define an extension operation + atp anda removal operation − atp analogously to + tp and − tp , respectively, cf. Defini-tion 2.3. As it becomes apparent in the proof rules, a thread’s resources are not staticbut affected by the thread’s actions. For instance, threads can spawn obligation-credit pairs and pass some of their held resources to newly forked threads (cf.proof rules
PR-ViewShift & VS-ObCred , PR-Fork in Figures 8 and 7). Tomake this precise, we define annotated versions (cid:32) ast and (cid:32) atp of the reductionrelations (cid:32) st and (cid:32) tp defined in Section 2. Definition 5.2.
Let ( { [ o ] } , χ ) , ( { [ o ] } , χ ) ∈ R . We define ( { [ o ] } , χ ) + R ( { [ o ] } , χ ) := ( { [ o + o ] } , χ + χ ) . Definition 5.3 (Annotated Single-Thread Reduction Relation) . We define an annotated single-thread reduction relation (cid:32) ast according to the rules presentedin Figure 10. A reduction step has the form
R, κ (cid:32) ast R (cid:48) , κ (cid:48) , T a for a set of forked annotated threads T a ⊂ R × K with | T a | ≤ . In contrast to the plain semantics, reductions in the annotated semantics canget stuck. Note that according to
A-RedST-Loop , performing a loop iterationrequires holding an empty obligations chunk. This ensures that busy-waitingthreads do not wait for themselves and corresponds to the restriction that proofrule
PR-Loop imposes on looping threads. Consider the program loop skip busy-waiting for itself. Our proof rules do not allow us to prove any specification { A } loop skip { B } where precondition A is neither False nor contains any credit and its reduction gets stuck in the annotated semantics.For the annotated semantics we introduce ghost steps that do not correspondto steps in the unannotated semantics, but only affect the ghost resources weadded for verification purposes. In particular, ghost steps allow a thread tospawn an obligation-credit pair and to cancel an obligation against a credit. Weintroduce two auxiliary step relations (cid:32) ghost and (cid:32) real to clearly differentiatebetween ghost steps and steps corresponding to real program steps.10 -RedST-Loop χ ≥ { [0] } , χ ) , loop skip ; κ (cid:32) ast ( { [0] } , χ ) , loop skip ; κ, ∅ A-RedST-Fork R m + R R f , fork c f ; κ m (cid:32) ast R m , κ m , { ( R f , c f ; done ) } A-RedST-Seq R, ( c ; c ); κ (cid:32) ast R, c ; ( c ; κ ) , ∅ Figure 10: Annotated reduction rules for single threads.
GS-ObCredIntro θ ∈ dom( P a ) P a ( θ ) = (( { [ o ] } , χ ) , κ ) P a θ (cid:32) ghost P a [ θ := (( { [ o + 1] } , χ + 1) , κ )] GS-ObCredCancel θ ∈ dom( P a ) P a ( θ ) = (( { [ o + 1] } , χ + 1) , κ ) P a θ (cid:32) ghost P a [ θ := (( { [ o ] } , χ ) , κ )]Figure 11: Ghost step rules for thread pools. Ghost steps allow to spawn andcancel an obligation-credit pair. Definition 5.4 (Ghost Thread Pool Steps) . We define a ghost step relation (cid:32) ghost on annotated thread pools according to the rules presented in Figure 11.A ghost step has the form P a θ (cid:32) ghost P a (cid:48) for an ID θ ∈ dom( P a ) and only affects the resources associated with θ . Wedenote its reflexive transitive closure by θ (cid:32) ∗ ghost . Ghost steps reflect the resource manipulation expressed by view shifts. Aghost step performed by
GS-ObCredIntro spawns an obligation-credit pairwhile
GS-ObCredCancel cancels an obligation against a credit. This mim-ics the treatment of obligations and credits displayed by view shift rule
VS-ObCred . Definition 5.5 (Real Thread Pool Reduction Steps) . We define a non-ghost re-duction relation (cid:32) real for annotated thread pools according to the rules presentedin Figure 12. A reduction step has the form P a θ (cid:32) real P a (cid:48) -RedTP-Lift θ ∈ dom( P a ) P a ( θ ) = ( R, κ ) R, κ (cid:32) ast R (cid:48) , κ (cid:48) , TP a θ (cid:32) real P a [ θ := ( R (cid:48) , κ (cid:48) )] + atp T A-RedTP-Exit θ ∈ dom( P a ) P a ( θ ) = ( R, exit ; κ ) P a θ (cid:32) real ∅ atp A-RedTP-ThreadTerm θ ∈ dom( P a ) P a ( θ ) = (( { [0] } , χ ) , done ) P a θ (cid:32) real P a − atp θ Figure 12: Annotated reduction rules for non-ghost steps of thread pools. for a thread ID θ ∈ dom( P a ) . We only allow annotated threads to terminate, i.e., be removed from thethread pool, if they do not hold any obligations, as shown by rule
A-RedTP-ThreadTerm .We define the annotated thread pool reduction relation (cid:32) atp as the unionof (cid:32) real and (cid:32) ghost . Definition 5.6 (Annotated Thread Pool Reduction Relation) . We define an annotated thread pool reduction relation (cid:32) atp such that: P a θ (cid:32) atp P a (cid:48) ⇐⇒ P a θ (cid:32) real P a (cid:48) ∨ P a θ (cid:32) ghost P a (cid:48) Note that our reduction relation (cid:32) atp ensures that at any time the numberof spawned credits in the system equals the number of spawned obligations.Also, the only way to discharge an obligation, i.e., removing it without simul-taneously removing a credit, is by exiting. These two properties are crucial tothe Soundness proof presented in Section 5.3.
Definition 5.7 (Annotated Reduction Sequence) . We define annotated reduc-tion sequences analogously to Definition 2.6.
Since our goal is to prove that no fair reduction sequence can correspond toa program discharging all its obligations, we need to lift our fairness definitionto the annotated semantics.
Definition 5.8 (Fair Annotated Reduction Sequences) . We call an annotatedreduction sequence ( P ai ) i ∈ N fair iff for all k ∈ N and θ k ∈ dom( P ak ) there exists j ≥ k such that P aj θ k (cid:32) real P aj +1 Note that fairness prohibits threads to perform ghost steps forever.12 .2 Interpreting Specifications
Specifications
We use Hoare triples { A } c { B } to express specifications. In-tuitively, such a triple states that given precondition A , command c either (i) di-verges, i.e., loops forever, (ii) abruptly terminates via exit or (iii) terminatesnormally and postcondition B holds afterwards. In the following we make thisintuition precise such that we can use it to show the correctness of our veri-fication approach. The annotated semantics act as an intermediary betweenhigh-level reasoning steps, e.g., using obligations to track which thread is goingto exit , and the actual program executions. Hence, we use this connection todefine the meaning of Hoare triples.Note that a reduction in the annotated semantics can get stuck in contrastto a reduction in the plain semantics. Therefore, a specification { A } c { B } additionally expresses that reduction of c in the annotated semantics does notget stuck. Interpretations
We interpret Hoare triples in terms of a model relation (cid:15) H and an auxiliary safety relation safe ( R, c ). Intuitively, a continuation κ is safeunder a complete resource bundle R if R provides all necessary ghost resourcessuch that the reduction of ( R, κ ) does not get stuck. We write anno ( P a , P ) toexpress that P a is an annotated version of P , containing the same threads buteach equipped with a resource bundle. Definition 5.9 (Annotation of Thread Pools) . We say that P a is an annotation of P and write anno ( P a , P ) if dom( P ) = dom( P a ) and if for every thread ID θ ∈ dom( P ) there exists a resource bundle R ∈ R such that P a ( θ ) = ( R, P ( θ )) . Definition 5.10 (Safety) . We define the safety predicate safe ⊆ R × K coin-ductively as the greatest solution (with respect to ⊆ ) of the following equation: safe ( R, κ ) = complete ( R ) →∀ P, P (cid:48) . ∀ θ ∈ dom( P ) . ∀ P a .P ( θ ) = κ ∧ P θ (cid:32) tp P (cid:48) ∧ anno ( P a , P ) ∧ P a ( θ ) = ( R, κ ) →∃ P a G . ∃ P a (cid:48) . P a θ (cid:32) ∗ ghost P a G ∧ P a G θ (cid:32) real P a (cid:48) ∧ anno ( P a (cid:48) , P (cid:48) ) ∧ ∀ ( R ∗ , κ ∗ ) ∈ range( P a (cid:48) ) \ range( P a ) . safe ( R ∗ , κ ∗ )Intuitively, a Hoare triple { A } c { B } holds in our model relation (cid:15) H if thefollowing two conditions are met:(1) Any resources R A fulfilling precondition A suffice to reduce c withoutgetting stuck, i.e., safe ( R A , c ; done ).(2) If reduction of ( R A , c ; done ) terminates in ( R B , done ) (i.e., reductiondoes neither abruptly exit nor diverge), then R B fulfils postcondition B .Note that given (1), property (2) is equivalent to safe ( R B , c ; κ ) for any continu-ation κ safe under R B . 13 efinition 5.11 (Hoare Triple Model Relation) . We define the Hoare triplemodel relation (cid:15) H such that (cid:15) H { A } c { B }⇐⇒∀ R F . ∀ κ. ( ∀ R B . R B (cid:15) A B → safe ( R B (cid:93) R R F , κ )) → ( ∀ R A . R A (cid:15) A A → safe ( R A (cid:93) R R F , c ; κ ))Note that compliance with the frame rule directly follows from above defin-ition, i.e., (cid:15) H { A } c { B } implies (cid:15) H { A ∗ F } c { B ∗ F } for any frame F ∈ A .Further, every specification { A } c { B } we can derive with our proof rules alsoholds in our model. Lemma 5.12 (Soundness of Hoare Triples) . Let (cid:96) { A } c { B } . Then (cid:15) H { A } c { B } holds.Proof. By induction on the derivation of (cid:96) { A } c { B } .This lemma bridges the gap between our verification approach and the an-notated semantics. That is, whenever we can prove a specification (cid:96) { A } c { B } ,we know that command c can be safely reduced in the annotated semantics givenprecondition A . If this reduction terminates normally (i.e. in case it neitherdiverges nor abruptly terminates), postcondition B holds in the final state. In the proof of Soundness Theorem 4.3, we show that programs which provablydischarge all their exit obligations and start without credits terminate under fairscheduling. That is, we show that such programs cannot have a correspondingfair reduction sequence. To be able to refer to the eventually discharged ob-ligations, the proof requires us to refer to annotated reduction sequences. Thefollowing lemma allows us to construct such an annotated reduction sequencefrom an unannotated one.
Observation 5.13 ( done Safe) . safe ( R, done ) holds for all complete R . Lemma 5.14.
Let (cid:15) H { A } c { B } , R A (cid:15) A A and complete ( R A ) . Furthermore, let ( P i ) i ∈ N be fair with P = { ( θ, c ; done ) } . There exists a fair annotated reductionsequence ( P ai ) i ∈ N with P a = { ( θ, ( R A , c ; done )) } .Proof. According to the definition of (cid:15) H (cf. Definition 5.11) the followingimplication holds: ∀ R F . ∀ κ. ( ∀ R B . R B (cid:15) A B → safe ( R B (cid:93) R R F , κ )) → ( ∀ R ∗ A . R ∗ A (cid:15) A A → safe ( R ∗ A (cid:93) R R F , c ; κ ))We can instantiate this to( ∀ R B . R B (cid:15) A B → safe ( R B , done )) → ( ∀ R ∗ A . R ∗ A (cid:15) A A → safe ( R ∗ A , c ; done )) . safe ( R B , done ) holds for any complete R B .Hence, the implication’s precondition holds trivially and we get ∀ R ∗ A . R ∗ A (cid:15) A A → safe ( R ∗ A , c ; done )and in particular safe ( R A , c ; done ).In the following, we construct the witness ( P ai ) i ∈ N inductively from the un-annotated reduction sequence ( P i ) i ∈ N . In the lemma, we already defined thereduction sequence’s start P a = { ( θ, ( R A , c ; done )) } .Assume we got an annotation ( P ai ) i ∈{ ,...,m } of the prefix ( P i ) i ∈{ ,...,n } where safe ( R ∗ , κ ∗ ) holds for every ( R ∗ , κ ∗ ) ∈ range( P am ). Note that m ≥ n , since theannotated prefix might contain ghost steps.Let θ n be the thread ID corresponding to the continuation reduced in reduc-tion step n , i.e., P n θ n (cid:32) tp P n +1 . There exist R m and κ m with P am ( θ n ) = ( R m , κ m ).By the assumption safe ( R m , κ m ) we get the existence of an annotated threadpool P a (cid:48) with anno ( P a (cid:48) , P n +1 ), P a (cid:48) ( θ n ) = ( R (cid:48) , κ (cid:48) ) and also safe ( R (cid:48) , κ (cid:48) ) for some R (cid:48) , κ (cid:48) .According to safe ( R m , κ m ) there exists P a G with P a θ (cid:32) ∗ ghost P a G and P a G θ (cid:32) real P a (cid:48) . That is, we get the existence of a (potentially empty) sequence of threadpools P am +1 , ..., P am + h corresponding to P a θ (cid:32) ∗ ghost P a G . By setting P am + h +1 := P a (cid:48) we obtain an annotation ( P ai ) i ∈{ ,...,m + h +1 } of the extended prefix ( P i ) i ∈{ ,...,n +1 } .We get safe ( R ∗ , κ ∗ ) for all ( R ∗ , κ ∗ ) ∈ range( P am + h +1 ).By induction we get the claimed annotated reduction sequence ( P ai ) i ∈ N with P a = { ( θ, ( R A , c ; done )) } . By construction of ( P ai ) i ∈ N , there exists an an-notated reduction step P aj θ i (cid:32) real P aj +1 for every step P i θ i (cid:32) tp P i +1 in the plainsequence. Hence, the construction preserves the fairness of ( P i ) i ∈ N .As next step, we show that an annotated reduction sequence such as ( P ai ) i ∈ N constructed above, cannot start with initial resources of the form R A = ( { [ o ] } , G (( P ai ) i ∈ N ) defined in the fol-lowing. In this graph, every node i represents the i th reduction step of thesequence, i.e., P ai θ i (cid:32) atp P ai +1 . Edges have the form ( i, θ j , n, j ). Such an edgeexpresses that either (i) P aj θ j (cid:32) atp P aj +1 is the first step of a thread forked instep i or (ii) j is the next index representing a reduction of thread θ i (in whichcase θ i = θ j holds). In both cases, n represents the name of the reduction ruleapplied in step P aj θ j (cid:32) atp P aj +1 . Definition 5.15 (Program Order Graph) . Let P a = { ( θ , ( R , κ )) } be an annotated thread pool and ( P ai ) i ∈ I an annot-ated reduction sequence. Furthermore, let N r be the set of names referring toreduction rules defining the relations (cid:32) real , (cid:32) ghost and (cid:32) ast .Below, we define the program order graph G (( P ai ) i ∈ N ) = ( N , E ) for ( P ai ) i ∈ N where E ⊆ N × N × N r × N . We define the set of edges E as the smallest setmeeting the following requirements: et i, j ∈ N be indices denoting reduction steps P ai θ i (cid:32) atp P ai +1 and P aj θ j (cid:32) atp P aj +1 for some thread IDs θ i , θ j ∈ N . Let n ∈ N r be the name of the reductionrule applied during step P ai θ i (cid:32) atp P ai +1 in the following sense: • In case the step is an application of reduction rule
A-RedTP-Lift incombination with some single thread reduction rule n st , then n = n st . • Otherwise, n denotes the applied (real or ghost) thread pool reduction rule.With these choices, ( i, θ j , n, j ) ∈ E holds if one of the following holds: • θ i = θ j and j = min( { l ∈ N | l > i ∧ P al θ j (cid:32) atp P al +1 } ) • θ i (cid:54) = θ j , dom( P ai +1 ) \ dom( P ai ) = { θ j } and j = min( { l ∈ N | l > i ∧ P al θ j (cid:32) atp P al +1 } ) ,We define node 0 to be the root of the program order graph. In case the choice ofreduction sequence is clear from the context, we write G instead of G (( P ai ) i ∈ N ) . Consider the program c ex2 = fork ( fork loop skip ; exit ); loop skip It forks a thread and busy-waits for it to exit the program. In turn, the forkedthread forks another thread that busy-waits as well, before it abruptly termin-ates the program. Figure 13 presents one possible example reduction sequenceand its program order graph.For any program order graph G , we call a subgraph G s of G sibling-closedif, for each node n of the subgraph, n ’s predecessors’ successors are also in thesubgraph. In other words, for each fork step node, either both the next step ofthe forking thread and the first step of the forked thread are in the subgraph,or neither are.Sibling-closed prefixes of program order graphs have the special propertythat the sum of the obligations held by the threads reduced in their leavesequals the sum of the credits held by these threads. This property forms acrucial part of our soundness argument, as we see in the following. Definition 5.16 (Sibling-Closed Subgraph) . Let G be a program order graphand G s a subgraph of G . For a node n ∈ G s \ { } , let p n be the predecessor of n in G , i.e., the node for which θ, m exist such that ( p n , θ, m, n ) ∈ edges ( G ) .Further, let S n = { j | ∃ θ. ∃ m. ( p n , θ, m, j ) ∈ edges ( G ) } be the set containing n and n ’s siblings in G .We call G s sibling-closed if for all n ∈ nodes ( G s ) and all s ∈ S n , it holdsthat s ∈ G s . Lemma 5.17.
Let G p be a finite sibling-closed prefix of some program ordergraph G (( P ai ) i ∈ N ) with P a = { ( θ , ( R , κ )) } for some complete R . Let L be
16D Thread pool Applied reduction rule0 { (0 , ( ∅ atp , c ex2 )) } (cid:32) ghost GS-ObCredIntro { (0 , (( { [1] } , , c ex2 )) } (cid:32) real A-RedTP-Lift + A-RedST-Fork { (0 , (( { [0] } , , loop skip )) , (1 , (( { [1] } , , fork loop skip ; exit )) } (cid:32) ghost GS-ObCredIntro { (0 , (( { [0] } , , loop skip )) , (1 , (( { [2] } , , fork loop skip ; exit )) } (cid:32) real A-RedTP-Lift + A-RedST-Fork { (0 , (( { [0] } , , loop skip )) , (1 , (( { [2] } , , exit )) , (2 , (( { [0] } , , loop skip )) } (cid:32) real A-RedTP-Lift + A-RedST-Loop { (0 , (( { [0] } , , loop skip )) , (1 , (( { [2] } , , exit )) , (2 , (( { [0] } , , loop skip )) } (cid:32) real A-RedTP-Lift + A-RedST-Loop { (0 , (( { [0] } , , loop skip )) , (1 , (( { [2] } , , exit )) , (2 , (( { [0] } , , loop skip )) } (cid:32) real A-RedTP-Lift + A-RedST-Loop (cid:32) real A-RedTP-Lift + A-RedST-Loop ... ... ...
GS-ObCredINtro0 A-RedST-Fork1 GS-ObCredINtro1 A-RedST-Fork2 A-RedST-Loop0 . . . Figure 13: Possible reduction sequence and program order graph of c ex2 = fork ( fork loop skip ; exit ); loop skip . Threads with ID θ , resource bundle R and continuation κ are depicted as a tuple ( θ, ( R, κ )).17 et of leaves of G p . For all l ∈ L choose θ l , o l , χ l , κ l such that P al θ l (cid:32) atp P al +1 and P al ( θ l ) = (( { [ o l ] } , χ l ) , κ l ) .The sum of the numbers of obligations held by the threads reduced in theleaves of G p equals the sum of the numbers of credits held by these threads, i.e, Σ l ∈ L o l = Σ l ∈ L χ l Proof.
Proof by induction on the size of G p .Remember that reduction sequences are infinite by definition and consider afair annotated reduction sequence ( P ai ) i ∈ N . The only construct in our languagethat introduces non-termination are loops. Since ( P ai ) i ∈ N is fair and does notget stuck, it must contain loop steps, i.e., reduction steps that result from anapplication of reduction rule A-RedTP-Lift in combination with
A-RedST-Loop . The latter rule, however, requires a credit but forbids the looping threadto hold an obligation. Obligations and credits can only be spawned simultan-eously. Hence, another thread must hold the obligation and will eventually exit .Intuitively, in the annotated semantics, reduction under fair scheduling musteither get stuck or terminate. The following lemma makes this intuition precise.
Lemma 5.18.
There are no fair annotated reduction sequences ( P ai ) i ∈ N with P a = { ( θ , (( { [ o ] } , , κ )) } for any θ , o , κ .Proof. Assume such a reduction sequence exists. Consider the program ordergraph G of ( P ai ) i ∈ N . Since, ( P ai ) i ∈ N is infinite, it contains loop-steps, i.e., re-duction steps P ai θ (cid:32) atp P ai +1 resulting from applications of A-RedTP-Lift incombination with
A-RedST-Loop . Accordingly, G is infinite, too, and containsloop-edges of the form ( i, θ, A-RedST-Loop , j ).Let G lf be its maximal loop-edge-free sibling-closed prefix. By analyzing theleaves of G lf , we prove that G and ( P ai ) i ∈ N are finite, which contradicts ouroriginal assumption about the existence of a fair reduction sequence ( P i ) i ∈ N .Let v l ∈ nodes ( G ) be a node of the full graph for which an edge of the form( v l , θ l , A-RedST-Loop , j ) ∈ edges ( G ) exists and for which the length of thepath from root 0 to v l is minimal. That is, said path does not contain anyloop-edges. Therefore, v l is a leaf of the prefix graph G lf and P av l θ l (cid:32) atp P av l +1 is aloop-step.According to reduction rule A-RedST-Loop , there exist R l , κ l with P av l ( θ l ) =( R l , κ l ) and R l (cid:15) A credit . Additionally, the rule also requires resource bundle R l to contain no obligations. According to Lemma 5.17, there exists a leaf v e ∈ leaves ( G lf ) \ { v l } , a thread ID θ e ∈ N \ { θ l } , a continuation κ e ∈ K and aresource bundle R e ∈ R containing the obligation such that P av e ( θ e ) = ( R e , κ e ).Generally, there are three possible reasons why some node v ∈ nodes ( G ) is aleaf of G lf , all of which depend on the associated reduction step P av θ v (cid:32) atp P av +1 :(i) Because it is a loop-step, (ii) because it is a thread termination step, i.e.,18 av ( θ v ) = ( R v , done ) and P av +1 = P av − atp θ v or (iii) because it is an abrupt exitstep.However, (i) P av e θ e (cid:32) atp P av e +1 cannot be a loop-step according to A-RedST-Loop , since it prohibits R e to hold any obligations. Similarly, (ii) P av e θ e (cid:32) atp P av e +1 cannot be a thread termination step either, since reduction rule A-RedTP-ThreadTerm also prohibits R e to hold any obligations.Therefore, the only possibility is (iii), i.e., P av e θ e (cid:32) atp P av e +1 abruptly exitsthe program and P av e +1 = ∅ atp . Thereby, the program order graph G and theannotated reduction sequence ( P ai ) i ∈ N must be finite.The combination of Lemmas 5.12, 5.14 and 5.18 allow a straight-forwardproof of the soundness theorem. Theorem 4.3 (Soundness) . Let (cid:96) { obs ( n ) } c { obs (0) } . There exists no fairreduction sequence ( P i ) i ∈ N starting with P = { ( θ , c ; done ) } for any θ ∈ N .Proof. Assume there exists a fair reduction sequence ( P i ) i ∈ N starting with P = { ( θ , c ; done ) } . By application of the Soundness Lemma for Hoare triples,Lemma 5.12, we get (cid:15) H { obs ( n ) } c { obs (0) } . By Lemma 5.14, there exists a fairannotated reduction sequence ( P ai ) i ∈ N starting with P a = { ( θ , (( { [ n ] } , , c ; done )) } However, by Lemma 5.18 the annotated reduction sequence ( P ai ) i ∈ N doesnot exist and consequently neither does ( P i ) i ∈ N . We are currently formalizing the presented approach and its soundness proof inCoq.
Ghost Signals
We plan to extend the verification approach described in thispaper to a verification technique we call ghost signals , which allows us to verifytermination of busy-waiting for arbitrary events. Ghost signals come with anobligation to set the signal and a credit that can be used to busy-wait for thesignal to be set. Consider a program with two threads: t e eventually performssome event X (such as setting a flag in shared memory) and t w busy-waits for X . By letting t e set the signal when it performs X , and thereby linking theghost signal to the event, we can justify termination of t w ’s busy-waiting. I/O Liveness as Abrupt Program Exit
In concurrent work we encodeI/O liveness properties as abrupt program termination following a conjecture ofJacobs et al. [2018]. Consider a non-terminating server S which shall reply toall requests. We can prove liveness of S using the following methodology: • For some arbitrary, but fixed N , assume that responding to the N th re-quest abruptly terminates the whole program.19 . . . . . . . . . Queue Responder Thread insertrequestsreceive req. 1, ..., N, ... respond to requests exit after respondingto request NResponder Thread . .
Clients Responder Thread extractrequestssending requests receiving response
Receiver ThreadReceiver Thread Server S Figure 14: Server S receiving and replying to requests. Threads communicatingvia shared queue. • Prove that the program always terminates.One can combine this approach with the one of the present paper to verifyliveness of a server where multiple threads independently receive and handlerequests. Using a prophecy variable
Jung et al. [2020], one can determine aheadof time which thread will receive the exiting request. The other threads canthen be seen as busy-waiting for this thread to exit.
Combination
We plan to combine the two approaches sketched above andconjecture that the combination will be expressive enough to verify livenessof programs such as the server S presented in Figure 14. It runs a set ofreceiving and a set of responding threads communicating via a shared queue.The responding threads busy-wait for requests to arrive in the queue. In orderto verify liveness of S , we need to show that some thread eventually abruptlyterminates the program by acquiring and responding to the N th request. Thisrequires us to prove that the responding threads’ busy-waiting for requests toarrive in the shared queue terminates.In order to demonstrate the approach’s usability, we plan to implement it inVeriFast Jacobs et al. [2011] and prove liveness of S . Liang and Feng [2016, 2017] propose LiLi, a separation logic to verify livenessof blocking constructs implemented via busy-waiting. In contrast to our verific-ation approach, theirs is based on the idea of contextual refinement. LiLi doesnot support forking nor structured parallel composition.D’Osualdo et al. [2019] propose TaDA Live, a separation logic for verifyingtermination of busy-waiting. This logic allows to modularly reason about fine-grained concurrent programs and blocking operations that are implemented interms of busy-waiting and non-blocking primitives. It uses the concept of oblig-ations to express thread-local liveness invariants, e.g., that a thread eventually20eleases an acquired lock. TaDA Live is expressive enough to verify CLH andspin locks. The current version supports structured parallel composition insteadof unstructured forking. Comparing their proof rules to ours, it is fair to saythat our logic is simpler. Of course, theirs is much more powerful. We hope tobe able to extend ours as sketched above while remaining simpler.
In this paper we proposed a separation logic to verify the termination of pro-grams where some threads abruptly terminate the program and others busy-waitfor abrupt termination. We proved our logic sound and illustrated its applica-tion.Abrupt termination can be understood as an approximation of a generalevent. We outlined our vision on how to extend our approach to verify thetermination of busy-waiting for arbitrary events. We have good hope that thefinal logic will be as expressive as TaDA Live proposed by D’Osualdo et al.[2019] while remaining conceptually simpler.Further, we sketched our vision to combine this extended work with concur-rent work on the encoding of I/O liveness properties as abrupt termination. Weillustrated that this combination will be expressive enough to verify liveness ofconcurrent programs where multiple threads share I/O responsibilities.
References
Emanuele D’Osualdo, Azadeh Farzan, Philippa Gardner, and Julian Suther-land. Tada live: Compositional reasoning for termination of fine-grainedconcurrent programs.
CoRR , abs/1901.05750, 2019. URL http://arxiv.org/abs/1901.05750 .Jean-Christophe Filliˆatre, L´eon Gondelman, and Andrei Paskevich. The spiritof ghost code.
Formal Methods in System Design , 48:152–174, 2016.Jafar Hamin and Bart Jacobs. Deadlock-free monitors. In
ESOP , 2018.Jafar Hamin and Bart Jacobs. Transferring obligations through synchroniza-tions. In
ECOOP , 2019.C. A. R. Hoare. An axiomatic basis for computer programming.
Commun.ACM , 12:576–580, 1968.Bart Jacobs, Jan Smans, Pieter Philippaerts, Fr´ed´eric Vogels, Willem Pen-ninckx, and Frank Piessens. Verifast: A powerful, sound, predictable, fastverifier for c and java. In M. Bobaru, K. Havelund, G.J. Holzmann, andR. Joshi, editors,
NASA Formal Methods (NFM 2011) , volume 6617, pages41–55. Springer, 2011. ISBN 978-3-642-20397-8. doi: https://doi.org/10.1007/978-3-642-20398-5 4. URL https://lirias.kuleuven.be/95720 .21art Jacobs, Dragan Bosnacki, and Ruurd Kuiper. Modular termination verific-ation of single-threaded and multithreaded programs.
ACM Trans. Program.Lang. Syst. , 40:12:1–12:59, 2018.Ralf Jung, Robbert Krebbers, Lars Birkedal, and Derek Dreyer. Higher-orderghost state.
Proceedings of the 21st ACM SIGPLAN International Conferenceon Functional Programming , 2016.Ralf Jung, Robbert Krebbers, Jacques-Henri Jourdan, Ales Bizjak, Lars Birke-dal, and Derek Dreyer. Iris from the ground up: A modular foundation forhigher-order concurrent separation logic.
J. Funct. Program. , 28:e20, 2018.Ralf Jung, Rodolphe Lepigre, Gaurav Parthasarathy, Marianna Rapoport, AminTimany, Derek Dreyer, and Bart Jacobs. The future is ours: prophecy vari-ables in separation logic.
Proceedings of the ACM on Programming Languages ,4(POPL), January 2020. ISSN 2475-1421. doi: 10.1145/3371113.Naoki Kobayashi. A new type system for deadlock-free processes. In
CONCUR ,2006.K. Rustan M. Leino, Peter M¨uller, and Jan Smans. Deadlock-free channels andlocks. In
ESOP , 2010.Hongjin Liang and Xinyu Feng. A program logic for concurrent objects underfair scheduling. In
POPL 2016 , 2016.Hongjin Liang and Xinyu Feng. Progress of concurrent objects with partialmethods.
Proc. ACM Program. Lang. , 2:20:1–20:31, 2017.John M. Mellor-Crummey and Michael L. Scott. Algorithms for scalable syn-chronization on shared-memory multiprocessors.
ACM Trans. Comput. Syst. ,9:21–65, 1991.Kurt M¨uhlemann. Method for reducing memory conflicts caused by busy waitingin multiple processor synchronisation. 1980.Peter W. O’Hearn, John C. Reynolds, and Hongseok Yang. Local reasoningabout programs that alter data structures. In
CSL , 2001.Md. Mahbubur Rahman. Process synchronization in multiprocessor and multi-core processor. , pages 554–559, 2012.John C. Reynolds. Separation logic: a logic for shared mutable data structures.