scispace - formally typeset
Search or ask a question
Book ChapterDOI

A proof framework for concurrent programs

15 Jun 2012-pp 174-190
TL;DR: This paper presents a proof framework for verifying concurrent programs that communicate using global variables and is geared towards verification of models that have an unbounded state size and are as close to the original code as possible.
Abstract: This paper presents a proof framework for verifying concurrent programs that communicate using global variables. The approach is geared towards verification of models that have an unbounded state size and are as close to the original code as possible. The bakery algorithm is used as a demonstration of the framework basics, while the (full) framework with thread synchronization was used to verify and correct the reentrant readers writers algorithm as used in the Qt library.

Summary (3 min read)

1 Introduction

  • Parallelism has been employed for many years, mainly in high-performance computing.
  • Parallel computer programs are more difficult to write than sequential ones, because concurrency introduces several new classes of potential software bugs.
  • In an earlier paper [14] a case study is presented that combines two formal verification methods, namely model checking and theorem proving.
  • The improved algorithm was subsequently shown to be correct in PVS.
  • In Section 3 these framework basics are applied to a classic example, the bakery algorithm.

2 Framework basics

  • In their case, the authors use PVS as theorem prover and Promela as the modeling language.
  • The embedding presented in this paper is a mixed shallow/deep one: the framework is based on a shallow embedding while the translation of the model into PVS exploits the native features of PVS as much as possible, and hence can be seen as a deep embedding.

Transition system

  • The authors framework reflects this directly by representing concurrently executing threads by means of a state transition system.
  • Denotes the set of natural numbers between 0 and NT, exclusive of NT.
  • The entire system state consists of all the threads combined with the global variable store global (again a theory type parameter), and a variable current signifying which thread is currently executing.
  • This Model theory, resulting from the translation of the Promela program (say P ), has the following skeleton.
  • The effect of step is local, i.e. it only affects the local state of the currently executing thread, and possibly the global state of the system.

Theorems and proofs

  • Proving the different properties requires (1) the instantiation of the (noDeadlockMeasure and noStarvationMeasure) measures needed for the theorems defined in Section 2, and (2) the definition of an invariant strong enough to prove that these measures indeed strictly decrease.
  • This is formulated using the program counter.
  • This value of peers is set to the value of the global variable enter at the moment the thread has drawn its number (the location with program counter 5), and the thread is removed from peer groups of other threads after leaving the critical section (indicated by the program counter value 10).
  • The invariants guarantee that when a process proceeds to the critical section (location 10), all the other processes have larger numbers.
  • The proofs of the theorems proceed by a case distinction on the value of the program counter, creating a symbolic execution of the algorithm.

3 An example: bakery algorithm

  • The algorithm itself is analogue to the way bakeries give their customers turns by drawing a number from a machine, where the baker serves the lowest number when he is available.
  • The complete model will execute the above code infinitely many times.
  • Next the authors translate this IL program into the PVS framework.
  • The first three assignments of their example are combined into a single transition.
  • This theory also contains the proper instances of the parameters of Threads from Section 2.

4 Framework with thread synchronisation

  • Many concurrent algorithms are based on locking primitives that modern operating systems usually support.
  • These primitives are not available in standard Promela but are added to the framework.
  • In principle the authors could have modeled these locking primitives in Promela (like the bakery algorithm) and translated this model to PVS using the procedure as described in the previous sections.
  • It appears to be more convenient to extend Promela with special synchronization constructs8, and use a shallow embedding by also incorporating basic locks into their PVS framework.

Incorporating locking primitives

  • The idea of the basic locks is similar to, for example, the synchronization mechanism of Java.
  • Besides, processes should be able to relinquish their turn temporarily by means of a wait command and also be able to wake other processes up using notify.
  • This state indicates whether the lock is occupied (in which case lockedBy refers to the corresponding thread) and maintains two queues for holding the blocked and waiting processes.
  • A thread executing a synchronization operation may indirectly affect other system components.
  • Instead of passing the complete system state to the step relation, the authors have implemented these ‘system calls’ by extending the result of step with a function of type [System → System ] .

Example: reentrant read-write

  • A more complex synchronization mechanism involves processes that acquire access to resources for both reading and writing: the classic readers-writers problem.
  • Most solutions give priority to write locks over read locks because write locks are assumed to be more important, smaller, exclusive, and occurring less frequently.
  • This is not included in the translation function, but can be added straightforwardly (e.g. by parameterizing the translation with an additional environment that performs this mapping).
  • The part of the step relation that corresponds to this program fragment is shown below.
  • The invariant needed to prove the theorems is large, but revolves around the relationships of the possible values of the variables used in the program at certain points in their execution past, similar to what was done in Section 3.

Did you find this useful? Give us your feedback

Content maybe subject to copyright    Report

A Proof Framework for Concurrent Programs
Leonard Lensink, Sjaak Smetsers and Marko van Eekelen
ICIS, Radboud University Nijmegen, The Netherlands
Email: {l.lensink,s.smetsers,m.vaneekelen}@cs.ru.nl
Abstract. This paper presents a proof framework for verifying concurrent
programs that communicate using global variables. The approach is geared
towards verification of models that have an unbounded state size and are
as close to the original code as possible. The bakery algorithm is used as
a demonstration of the framework basics, while the (full) framework with
thread synchronization was used to verify and correct the reentrant readers
writers algorithm as used in the Qt library.
1 Introduction
Parallelism has been employed for many years, mainly in high-performance com-
puting. The physical constraints preventing an unlimited growth in processor speed
have led to a revival of interest in concurrent computing. Parallel computing has
become a dominant paradigm in computer architecture, particularly for multi-core
systems [13].
Parallel computer programs are more difficult to write than sequential ones,
because concurrency introduces several new classes of potential software bugs. In
practice, it can be incredibly difficult to track down these software bugs, because of
their unpredictable nature: they are typically caused by infrequent ’race conditions’
that are hard to reproduce. In such cases, it is necessary to thoroughly investigate
‘suspicious’ parts of the system in order to improve these components in such a way
that correctness is guaranteed. The most thorough technique is to formally verify
properties of the system under investigation.
In an earlier paper [14] a case study is presented that combines two formal
verification methods, namely model checking and theorem proving. The idea is to
use the model checker to track down and remove (concurrency) bugs, and to use the
theorem prover to formally prove their absence. Model checkers and theorem provers
have their own input languages. Therefore, the use of these formal tools requires
that the original program is first converted to (modeled in) the language of the
model checker, and subsequently translated into the language of the theorem prover.
Obviously, both translations introduce potential sources of errors, particularly if
these translations are performed manually.
The experience with this case study led us to develop a general proof framework
with specific support to construct proofs of mutual exclusion, deadlock and starva-
tion properties for concurrent algorithms that communicate using shared variables.
The proof framework consists of a model that can be instantiated and used for dif-
ferent programs, a set of theorems that can be used to prove relevant properties of
the system and a general approach towards solving the proofs and proof obligations
generated by the framework. Using SPIN [5] as model checker, we investigate how
(concurrent) Promela (the input language of SPIN) programs can be modeled in
PVS [10]. We define an automatic translation within the framework that serves as a

basis not only to facilitate the conversion of Promela into PVS, but also to support
the investigation of general properties of parallel computer programs.
In this paper, this framework is introduced. It integrates model checking with
theorem proving. An approach like this is used earlier in VeriTech [6], a translation
framework between different formal notations. Novel in this approach is that it pro-
vides a translation extended with theorems and proof strategies, and unlike TAME
[1], which is geared towards automaton models, the intended use is to prove prop-
erties of computer programs that make use of communication primitives. The use
of the framework is explained applying it to a common mutual exclusion algorithm
known as the bakery algorithm [7]. We demonstrate the power of the framework by
applying it to a larger example, showing correctness of a solution to the reentrant
readers-writers problem [15] that improves upon the widely used Qt C++ library
by Trolltech. In that paper [15] it was described how a model was constructed and
checked using the SPIN model checker. This revealed an error in the implemen-
tation, and a correction was suggested. The improved algorithm was subsequently
shown to be correct in PVS. However, the PVS model was constructed manually.
Here, we show how the model can be generated automatically, and how the proof can
be structured using the support of the framework. For this paper, some knowledge
of PVS and Promela or similar formal specification languages is presumed.
Section 2 introduces the framework basics. In Section 3 these framework ba-
sics are applied to a classic example, the bakery algorithm. Section 4 adds thread
synchronisation to the framework and applies it to a large example, the reentrant
readers-writers problem. Section 5 draws conclusions and suggests future work.
2 Framework basics
The general approach is to take a piece of (parallel) code, and model it in a model
checker to detect bugs. Subsequently, after improving the model it will be subject
to verification in a theorem prover. To do this systematically, an embedding of the
semantics of the model checker in the theorem prover is required. In our case, we
use PVS as theorem prover and Promela as the modeling language. The embedding
presented in this paper is a mixed shallow/deep one: the framework is based on a
shallow embedding while the translation of the model into PVS exploits the native
features of PVS as much as possible, and hence can be seen as a deep embedding.
Transition system
In essence, a SPIN model is a state transition system with temporal logic. Our
framework reflects this directly by representing concurrently executing threads by
means of a state transition system. Each process runs in a thread. The semantics
of executing threads are captured in a theory that specifies that each thread is
either Running, Waiting, or Blocked. All threads have a threadid tid of type TID,
a program counter pc, a return address rtn and a local store local. The types
of these entities are provided as theory type parameters, and will be supplied by
the concrete (translated) Promela program. The theory parameter NT denotes the
number of concurrently executing threads.
Threads[NT:posnat, PC, LS, GS: TYPE] : THEORY BEGIN
TID : TYPE = below(NT)
1
1
Denotes the set of natural numbers between 0 and NT, exclusive of NT.

TStatus : TYPE = { Running, Waiting, Blocked }
TState : TYPE = [# tid: TID, status: TStatus, local:LS, pc , rtn: PC # ]
2
Threads : TYPE = [ TID TState]
System : TYPE = [# threads: Threads, current: TID, global: GS #]
currThread(s: System): TState = sthreads(s current)
3
END Threads
The entire system state consists of all the threads combined with the global variable
store global (again a theory type parameter), and a variable current signifying which
thread is currently executing. The utility function currThread yields the state of the
currently executing thread.
The (global) state transition relation of the system is determined by the (lo-
cal) state transition of the concurrently executing threads. The behavior of each
thread is specified by means of a step relation. This relation is defined in a separate
theory Model, also containing definitions of the entities required by Threads. This
Model theory, resulting from the translation of the Promela program (say P ), has
the following skeleton. Sections 3 and 4 show how this skeleton is instantiated for
different Promela models.
Model [ NT:posnat ] : THEORY BEGIN
PC:TYPE= below( ... number of instructions generated from P ... )
4
GV:TYPE= [# global variables appearing in P # ]
LV:TYPE= [# local variables of each thread in P # ]
IMPORTING Threads[NT, PC, LV, GV ]
step(lv1:TState,gv1:GV)(lv2:TState, gv2:GV): bool = generated from P
The effect of step is local, i.e. it only affects the local state of the currently executing
thread, and possibly the global state of the system. The local states of other threads
are untouched, which also follows from step’s type. To enforce this kind of locality
for the entire system, we introduce the parameterized predicate PredSys on System
that when applied to a system s, identifies all valid predecessors of s.
PredSys(s: System): pred[System ] =
{ p: System | (ot:TID): ot6=scurrent pthreads(ot) = s threads(ot) }
As usual, we will model parallel execution by non-deterministic interleaving. To
anticipate on the proving process we already include the notion of invariancy, by
means of an predicate on the System type, called invSystem. This leads to the fol-
lowing interleave relation, performing one execution step of a randomly selected
running thread.
interleave(ps:(invSystem)
5
, ss: System) : bool =
PredSys(ss)(ps) currThread(ps) status = Running
LET cs=ps WITH [ current = sscurrent]
6
IN
step(currThread(cs) ,csglobal)(currThread(ss) ,ssglobal)
2
Recordtypes in PVS are surrounded by [# and #].
3
r‘x denotes the selection of the x-component of record r.
4
below(n) denotes the set {0..n 1}.
5
PVS allows predicates to be used as types.
6
r WITH [‘x := e] denotes a new record that is equal to r except for the x-component
which has value e.

Theorems and proofs
PVS has no innate notion of deadlock or starvation, so these have to be defined ex-
plicitly. Deadlock states are usually defined as states for which there are no outgoing
edges. Although final states may have no outgoing edges, they are not considered as
deadlock states. Assume that zeroState denotes a predicate identifying these final
states, we can formulate deadlock-freeness as:
(s:(invSystem)): ¬ zeroState(s) (t:System): interleave(s , t)
This interpretation of deadlock is often not precise enough. Consider for example a
situation where a process executes a non terminating loop (because it is waiting for
something that will never occur). Then, it might be that all other threads are waiting
for this one to terminate before they can proceed. According to the definition there
would be no deadlock. To handle this situation a refined notion of deadlock-freeness
is needed. This refinement is based on the observation that if there exists a (well-
founded) order < on states such that from every non-final state s of the system
a transition can be made to a state t with t < s, then the system will be free of
deadlock. More formally:
NoDeadlock(s:(invSystem)) : bool =
¬ zeroState(s) (t:System): interleave(s , t) t < s
Proving deadlock-freeness of a system boils down to giving an appropriate state
ordering and showing that the generated step relation indeed has this NoDeadlock
property.
The previous theorem can also guarantee freedom from starvation, if fairness
of scheduling is imposed on the system. However, most (efficient) thread imple-
mentations do not provide this way of scheduling. Therefore, we introduce a more
sophisticated notion of starvation freedom that makes no specific assumptions on
the scheduling regimen. We base this notion on the following intuition: if a process
intends to perform a certain action it will eventually be able to. The intention is
signaled by a process entering a certain execution path. For instance, executing the
instruction that puts it on the path to enter a critical section. Execution of the
intended action is signaled by reaching the goal instruction, e.g. when the process
finally gets the permission to enter the critical section. This leads to the following
definitions, in which both intention and goal are specified as PC values.
NoStarvation(s:(invSystem) , t:TID, enter , goal:PC) : bool =
sthreads(t) PC = enter eventually(s , t , goal)
eventually(s1:(invSystem) , t:TID, goal:PC): RECURSIVE bool = (s2:System):
interleave(s1,s2) s2threads(t) pc = goal eventually(s2,t ,goal)
MEASURE noStarvationMeasure(s1,t)
In PVS all functions must be total. For recursive functions, such as eventually above,
a so called measure must be provided. This measure, based on some well-founded
order, ensures that at least one of the function arguments strictly decreases (accord-
ing to the order) at each recursive call, thus ensuring termination. In the case above,
termination also guarantees freedom of starvation, because only a finite number of
interleaving steps are possible before the thread reaches its goal. Proving the ab-
sence of starvation boils down to giving a proper definition of noStarvationMeasure.
In combination with deadlock-freeness this results in eventually reaching the goal. In
the sequel, we will also specify the state ordering for deadlock-freeness as a measure
with the obvious name noDeadlockMeasure.

In general, these measures will involve parts of the global system state as well
as properties of individual threads. In order to define and facilitate reasoning about
these measures the following small PVS theory proves to be very useful. It contains
a folding operation fsum that accumulates the results of a function fun, provided
as a parameter. The lemma relates the results of fsum applied to functions f and
g for which there exists at most one argument for which f and g produce different
results.
fsum(m:upto(N) ,fun: [below(N)nat] ):RECURSIVE nat =
IF m=0 THEN 0 ELSE fun(m-1)+fsum(m-1, fun) ENDIF MEASURE m
fsum_diff: LEMMA
(n:upto(N) ,k:below(n) ,f,g:[below(N)nat ] ):
((m:below(n)): m6=k f(m)=g(m)) fsum(n ,f)+g(k) = fsum(n,g)+f(k)
Translating Spin models to the framework
In this section we show how Promela programs are translated into our PVS frame-
work. Since we focus on concurrent systems in which processes communicate via
shared variables, it is not necessary to cover Promela completely. In particular,
the inter process communication via channels is left out. The core of the transla-
tion is the way Promela statements are treated. To facilitate a formal presentation,
we introduce an abstract syntax for Promela statements that serve as input to
the translator. As a result, we do not generate PVS directly, but make use of an
intermediate target language IL which can be converted almost directly into an
appropriate PVS theory. This is done to keep the core translation simple: some
peephole optimizations, in particular small transformations that reduce the state
space, can now be performed in a separate phase. The conversion from IL to PVS
is not fully elaborated but informally exemplified. The syntax of Abstract Promela
Statements is given in the left column of the table below.
s Denotes 0 or more and
<s> denotes 0 or 1 occurrences of s.
L : x, y, . . . local variables
G : X, Y, . . . global variables
V ::= L | G all variables
P : p, q, . . . procedure names
E
int
: 1, x + y, . . . integer expressions
E
bool
: true, x > 3, . . . boolean expressions
E ::= E
int
| E
bool
all expressions
SM : LOCK, UNLOCK, WAIT, TRANS, NOTIFY synchronization operations
PS ::= V <[E
int
]> := E
| if
G <else TE >
| do
G <else TE > od
| P
| atomic
PS
| G.SM
G ::= E
bool
TE
TE ::= h
PS, booli
IL ::= ASS V <[E
int
]> E
| GOTO PC
| SWITCH
(E
bool
, PC ) <PC >
| CALL P C
| RTN
| ATO
| OTA
| SM LI
PC ::= N
LI ::= N
Fig. 1: Syntax of Promela and the intermediate language IL.

Citations
More filters
Dissertation
01 Jan 2013
TL;DR: Using PVS (Prototype Verification System), it is proved that an industry designed scheduler for a smartcard personalization machine is safe and optimal and shows that theorem provers can be successfully used for industrial problems in cases where model checkers suffer from state explosion.
Abstract: Using PVS (Prototype Verification System), we prove that an industry designed scheduler for a smartcard personalization machine is safe and optimal. This scheduler has previously been the subject of research in model checked scheduling synthesis and verification. These verification and synthesis efforts had only been done for a limited number of personalization stations. We have created an executable model and have proven the scheduling algorithm to be optimal and safe for any number of personalization stations. This result shows that theorem provers can be successfully used for industrial problems in cases where model checkers suffer from state explosion.

41 citations

References
More filters
Journal ArticleDOI
Gerard J. Holzmann1
01 May 1997
TL;DR: An overview of the design and structure of the verifier, its theoretical foundation, and an overview of significant practical applications are given.
Abstract: SPIN is an efficient verification system for models of distributed software systems. It has been used to detect design errors in applications ranging from high-level descriptions of distributed algorithms to detailed code for controlling telephone exchanges. The paper gives an overview of the design and structure of the verifier, reviews its theoretical foundation, and gives an overview of significant practical applications.

4,159 citations


"A proof framework for concurrent pr..." refers methods in this paper

  • ...Using SPIN [5] as model checker, we investigate how (concurrent) Promela (the input language of SPIN) programs can be modeled in PVS [9]....

    [...]

  • ...This tabular specification is translated straightforwardly into SPIN and PVS....

    [...]

  • ...Using SPIN [5] as model checker, we investigate how (concurrent) Promela (the input language of SPIN) programs can be modeled in PVS [10]....

    [...]

  • ...Keywords: Formal Verification, Synchronization, Concurrency, PVS, SPIN....

    [...]

  • ...In essence, a SPIN model is a state transition system with temporal logic....

    [...]

Journal ArticleDOI
TL;DR: A detailed user guide is given which describes how to use the various tools of Uppaal version 2.02 to construct abstract models of a real-time system, to simulate its dynamical behavior, to specify and verify its safety and bounded liveness properties in terms of its model.
Abstract: This paper presents the overal structure, the design criteria, and the main features of the tool box Uppaal. It gives a detailed user guide which describes how to use the various tools of Uppaal version 2.02 to construct abstract models of a real-time system, to simulate its dynamical behavior, to specify and verify its safety and bounded liveness properties in terms of its model. In addition, the paper also provides a short review on case-studies where Uppaal is applied, as well as references to its theoretical foundation.

2,358 citations


"A proof framework for concurrent pr..." refers methods in this paper

  • ...For the purpose of developing consistent requirement specifications, [4] introduces a framework that is used for the transformation of transition systems (given as specifications in the model checker Uppaal [7]) to specifications in PVS....

    [...]

  • ...For the purpose of developing consistent requirement specifications, De Groot [4] introduces a framework that is used for the transformation of transition systems (given as specifications in the model checker Uppaal [8]) to specifications in PVS....

    [...]

Book ChapterDOI
15 Jun 1992

1,652 citations


"A proof framework for concurrent pr..." refers methods in this paper

  • ...Using SPIN [5] as model checker, we investigate how (concurrent) Promela (the input language of SPIN) programs can be modeled in PVS [10]....

    [...]

Book
31 May 2008
TL;DR: Principles of Model Checking offers a comprehensive introduction to model checking that is not only a text suitable for classroom use but also a valuable reference for researchers and practitioners in the field.
Abstract: Our growing dependence on increasingly complex computer and software systems necessitates the development of formalisms, techniques, and tools for assessing functional properties of these systems. One such technique that has emerged in the last twenty years is model checking, which systematically (and automatically) checks whether a model of a given system satisfies a desired property such as deadlock freedom, invariants, or request-response properties. This automated technique for verification and debugging has developed into a mature and widely used approach with many applications. Principles of Model Checking offers a comprehensive introduction to model checking that is not only a text suitable for classroom use but also a valuable reference for researchers and practitioners in the field. The book begins with the basic principles for modeling concurrent and communicating systems, introduces different classes of properties (including safety and liveness), presents the notion of fairness, and provides automata-based algorithms for these properties. It introduces the temporal logics LTL and CTL, compares them, and covers algorithms for verifying these logics, discussing real-time systems as well as systems subject to random phenomena. Separate chapters treat such efficiency-improving techniques as abstraction and symbolic manipulation. The book includes an extensive set of examples (most of which run through several chapters) and a complete set of basic results accompanied by detailed proofs. Each chapter concludes with a summary, bibliographic notes, and an extensive list of exercises of both practical and theoretical nature.

1,178 citations


"A proof framework for concurrent pr..." refers background in this paper

  • ...However, several modifications have been proposed to restrict the drawn numbers also leading to a finite state space [2]....

    [...]

Book
01 Jan 1990
TL;DR: A hybrid process algebra can be used for the specification, simulation, control and verification of embedded systems in combination with the environment, and for any dynamic system in general.
Abstract: Process algebra is the study of distributed or parallel syst em by algebraic means. Originating in computer science, process algebra has been extended in re ce t years to encompass not just discrete-event systems, but also continuously evolving ph enomena, resulting in so-called hybrid process algebras. A hybrid process algebra can be used for th e specification, simulation, control and verification of embedded systems in combination with the ir environment, and for any dynamic system in general. As the vehicle of our exposition, we use th e hybrid process algebra χ (Chi). The syntax and semantics of χ are discussed, and it is explained how equational reasoning simplifies tool implementations for simulation and verification. A bot tle filling line example is introduced to illustrate system analysis by means of equational reasonin g.

1,058 citations

Frequently Asked Questions (2)
Q1. What are the contributions mentioned in the paper "A proof framework for concurrent programs" ?

This paper presents a proof framework for verifying concurrent programs that communicate using global variables. 

Their future plans are to extend the framework in such a way that it covers the complete Promela language, e. g. by adding constructs for modeling message passing. Furthermore, the proof process can be partially automated by defining appropriate PVS-tactics to avoid repeating certain sequences of proof steps. Also, many auxiliary mappings of program counters to natural numbers that were needed to define proper measures, can be generated automatically.