Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

Program Verification: Lecture 27 - Concurrent Imperative Programs & Dekker's Mutex - Prof., Study notes of Computer Science

A lecture note from the computer science department at the university of illinois at urbana-champaign, covering the verification of concurrent imperative programs using maude, focusing on dekker's mutex algorithm. It includes the code of the algorithm for two processes, model checking results, and solutions for the thread game.

Typology: Study notes

Pre 2010

Uploaded on 03/16/2009

koofers-user-trc
koofers-user-trc 🇺🇸

10 documents

1 / 43

Toggle sidebar

Related documents


Partial preview of the text

Download Program Verification: Lecture 27 - Concurrent Imperative Programs & Dekker's Mutex - Prof. and more Study notes Computer Science in PDF only on Docsity! Program Verification: Lecture 27 José Meseguer Computer Science Department University of Illinois at Urbana-Champaign 1 Verification of Concurrent Imperative Programs In the case of deterministic programs, we first studied the verification of declarative deterministic programs such as Maude functional modules. Then, in a sense, we reduced to this case the verification of imperative programs. Indeed, we can specify the semantics of a deterministic imperative language L as an equational theory E(L) (in fact, a Maude functional module). Then, reasoning about the correctness of imperative programs in L reduces (perhaps through decomposition by means of a Hoare logic) to proving inductive properties satisfied by the initial model TE(L). 2 ***(Equality test comparing the contents of a named memory location to an Int? value.) fmod TESTS is inc MEMORY . sort Test . op _=_ : Qid Int? -> Test . op eval : Test Memory -> Bool . var Q : Qid . var M : Memory . vars N? N’? : Int? . eq eval(Q = N?, [Q, N’?] M) = N? == N’? . ceq eval(Q = N?, M) = N? == null if Q in M =/= true . endfm ***(Syntax for arithmetic expressions, and their evaluation semantics. To avoid evaluation of expressions by themselves, which would happen even without a memory for integer subexpressions if we keep the usual syntax, the operators + and * are specified as constructors with syntax +’ and *’ ) 5 fmod EXPRESSION is inc MEMORY . sort Expression . subsorts Qid Int? < Expression . op _+’_ : Expression Expression -> Expression [ctor] . op _*’_ : Expression Expression -> Expression [ctor] . op eval : Expression Memory -> Int? . var Q : Qid . var M : Memory . vars N N’ : Int . var N? : Int? . vars E E’ : Expression . eq eval(N?, M) = N? . eq eval(Q, [Q, N?] M) = N? . ceq eval(Q,M) = null if Q in M =/= true . eq eval(E +’ E’, M) = eval(E,M) + eval(E’,M) . eq eval(E *’ E’, M) = eval(E,M) * eval(E’,M) . endfm 6 ***(Syntax for a trival sequential language. We allow abstracting out program fragments as elements of sorts LoopingUserStatement and UserStatement. Elements of sort LoopingUserStatement abstract out potentially nonterminating program fragments, whereas elements of sort UserStatement but not of sort LoopingUserStatement abstract out terminating program fragments.) fmod SEQUENTIAL is inc TESTS . inc EXPRESSION . sorts UserStatement LoopingUserStatement Program . subsort LoopingUserStatement < UserStatement < Program . op skip : -> Program . op _;_ : Program Program -> Program [prec 61 assoc id: skip] . op _:=_ : Qid Expression -> Program . op if_then_fi : Test Program -> Program . op while_do_od : Test Program -> Program . op repeat_forever : Program -> Program . endfm 7 vars P R : Program . var S : Soup . var U : UserStatement . var L : LoopingUserStatement . vars I J : Pid . var M : Memory . var Q : Qid . vars N? X? : Int? . var T : Test . var E : Expression . rl {[I, U ; R] | S, M, J} => {[I, R] | S, M, I} . rl {[I, L ; R] | S, M, J} => {[I, L ; R] | S, M, I} . rl {[I, (Q := E) ; R] | S, [Q, X?] M, J} => {[I, R] | S, [Q,eval(E,[Q, X?] M)] M, I} . crl {[I, (Q := E) ; R] | S, M, J} => {[I, R] | S, [Q,eval(E,M)] M, I} if Q in M =/= true . 9 rl {[I, if T then P fi ; R] | S, M, J} => {[I, if eval(T, M) then P else skip fi ; R] | S, M, I} . rl {[I, while T do P od ; R] | S, M, J} => {[I, if eval(T, M) then (P ; while T do P od) else skip fi ; R] | S, M, I} . rl {[I, repeat P forever ; R] | S, M, J} => {[I, P ; repeat P forever ; R] | S, M, I} . endm 10 Dekker’s Mutex Algorithm One of the earliest correct solutions to the mutual exclusion problem was given by Dekker with his algorithm. The algorithm assumes processes that execute concurrently on a shared memory machine and communicate with each other through shared variables. There are two processes, p1 and p2. Process 1 sets a Boolean variable c1 to 1 to indicate that it wishes to enter its critical section. Process p2 does the same with variable c2. If one process, after setting its variable to 1 finds that the variable of its competitor is 0, then it enters its critical section rightaway. In case of a tie (both variables set to 1) the tie is broken using a variable turn that takes values in {1, 2}. 11 Dekker’s Mutex Algorithm (IV) We can then define the two processes for Dekker’s algorithm and the desired initial state in the following module extending PARALLEL. Note that we assume that crit does terminate, whereas rem may not. mod DEKKER is inc PARALLEL . subsort Int < Pid . op crit : -> UserStatement . op rem : -> LoopingUserStatement . ops p1 p2 : -> Program . op initialMem : -> Memory . op initial : -> MachineState . 14 eq p1 = repeat ’c1 := 1 ; while ’c2 = 1 do if ’turn = 2 then ’c1 := 0 ; while ’turn = 2 do skip od ; ’c1 := 1 fi od ; crit ; ’turn := 2 ; ’c1 := 0 ; rem forever . 15 eq p2 = repeat ’c2 := 1 ; while ’c1 = 1 do if ’turn = 1 then ’c2 := 0 ; while ’turn = 1 do skip od ; ’c2 := 1 fi od ; crit ; ’turn := 1 ; ’c2 := 0 ; rem forever . eq initialMem = [’c1, 0] [’c2, 0] [’turn, 1] . eq initial = { [1, p1] | [2, p2], initialMem, 0 } . endm 16 Model Checking Dekker’s Algorithm (III) But the strong liveness property that executing infinitely often implies entering one’s critical section infinitely often fails, as witnessed by the counterexample, reduce in CHECK : modelCheck(initial,[]<> exec(1) -> []<> enterCrit(1)) . ModelChecker: Property automaton has 3 states. ModelCheckerSymbol: Examined 16 system states. rewrites: 159 in 0ms cpu (0ms real) (~ rewrites/second) result ModelCheckResult: counterexample({{[1,repeat ’c1 := 1 ; while ’c2 = 1 do if ’turn = 2 then ’c1 := 0 ; while ’turn = 2 do skip od ; ’c1 := 1 fi od ; crit ; ’turn := 2 ; ’c1 := 0 ; rem forever] | [2,repeat ’c2 := 1 ; while ’c1 = 1 do if ’turn = 1 then ’c2 := 0 ; while ’turn = 1 do skip od ; ’c2 := 1 fi od ; crit ; ’turn := 1 ; ’c2 := 0 ; rem forever],[’c1,0] [’c2,0] [ ’turn,1],0},unlabeled} ... 19 Model Checking Dekker’s Algorithm (IV) Even the weaker liveness property that if both p1 and p2 execute infinitely often then both enter their critical sections infinitely often fails, due to possible looping in the rem part: reduce in CHECK : modelCheck(initial,[]<> exec(1) /\ []<> exec(2) -> []<> enterCrit(1) /\ []<> enterCrit(2)) . ModelChecker: Property automaton has 7 states. ModelCheckerSymbol: Examined 236 system states. rewrites: 1972 in 50ms cpu (50ms real) (39440 rewrites/second) result ModelCheckResult: counterexample({{[1,repeat ’c1 := 1 ; while ’c2 = 1 do if ’turn = 2 then ’c1 := 0 ; while ’turn = 2 do skip od ; ’c1 := 1 fi od ; crit ; ’turn := 2 ; ’c1 := 0 ; rem forever] | [2,repeat ’c2 := 1 ; while ’c1 = 1 do if ’turn = 1 then ’c2 := 0 ; while ’turn = 1 do skip od ; ’c2 := 1 fi od ; crit ; ’turn := 1 ; ’c2 := 0 ; rem forever],[’c1,0] [’c2,0] [ ’turn,1],0},unlabeled} ... 20 Model Checking Dekker’s Algorithm (V) However, the more subtle weak liveness property that if p1 and p2 both get to execute infinitely often, then if p1 is infinitely often out of its ”rem” section, then p1 enters its critical section infinitely often holds; of course, the same holds for p2. reduce in CHECK : modelCheck(initial,[]<> exec(1) /\ []<> exec(2) -> []<> ~ in-rem(1) -> []<> enterCrit(1)) . ModelChecker: Property automaton has 5 states. ModelCheckerSymbol: Examined 263 system states. rewrites: 2219 in 60ms cpu (70ms real) (36983 rewrites/second) result Bool: true 21 eq p2 = repeat ’a2 := ’c ; ’b2 := ’c ; ’c := ’a2 +’ ’b2 forever . eq init = { [1, p1] | [2, p2], [’c, 1], 0 } . eq init1 = { [1, p1], [’c, 1], 0 } . eq init2 = { [2, p2], [’c, 1], 0 } . endm 24 The Thread Game (II) We can use the search command in Maude to gain some experimental evidence about the first question, Maude> search [1] init =>* { S:Soup, [’c, 1] M:Memory, J:Pid } . Solution 1 (state 0) states: 1 rewrites: 3 in 0ms cpu (0ms real) (~ rewrites/second) S:Soup --> [1,repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever] | [2, repeat ’a2 := ’c ; ’b2 := ’c ; ’c := (’a2 +’ ’b2) forever] M:Memory --> none J:Pid --> 0 Maude> search [1] init =>* { S:Soup, [’c, 2] M:Memory, J:Pid } . Solution 1 (state 13) states: 14 rewrites: 38 in 10ms cpu (10ms real) (3800 rewrites/second) S:Soup --> [1,repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever] | [2, repeat ’a2 := ’c ; ’b2 := ’c ; ’c := (’a2 +’ ’b2) forever] M:Memory --> [’a1,1] [’b1,1] 25 J:Pid --> 1 Maude> search [1] init =>* { S:Soup, [’c, 3] M:Memory, J:Pid } . Solution 1 (state 69) states: 70 rewrites: 326 in 0ms cpu (0ms real) (~ rewrites/second) S:Soup --> [1,repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever] | [2, repeat ’a2 := ’c ; ’b2 := ’c ; ’c := (’a2 +’ ’b2) forever] M:Memory --> [’a1,1] [’b1,1] [’a2,1] [’b2,2] J:Pid --> 2 Maude> search [1] init =>* { S:Soup, [’c, 4] M:Memory, J:Pid } . search [1] in THREAD-GAME : init =>* {S:Soup,M:Memory [’c,4],J:Pid} . states: 62 rewrites: 282 in 10ms cpu (10ms real) (28200 rewrites/second) S:Soup --> [1,repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever] | [2, repeat ’a2 := ’c ; ’b2 := ’c ; ’c := (’a2 +’ ’b2) forever] M:Memory --> [’a1,2] [’b1,2] J:Pid --> 1 Maude> search [1] init =>* { S:Soup, [’c, 5] M:Memory, J:Pid } . Solution 1 (state 275) states: 276 rewrites: 1437 in 30ms cpu (30ms real) (47900 rewrites/second) 26 M:Memory --> [’a1,4] [’b1,6] [’a2,2] [’b2,4] J:Pid --> 1 ... Maude> search [1] init =>* { S:Soup, [’c, 99] M:Memory, J:Pid } . Solution 1 (state 68974) states: 68975 rewrites: 408394 in 8960ms cpu (9020ms real) (45579 rewrites/second) S:Soup --> [1,repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever] | [2, repeat ’a2 := ’c ; ’b2 := ’c ; ’c := (’a2 +’ ’b2) forever] M:Memory --> [’a1,48] [’b1,51] [’a2,3] [’b2,48] J:Pid --> 1 29 The Thread Game (III) We can likewise use the rewite command in Maude to gain some experimental evidence about the second question, Maude> rewrite [20] in THREAD-GAME : init1 . rewrite [20] in THREAD-GAME : init1 . ---> {empty | [1,(’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1)) ; repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever ; skip],[’c,1],1} ---> {empty | [1,’b1 := ’c ; ’c := (’a1 +’ ’b1) ; repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever],[’c,1] [’a1,eval(’c, [’c,1])],1} ---> {empty | [1,’c := (’a1 +’ ’b1) ; repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever],([’a1,1] [’c,1]) [’b1,eval(’c, [’a1,1] [’c,1])],1} 30 ---> {empty | [1,repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever],([’a1,1] [’b1,1]) [’c,eval(’a1 +’ ’b1, ([’a1,1] [’b1,1]) [’c,1])],1} ---> {empty | [1,(’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1)) ; repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever ; skip],[’a1,1] [’c,2] [’b1,1],1} ---> {empty | [1,’b1 := ’c ; ’c := (’a1 +’ ’b1) ; repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever],([’c,2] [’b1,1]) [’a1,eval(’c, ([’c,2] [’b1,1]) [ ’a1,1])],1} ---> {empty | [1,’c := (’a1 +’ ’b1) ; repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever],([’a1,2] [’c,2]) [’b1,eval(’c, ([’a1,2] [’c,2]) [’b1,1])],1} ---> {empty | [1,repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever],([’a1,2] [’b1,2]) [’c,eval(’a1 +’ ’b1, ([’a1,2] [’b1,2]) [’c,2])],1} 31 ---> {empty | [1,’c := (’a1 +’ ’b1) ; repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever],([’a1,16] [’c,16]) [’b1,eval(’c, ([’a1,16] [’c,16]) [’b1, 8])],1} ---> {empty | [1,repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever],([’a1, 16] [’b1,16]) [’c,eval(’a1 +’ ’b1, ([’a1,16] [’b1,16]) [’c,16])],1} result MachineState: {[1,repeat ’a1 := ’c ; ’b1 := ’c ; ’c := (’a1 +’ ’b1) forever],[’a1,16] [’c,32] [’b1,16],1} Maude> 34 The Thread Game (IV) The above experimental evidence suggests the following two conjectures: 1. when both processes are running, then for any n ≥ 1 there is an execution such that ’c eventually holds n 2. when only one process is running, then ’c will initially hold 1, and then for each n ≥ 0 if it holds 2n, it will continue holding that value until it eventually holds 2n+1. Can you prove it? (Note: Any precise mathematical proof will do; do not even need to use temporal logic). 35 A Semantic Framework for Programming Languages PARALLEL is a toy language. Can the rewriting logic approach scale up to real concurrent languages? The answer is “yes.” We can define the semantics of a concurrent programming language L by a rewrite theory RL = (ΣL, EL, RL), where: • ΣL specifies L’s syntax and the auxiliary operators needed in semantic definitions (memory, environment, etc.) • the equations EL specify the semantics of all the deterministic features of L and of the auxiliary semantic operations. • the rewrite rules RL specify the semantics of all the concurrent features of L. 36 JavaFAN Project Based on Maude rewriting logic specifications of Java and JVM, we are developing JavaFAN (Java Formal ANalyzer), a tool in which Java and JVM code can be executed and analyzed. The following figure shows the architecture of JavaFAN. 39 Performance of JavaFAN Tests JVM Java Other Remote Agent (s) 0.3 0.1 2 (Stanford) 2-stage Pipeline 17m — 100m+ (Stanford) DinPhil (4) 0.64 1.2 — DinPhil (6) 33.3 81.7 — DinPhil (8) 13.7m 98m — DinPhil (9) 803.2m — — Deadlock-free DinPhil (5) 3.2m 19.2 ∞ (JPF) Deadlock-free DinPhil (7) 686.4m 27m ∞ (JPF) Thread Game (100) (s) 17.1 6.6 — Thread Game (1000) (s) 10.1m 5.1m — 40 Performance of JavaFAN: Some discussion There are essentially two reasons for JavaFAN to compare favorably with more conventional Java analysis tools: (1) the high performance of Maude for execution, search, and model checking; and (2) optimized equational and rule definitions. The second reason is the use of performance-enhancing specification techniques at the Maude level, including: • expressing as equations E the semantics of all deterministic computations, and as rules R only concurrent computations. • favoring unconditional equations and rules over less efficient conditional versions. • using a continuation passing style in semantic equations. 41
Docsity logo



Copyright © 2024 Ladybird Srl - Via Leonardo da Vinci 16, 10126, Torino, Italy - VAT 10816460017 - All rights reserved