<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>Towards Verifying Parallel Algorithms and Programs using Coloured Petri Nets</article-title>
      </title-group>
      <contrib-group>
        <aff id="aff0">
          <label>0</label>
          <institution>Department of Mathematics and Computer Science, Eindhoven University of Technology</institution>
          ,
          <country country="NL">The Netherlands</country>
        </aff>
      </contrib-group>
      <fpage>57</fpage>
      <lpage>71</lpage>
      <abstract>
        <p>description and generation of correct implementation code. We illustrate our idea by applying the technique to a parallel implementation of explicit state-space exploration.</p>
      </abstract>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>Introduction</title>
      <p>
        Parallel and distributed computing address important problems of scalability
in computer science, where some problems are too large or complex to be
handled by just one computer. Until now, focus has mostly been on distributed
algorithms, i.e., algorithms running on multiple computers communicating via a
network, as access to parallel computers, i.e., computers capable of running
multiple processes communicating via shared memory (RAM), has been limited. For
this reason, there are many papers on modeling distributed algorithms, such as
network protocols [
        <xref ref-type="bibr" rid="ref11 ref12 ref3 ref5">3, 5, 11, 12</xref>
        ]. With the advance of cheap multi-core processors
and cheap multi-processor systems, access to multiple core s has become more
common, and the development and analysis of algorithms for parallel processing
becomes very interesting. As parallel computing allows much faster
communication between processes, tasks that were not previously feasible or efficient to
do concurrently becomes interesting. In this paper, we present our experiences
developing parallel algorithms with synchronization mechanisms developed and
verified by means of coloured Petri nets (CPNs) [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ]. This work was motivated
by the requirement for a parallel state-space exploration a lgorithm. In this
paper, we provide an approach that allows us to extract a model for analysis from
a program or abstractly described algorithm in a systematic way. We do this in
a way that allows us to automatically generate a skeleton implementation of the
algorithm subsequently. We use a simple state-space algori thm as example, but
the approach has also been used for other parallel algorithms, such as parts of a
protocol for operational support [
        <xref ref-type="bibr" rid="ref16">16</xref>
        ].
      </p>
      <p>
        Classically, formal models can partake in a development in two different
ways: by extracting an implementation from a model, which we call model-driven
software engineering, or by extracting a model from an implementation, which
we call model-extraction . Our focus in this paper is on model-extraction but
in a way that allows us to also do code generation, thereby allowing a new
combined approach. The model-driven engineering approach is shown in Fig. 1
(top) and shows that we start with model which is verified according to one or
more properties. If it is ok, we can extract a program, and otherwise we refine the
model. Examples of this approach are within hardware synthesis [
        <xref ref-type="bibr" rid="ref17 ref9">9, 17</xref>
        ], using a
CPN simulator to drive a security system [
        <xref ref-type="bibr" rid="ref14">14</xref>
        ], or general code generation from a
restricted class of CPNs [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ]. The model-extraction approa ch is shown in Fig. 1
(bottom). Here, we do not start with a model, but rather with a program. From
the program, we extract a model and verify it for correctness. If an error is found,
the resulting error-trace is replayed on the original progr am to determine if it can
be reproduced here. If not, the abstraction used to extract the model is refined
and the cycle restarts. This approach is rarely used in the high-level Petri net
world, but is employed by, e.g., FeaVer [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ] to translate C code to PROMELA
code usable in SPIN [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ], Java PathFinder [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ] to translate Java programs to
PROMELA, SLAM [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ] for automatically translating C device drivers to boolean
programs, BLAST [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ] for model-checking C programs, and many other tools.
Both of these approaches may terminate the loop without providing a definite
response.
      </p>
      <p>The model-driven software engineering and model-extracti on approaches have
different strengths and weaknesses. The main strength of the model-driven
softUNIT
Fig. 1: Model-driven software engineering (top) and model- extraction (bottom).</p>
      <p>COUNTER_EXAMPLE
MODEL</p>
      <p>m
ware engineering approach is that it is possible to verify an algorithm before
implementation and we can even get a guaranteed-correct (te mplate)
implementation with little or no user-interaction. The disadvantag e is that the approach
is of little use for already existing software. The model-ex traction approach
precisely alleviates this by extracting a model from an existing implementation
automatically, ensuring there is correspondence between the model and
implementation. The main disadvantage is that we need an implementation of a,
perhaps faulty, algorithm before analysis can start.</p>
      <p>We would like to provide a translation supplying as many of the strengths
of these approaches as possible. By supporting model-extra ction in a way that
allows subsequent code generation, we can support both approaches plus a new
merged approach, shown in Fig. 2. Here we extract a model from a
description in one – possibly abstract – language, manually or autom atically refine the
abstraction until we can prove the system to be correct (optionally modifying
the original description if we find errors), and then extract an implementation.
While the last step seems superfluous if we already have an implementation, it
can be useful, for example, to use a program written in pseudo-code as input,
automatically derive and verify a model, and from the model extract a runnable
program in a desired implementation language. Alternatively, we can do
roundtrip engineering, where we take an implementation as input, verify and correct
it on the level of a model, and update the original implementation to reflect the
changes.</p>
      <p>
        To do this, we use systematic extraction and abstraction methods that can
be derived from a program or from an algorithm written in pseudo code. Our
approach builds on process-partitioned coloured Petri nets (PP-CPNs) as
described in [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ]. The use of a (slightly restricted class of) CPNs allows us to
refine data-structures as much as required and even using act ual data-structures
of the original algorithm or program. The restricted class of PP-CPNs allows
us to automatically generate executable code from the model. Derivation of
abstractions of the data-types used can be done by the user or au tomatically using
counter-example guided abstraction refinement (CEGAR) [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ] as implemented
in SLAM [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ] and BLAST [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ]. CEGAR automatically improves abstractions by
      </p>
      <sec id="sec-1-1">
        <title>1p`ropgroragmramp</title>
        <p>1</p>
        <p>PROGRAM
p p' 1`ininititiaial_l_aabbssttrraaccttioionn</p>
        <p>1
initial_abstraction
Refine
Program
c</p>
        <p>Model
Extraction
a
a</p>
        <p>Refine
Abstraction
m
()
p
ABSTRACTION</p>
        <p>MODEL
replaying errors found in an abstract model on the original program and using
about why a given error-trace cannot be replayed in the origi nal program to
refine the abstraction.</p>
        <p>
          In this paper we focus on model-extraction. Our goal is to pro vide a
proofof-concept, so we do certain steps that can be automated by ha nd, such as the
translation from code to a model using patterns. We do not address refinement
after discovery of errors in this paper, but assume an external library using
CEGAR or a user takes care of that. We have already treated the code generation
aspect in [
          <xref ref-type="bibr" rid="ref13">13</xref>
          ].
        </p>
        <p>
          The rest of this paper is structured as follows: in the next section, we
introduce process-partitioned coloured Petri nets as defined in [
          <xref ref-type="bibr" rid="ref13">13</xref>
          ] and a simple
algorithm for state-space generation which we use as runnin g example to
illustrate our idea. In Sect. 3, we introduce our approach to generating PP-CPN
models from algorithms using a naive parallel version of the algorithm presented
in Sect. 2. In Sect. 4, we use state-space generation to ident ify a problem in the
original parallelization, fix the problem and show that the problem no longer is
present in a modified version. Finally, in Sect. 5, we sum up our conclusions and
provide directions for future work.
2
        </p>
      </sec>
    </sec>
    <sec id="sec-2">
      <title>Background</title>
      <p>
        In this section, we briefly introduce process-partitioned C PNs as defined in [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ].
We also give a simple algorithm for explicit state-space gen eration which we use
as example in the remainder of the paper.
      </p>
      <p>Process-partitioned CPNs. Coloured Petri nets (CPNs) consist of places,
transitions, and arcs. Places are typed and arcs have expressions that may
contain variables. Places may contain tokens and we call the distribution of tokens
on all places a marking of the net, and the marking before executing any
transitions the initial marking. CPNs have a module concept, where subpages are
represented by substitution transitions.</p>
      <p>
        In [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ] we introduce the notion of process-partitioned CPNs (PP-CPNs).
These are CPNs, which are partitioned into separate kinds of processes. In this
paper, we are only interested in models containing a single kind of process, so
we just look at process subnets (Def. 2 in [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ]). A single process subnet is a
PP-CPN, but not necessarily the other way around, but in this paper, whenever
we talk about PP-CPNs, we assume they consist of exactly one p rocess subnet.
A process subnet is a CPN with a distinguished process colour set serving as
process identifier. The model in Fig. 6 (left) is an example of a PP-CPN (we
provide a detailed description of the model in Sect. 3). The process colour set
of this model is P. The places of a process subnet are partitioned into process
places, local places, and shared places (in [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ], we additionally introduce buffer
places for asynchronous communication between processes, but these are not
used here). These places correspond to the control flow, the local variables, and
shared variables of normal programs. Process places must have the process colour
set as type (in the example S and E and all unnamed places are process places),
local places must have a product of the process colour set and any other type as
type (in the example, s, b, and s’ ), and shared places can have any type (in the
example, Waiting and Visited).
      </p>
      <p>In the initial marking, exactly one of the process places must contain all
tokens of the process colour set and the remaining process places must be empty
(modeling that all processes must start in the same location in the program).
Local places must initially contain exactly one token for each process so that if
we project onto the component of the process colour set, we obtain exactly one
copy of all values of the set (modeling that all local variables must be initialized).
All shared places must contain exactly one value (modeling that shared variables
must be initialized). All arc expression must ensure that tokens are preserved.</p>
      <p>
        We have chosen to adopt the notion that we cannot create new processes
or destroy processes from [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ] even though nothing in our approach breaks if
we allow dynamic instantiation and destruction of processes. This is mainly for
simplicity as we did not need dynamic instantiation in our examples.
State-space Generation. State-space
generation is a means of analysis of
formal models, such as the ones specified by
means of CPNs. A simple implementation
is shown in Fig. 3. We start in the
initial marking of the model and compute
all enabled bindings. We then
systematically execute each, note the marking we
reach by executing bindings, store them
in Waiting, and repeat the procedure
for each of these newly discovered
markings. To also terminate in case of loops,
we store all markings for which we have
already computed successors in Visited
and avoid expanding them again. We
often call a marking a state in the context
of state-space analysis.
3
      </p>
      <p>Approach
1: Waiting ← { Model.initial()}
2: Visited ← { Model.initial()}
3: while Waiting 6= ∅ do
4: Pick a s ∈ Waiting
5: Waiting ← Waiting \ { s}
6: // Do any handling of s here
7: for all b enabled in s do
8: Execute b in s to get s′
9: if s′ ∈/ Visited then
10: Waiting ← Waiting∪{ s′ }
11: Visited ← Visited ∪ { s′ }</p>
      <p>
        We introduce our approach to verifying parallel algorithms by a parallel version
of the algorithm for generating state-spaces shown in Fig. 3 . The basic idea is
to use the loop of Fig. 3 for each process and share the use of Waiting and
Visited, naturally with appropriate locking. From this algorithm, we illustrate
our approach to extract a PP-CPN model. The last step, going f rom a PP-CPN
model to implementation code, is handled in [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ].
      </p>
      <p>A simple way to parallelize Fig. 3 is shown in Fig. 4 (left). Here, we
initialize as before (ll. 1–2). We have moved the main loop to a separa te procedure,
computeStateSpace. We perform mostly the same loop as before (ll. 16–24), but
instead of testing for emptiness and picking an element of the queue in three
steps, we do so using a procedure pickAndRemoveElement (ll. 17 and 24). The
implementation of pickAndRemoveElement (ll. 4–9) does the same as we did
before, except we return a bottom element ⊥ if no elements are available and
use that in the condition of the loop (l. 18). This forces us to perform the pick
in two places: before the first invocation of the loop (l. 17) and at the end of
the loop (l. 24). Handling of states (l. 19) and iteration over all enabled
bindings (ll. 20–21) is the same as before. Now, instead of checki ng if a state is a
member of Visited and conditionally adding it to the set, we do both in a
single step as shown in the procedure addCheckExists (ll. 22 and 11–14). We do
this under the assumption that adding an element to the set does nothing if the
element is already there. If the state was not already in Visited, we add it to
Waiting (l. 23). The reason for this re-organization is that we now as sume that
pickAndRemoveElement, addCheckExists, and the access to Waiting in line
23 are atomic, e.g., by creating a data-structure ensuring t his or by requesting a
lock for each data-structure before the start of an operatio n and releasing it
afterward. This allows us to start two instances of computeStateSpace in parallel
in lines 26–27. We will not argue for the correctness of neith er Fig. 3 nor Fig. 4
(left), but note that it is easy to convince ourselves that if one is correct, so is the
other with the assumption that pickAndRemoveElement and addCheckExists
happen atomically.</p>
      <p>Model Extraction. To go from Fig. 4 (left) to a PP-CPN model, we first
extract the control-flow of the algorithm including generat ing representations of
data, and then we refine the update of the data until we can prove the properties
of the model we want.</p>
      <p>
        Extracting the control-flow consists of creating the proces s places and
transitions of the model. We do that using templates, very similar to the
workflowpatterns [
        <xref ref-type="bibr" rid="ref15">15</xref>
        ] for low-level Petri nets. In Fig. 5 we show the p atterns necessary to
translate programs using our simple pseudo-code language t o a PP-CPN model.
From left to right the patterns match an atomic action (Atomic), a sequence of
two subprograms (S1; S2), a conditional branch (if condition then S1 else S2),
a while loop (while condition do S), and a critical section (atomic S). The
type P is the process colour set and for each pattern, the place S is the start
place and E the end place. All places created are process places except for the
Mutex place, which is a shared place. We put all processes on the start place
of the top level. We can add new templates or derive other constructs, such as
a simplified conditional branch omitting the else path, a repeat/until loop, a for
loop, and a for all loop.
      </p>
      <p>In the initial abstraction, we translate a condition to an unbound boolean
variable in the PP-CPN model. We add a local place for each loc al variable and
a shared place for each global variable. These are available on all subpages where
they are within the scope. In the initial abstraction, we approximate the type
1: Waiting ← { Model.initial()}
2: Visited ← { Model.initial()}
3:
4: proc pickAndRemoveElement() is
5: if Waiting = ∅ then
6: return ⊥
7: Pick a s ∈ Waiting
8: Waiting ← Waiting \ { s}
9: return s
10:
11: proc addCheckExists(s′ ) is
12: result ← s′ ∈/ Visited
13: Visited ← Visited ∪ { s′ }
14: return result
15:
16: proc computeStateSpace() is
17: s ← pickAndRemoveElement()
18: while s 6= ⊥ do
19: // Handle s here
20: for all b enabled in s do
21: Execute b in s to get s′
22: if addCheckExists(s′ ) then
23: Waiting ← Waiting ∪ { s′ }
24: s ← pickAndRemoveElement()
25:
26: computeStateSpace()
27: | computeStateSpace()
1: Waiting ← { Model.initial()}
2: Visited ← { Model.initial()}
3: MayAdd ← 0
4:
5: proc pickW ithCounter() is
6: s ← pickAndRemoveElement()
7: if s 6= ⊥ then
8: MayAdd ← MayAdd + 1
9: return s
10:
11: proc computeStateSpace() is
12: repeat
13: s ← pickW ithCounter()
14: while s 6= ⊥ do
15: // Do any handling of s here
16: for all b enabled in s do
17: Execute b in s to get s′
18: if addCheckExists(s′ ) then
19: Waiting ← Waiting ∪</p>
      <p>{ s′ }
MayAdd ← MayAdd − 1
s ← pickW ithCounter()
until MayAdd=0
20:
21:
22:
23:
24: computeStateSpace()
25: | computeStateSpace()
of all variables with UNIT, and local and shared places are not connected to
transitions.</p>
      <p>Applying this extraction to the computeStateSpace procedure of Fig. 4 (left)
and flattening it, we obtain Fig. 6 (left). Transitions are named after the line
number they correspond to and conditions after the performed tests. Assign To
Value stems from expanding the for all loop in line 18 to a while loop and line 19
has been omitted. We have instantiated the process twice (initial marking of S).
Abstraction Refinement. The initial abstraction allows execution of traces
not allowed in the original program. In the model in Fig. 6 (left), it is possible
to first terminate p(1) and have p(2) continue computation. This is not possible
in Fig. 4 (left). The model does find all possible interleavings of the process,
though, so if the state-space does not contain any erroneous states, neither will
the program.</p>
      <p>Abstraction refinement consists of using more elaborate types on local and
shared places, of adding arcs for reading and updating local and shared places,</p>
      <p>S
pIind P
Atomic
pid</p>
      <p>E
Out P</p>
      <p>S
pIind P</p>
      <p>S1 S1
pid
pid P</p>
      <p>S2 S2
pid</p>
      <p>E
Out P
if condition
then 1`pid
else empty
pid P</p>
      <sec id="sec-2-1">
        <title>ThenS1</title>
        <p>pid</p>
        <p>S
pIind P</p>
        <p>If</p>
        <p>E
Out P
if condition
then empty
else 1`pid
pid</p>
        <p>P
pid
ElseS2</p>
        <p>S
pInid P</p>
        <p>While
if condition
then 1`pid
else empty
pid
pid P</p>
        <p>S S
if condition
then empty
else 1`pid</p>
        <p>E
Out P</p>
        <p>Mutex
1 1t`rtureue pid P</p>
        <p>S
BOOL</p>
        <p>S
true
false
false
true</p>
        <p>S
pInid P
Acquire
pid
pid
pid P
Release
pid</p>
        <p>E
Out P
and of limiting the values of condition variables, often using values from the
local or shared places. Refinements must limit the behavior of previous models
(which formally must be able to simulate any refinement if we ignore local and
shared places), and must be true to the original program.</p>
        <p>The basic idea is to refine the types of places modeling local and global
variables and add tests accordingly. When we cannot determine an exact test or
update, we solve it by non-deterministically choosing amon g the possible values.
Here we only do a simple refinement to avoid the situation where one process can
decide that Waiting is empty just to have the other immediately afterward decide
it is not. For this, we refine the type of Waiting to a BOOL, indicating whether
the Waiting set is empty or not, and refine the type of s to indicate whether ⊥
was returned from isEmpty. The value of Waiting is initially false (as we add the
initial state in line 1 of Fig. 4 (left)) and we do not care about the initial value of
s, as it will be set before it is read. We make sure to read and update the values
of Waiting and s faithfully. Adding an element to Waiting (l. 23) implies setting
the value to true and for picking elements (ll. 17 and 24), we read the previous
value of Waiting, use that to set the value of s, and non-deterministically set the
value of the waiting set to true or false (though if the value already was true it
remains so) as we do not have enough information to know which is the correct
answer. We obtain the model in Fig. 6 (right). For readability, we have merged
the transitions 17 and 24, but this is not necessary for analysis. We no longer
can execute the erroneous trace on this refined model.
4</p>
      </sec>
    </sec>
    <sec id="sec-3">
      <title>Analysis</title>
      <p>The main reason we started this work in the first place is to analyze parallel
algorithms. Our focus is on new problems arising when creating parallel
algorithms, not on proving correctness of serial algorithms. We therefore assume that
pidS P2 11``Ppp.((a12l))l(+)+</p>
      <p>17
pid
pid P
pid</p>
      <p>24
pid</p>
      <p>if waitingNonEmpty</p>
      <sec id="sec-3-1">
        <title>While 18 tehlseen1e`mppidty</title>
        <p>if waitingNonEmpty
tehlseene1m`ppitdy E
if moreEnabledBindingspid P P
then empty
else 1`pid</p>
        <p>While 20
P if moreEnabledBindings
then 1`pid
else empty
pid
algorithms are correct under certain mutual-exclusion ass umptions, and search
for such violations. We are also interested in potential dead- and live-locks.
Assuming a valid refinement, we can ensure that absence of safety violations in the
model guarantees absence in the real program as we can simulate all executions
of the algorithm. This includes proving absence of mutual-e xclusion violations.
We cannot use our approach to ensure the absence of dead-lock s, as we deal
with over-approximations of the possible interleavings an d further restricting
the behavior may introduce new dead-locks, but we can still fi nd dead-locks and
remove them from the implementation.</p>
        <p>We can do state-space analysis of the derived models from Fig . 6, and obtain
a state-space with 81 states for the abstract model (left) an d a state-space with
130 states for the refined model. As the models do not have any critical regions,
they of course have no mutual exclusion violations.
Dead-locks and Live-locks. As all processes have a distinguished start and
end-state, we can recognize dead-locks and live-locks in th e model. A dead-lock
is a state without successors (a dead state) where not all processes reside on E.
Neither of the models in Fig. 6 has dead-locks; the model to th e left has exactly
one dead state, where all process ids reside on E and the shared and local places
retain their initial marking. The model in Fig. 6 (right) also has one dead state,
where all process ids reside on E, Waiting is true, s is true for all processes, and
all remaining local and shared places have their initial value.</p>
        <p>Live-locks are a harder to recognize. We only consider live- locks in the absence
of dead-locks. A model has a strong live-lock if the dead states of the model do
not constitute a home space, i.e., if it is not always possible to reach one of the
dead states. A strong live-lock in the model does not necessa rily imply a
livelock in the original algorithm, but can be used to identify parts of the original
program that should be further investigated. None of the models in Fig. 6 have
strong live-locks.</p>
        <p>A model may have a weak live-lock if its state-space has a loop. A loop may
also just indicate that a loop may execute an unbounded number of times. Both
models in Fig. 6 have loops, but analysis shows that the transition While 20
is impartial , i.e., that in any infinite execution it occurs an infinite number of
times. This happens if we compute infinitely many successors (the state-space
has infinitely many states), and makes sense in our algorithm.</p>
        <p>A particular interesting kind of live-lock is a loop reachab le from a state
where E contains tokens. This means that even after one of the processes have
terminated, the amount of work done by another process is unbounded. We have
already seen that Fig. 6 (left) exhibits this due to too abstract modeling, i.e.,
that process p(1) may decide that Waiting is empty initially and terminate, just
to have p(2) decide it is non-empty and continue computation. We have see n this
is not possible in the original algorithm, which caused us to refine the model to
Fig. 6 (right). We would therefore expect that no such live-l ock was present
in the refined model. Maybe surprisingly, one such does exist. This is seen by
having p(1) check Waiting in 17/24, modify Waiting to be empty, and successfully
continue. Then, p(2) checks Waiting, notices it is empty and terminates. Now,
p(1) continues. This is also possible in Algorithm 4 (left), and even quite likely
as the two processes will test Waiting initially, one of them will consume the only
element it contains initially, and other processes terminate. This also occurred in
reality in our first implementation of a parallel state-spac e exploration algorithm
using Algorithm 4 (left).</p>
        <p>To fix this, we notice that the reason p(2) terminates prematurely in the
previous example is that it decided to terminate while p(1) can still add new
states to Waiting. The idea of an improved algorithm is to ensure that no
processes may terminate when others may produce new states. This prompts us to
make Algorithm 4 (right). We reuse calculateStateSpace, addCheckExists, and
pickAndRemoveElement from Algorithm 4 (left) and define a new procedure
for picking, pickW ithCounter (ll. 5–9) which is used in place of the original
pickAndRemoveElement (ll. 13 and 21). We use MayAdd as a counter of the
number of processes which may add new states to Waiting. We add an
additional loop around the previous main loop ensuring we only quit when MayAdd
is zero. We inline the call to pickW ithCounter for the translation and use a
mutex around the call to ensure atomicity.</p>
        <p>We use the same approach to translate the model to a CPN model. We
maintain the abstraction of Waiting and do no abstraction of MayAdd, i.e.,
we increment and decrement it according to the algorithm. We implement the
mutex around the call to pickW ithCounter as a place with type UNIT containing
a single token acting as the mutex. We then obtain the model in Fig. 7. We
have not completely flattened it for readability and to keep resemblance with
the previous models in Fig. 6. At the left we have the loop in lines 13–21,
which mostly corresponds to Fig. 6 (right). The only changes are that aside from
renaming transitions to correspond with the line numbers of Algorithm 4 (right),
we have added a transition for the new line 20 causing some rerouting of the flow,
added a place representing MayAdd, and changed 13/21 (named 17/24 in Fig. 6)
to a substitution transition. We have modeled the new outer loop as a separate
page shown in Fig. 7 (top/right). We implement the semantics of a repeat/until
loop looping over the page in Fig. 7 (left). We share access to MayAdd. The
Test transition is explained later. The page corresponding to the substitution
transition modeling pickW ithCounter is shown in Fig. 7 (bottom/right). Again,
we share access to a local place (s) and two shared places (MayAdd and Waiting).
In all cases, the S and E places of a subpage is in port/socket relationship with
the input and output place of the corresponding substitution transition.</p>
        <p>We can use state-space analysis to verify that (for this confi guration) we do
not violate the mutex property in pickW ithCounter. The state-space for this
model contains 399 states and 934 bindings. We can check this explicitly by
looking at the total number of tokens on the four unnamed places in Fig. 7
(bottom/right). This is either 0 or 1, showing that never do we have more than
one process inside pickW ithCounter. The Test transition in Fig. 7 is added
to easily test whether it is ever possible for a process to execute lines 15–20
while another process has terminated, i.e., whether it is possible for a process to
terminate while there is still work to do. The transition requires a token from E,
i.e., a process that terminated and that the value of MayAdd is non-zero (this is
handled by the guard [n&lt;&gt;0], which has not been explained but exactly ensures
this). If Test is enabled in any state, it means that a process has terminated while
another has more work to do. State-space analysis shows this is not the case. This
is also a safety property, so absence of violations in the model implies absence of
violations in the original algorithm. We can prove the property without adding
Test by searching for a state where E has tokens and Waiting is false or one of
the unnamed places below While 14 contains tokens.</p>
        <p>We can convince ourselves that the mutex around pickWithCounter is
necessary by removing it and repeating analysis. We then get a state where Test is
enabled, and we can verify the same error is present in the original model (have
one process enter pickW ithCounter and consume the last element of Waiting,</p>
        <p>S 2 11``Ppp.((a12l))l(+)+
pIind P
13/p2i1ck
pid
pid P if isNotBottom(s)</p>
        <p>then empty</p>
        <sec id="sec-3-1-1">
          <title>While 14 else 1`pid</title>
        </sec>
      </sec>
      <sec id="sec-3-2">
        <title>OutE P</title>
        <p>(pid, s)
if isNotBottom(s)
then 1`pid
else empty
pid P</p>
        <p>While 16
if moreEnabledBindings
then 1`pid
else empty
then have the other process enter pickW ithCounter, notice there is no element
and return ⊥, and terminate, just to have the first process continue alone).</p>
        <p>In addition to the analysis of non-termination, we naturall y also check for
dead- and live-locks as before and find nothing unexpected. W hile Algorithm 4
(left) is quite simple and it is probably possible to convince oneself that it is
correct without verification, the introduction of MayAdd makes Algorithm 4
(right) sufficiently complicated that correctness is not immediately apparent. We
have verified the algorithm with up to 4 processes (yielding 55.709 states), which
is the configuration we use in practice. Verification has given us confidence that
the algorithm will work with any number of processes. We have also investigated
an extended version additionally adding a checkpointing mechanism where all
threads are paused while Waiting and Visited are written to disk in a consistent
configuration.</p>
        <p>
          We also used the method to verify the implementation of a slightly simplified
version of the protocol for operational support developed in [
          <xref ref-type="bibr" rid="ref16">16</xref>
          ]. The protocol
supports a client which sends a request to an operational support service, which
mediates contact to a number of operational support providers. The protocol
developed in [
          <xref ref-type="bibr" rid="ref16">16</xref>
          ] has support for running all participants on separate machines,
i.e., using asynchronous communication, but we are satisfied with an
implementation running the operational support server and providers on the same server.
We therefore have to send fewer messages, but need to access shared data on the
server. We devised a fine-grained locking mechanism using th e method devised
in this paper and proved that it enforced mutual exclusion and well as caused
no dead-locks, increasing our confidence that the implement ation works.
5
        </p>
      </sec>
    </sec>
    <sec id="sec-4">
      <title>Conclusion and Future Work</title>
      <p>
        We have sketched an approach for correct implementation of parallel algorithms.
The approach allows users to extract a model from an algorithm written in an
implementation or abstract language and verify correctness using state-space
analysis. The approach also facilitates the generation of skeleton implementation
code from the verified model using the approach from [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ] as we rely on
processpartitioned coloured Petri nets. Finally, we can also combine the two approaches,
which facilitates writing an algorithm in an abstract language, extract a model
for verification, and then extract a skeleton implementation.
      </p>
      <p>
        Verification of software by means of models is not new. Code-g eneration
from models have been used in numerous projects. The approach has been
most successful for generating specification of hardware from low-level Petri
nets and other formalisms to synthesize hardware such as computer chips [
        <xref ref-type="bibr" rid="ref17 ref9">9, 17</xref>
        ].
The approach has also been applied to high-level Petri nets t o generate lower
level controllers [
        <xref ref-type="bibr" rid="ref14">14</xref>
        ] and more general software [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ]. Model extraction was
pioneered by FeaVer [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ], which made it possible to extract PROMELA models
from C code using user-provided abstractions, and Java Path Finder [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ] which
did the same for Java programs. The approach has successfully been refined
using counter-example guided abstraction refinement (CEGAR) [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ] which was first
implemented by Microsoft SLAM [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ], which extracts and automatically refines
abstractions from C code for Microsoft Windows device drivers, and refined by
BLAST [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ]. While the tools for model-extraction support a fu ll development
cycle by abstraction refinement and reuse for modified implementations, the idea
of combining the two approaches is to the best of our knowledge new. The
combination allows some interesting perspectives. The perspective we have focused
on in this paper is the ability to write an algorithm in pseudo-code, extract a
model from the code, and generate an implementation in a real language.
Another perspective is supporting a full cycle as well, where we extract a model
from a program, find and fix an error in the model, and emit code that is merged
with the original code, supporting a cycle where we do not need to fix problems
on the original code but can do so at the model level. The use of coloured Petri
nets instead of a low-level formalism allows us to use the rea l data-types used in
the program instead of abstractions, much like how FeaVer allows using C code
as part of PROMELA models, but with the added bonus that the operations
are a true part of the modeling language rather than an extension that requires
some trickery to handle correctly.
      </p>
      <p>The work presented here is only in the initial stages, but looks very promising.
We have several ideas for future work. Currently, we have to manually extract
the model from patterns. This is tedious and error-prone, an d it would be nice
to have automatic extraction. Such a translation should implement the patterns
included in Fig. 5, but could also use explicit patterns for repeat/until loops
and other constructs. Given an implementation of the translation to and from
models, we could look at supporting a full development cycle allowing us to
update existing code with changes to the model.</p>
      <p>An implementation could also implement reduction rules like the one we
used to merge lines 17 and 24 in the model in Fig. 6 (right). We can also add
simplifications collapsing long traces of unconditional progress not modifying
any data to reduce the state-space without removing behavio r. For example, in
Fig. 7 we can remove transitions Assign To Value and 17, merging the input place
of Assign To Value and the output place of 17, to obtain a smaller state-space of
26.909 states for 4 processes, down from 55.709 states. We can also merge the
acquisition of a lock with the first regular transition (merging the transitions
Acquire Lock with 6 in Fig. 7 (bottom/right)) and merging releases with the
last. This reduces the state-space to 14.841 states.</p>
      <p>Currently, we provide abstractions manually. Like SLAM, we could easily
replay found errors on the original code and provide assistance in the
development of refinements, possibly even making them automatically. In our example,
replaying the early termination error trace found in Fig. 6 (left) on Algorithm 4
(left) would show that it is not possible for isEmpty to return false initially and
that it can only change from returning false to returning true if we execute line
23. Even though we might not be able to provide the abstraction refinement in
Fig. 6 (right) fully automatically, providing such diagnostics can be very useful
for the user for improving the refinement.</p>
      <p>
        Our current method focuses on parallel algorithms with a fixed number of
identical processes, but there is nothing in our approach preventing us from
extending this to also handle distributed settings with asynchronous
communication using buffer places and different kinds of processes; the code generation
in [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ] even supports that out of the box. While the fixed number of processes
used in this paper works well for simple algorithms, more advanced algorithms
may need to spawn processes. Nothing in our approach inherently forbids this,
but the code generation in [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ] does not support this out of the box. We believe
that it should be quite easy to devise a construction for starting new processes
and adapt the code generation to handle this.
      </p>
      <p>One thing our approach does not support very well at the moment is
intraprocedure calls. We can currently simulate this in simple cases by inlining
procedure calls, but this is not possible when using recursion. One way to fix it is
to view a recursive call as starting a new process for executing the child and
waiting for the result. If we support different kinds of processes, communication
between processes, and dynamic instantiation of processes, this should be easy
to add.</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          1.
          <string-name>
            <given-names>T.</given-names>
            <surname>Ball</surname>
          </string-name>
          and
          <string-name>
            <given-names>S.K.</given-names>
            <surname>Rajamani</surname>
          </string-name>
          .
          <article-title>The SLAM project: debugging system software via static analysis</article-title>
          .
          <source>In Proc. of POPL'02</source>
          , pages
          <fpage>13</fpage>
          -. ACM Press,
          <year>2002</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          2.
          <string-name>
            <given-names>D.</given-names>
            <surname>Beyer</surname>
          </string-name>
          ,
          <string-name>
            <given-names>T.A.</given-names>
            <surname>Henzinger</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R.</given-names>
            <surname>Jhala</surname>
          </string-name>
          , and
          <string-name>
            <given-names>R.</given-names>
            <surname>Majumdar</surname>
          </string-name>
          .
          <article-title>The Software Model Checker BLAST: Applications to Software Engineering</article-title>
          . STTT,
          <volume>7</volume>
          (
          <issue>5</issue>
          ):
          <fpage>5055</fpage>
          -
          <lpage>25</lpage>
          ,
          <year>2007</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          3.
          <string-name>
            <given-names>J.</given-names>
            <surname>Billington</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.C.</given-names>
            <surname>Wilbur-Ham</surname>
          </string-name>
          , and
          <string-name>
            <given-names>M.Y.</given-names>
            <surname>Bearman</surname>
          </string-name>
          .
          <article-title>Automa ted protocol Verification</article-title>
          .
          <source>In Proc. of IFIP WG 6.1 5th International Workshop on Protocol Specification, Testing, and Verification</source>
          , pages
          <fpage>597</fpage>
          -
          <lpage>0</lpage>
          . Elsevier,
          <year>1985</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          4.
          <string-name>
            <given-names>E.</given-names>
            <surname>Clarke</surname>
          </string-name>
          ,
          <string-name>
            <given-names>O.</given-names>
            <surname>Grumberg</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Jha</surname>
          </string-name>
          ,
          <string-name>
            <given-names>Y.</given-names>
            <surname>Lu</surname>
          </string-name>
          , and
          <string-name>
            <given-names>H.</given-names>
            <surname>Veith</surname>
          </string-name>
          .
          <article-title>Counterexample-Guided Abstraction Refinement for Symbolic Model Checking</article-title>
          .
          <source>J. ACM</source>
          ,
          <volume>50</volume>
          :
          <fpage>7527</fpage>
          -
          <lpage>94</lpage>
          ,
          <year>2003</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          5.
          <string-name>
            <surname>K.L. Espensen</surname>
            ,
            <given-names>M.K.</given-names>
          </string-name>
          <string-name>
            <surname>Kjeldsen</surname>
            , and
            <given-names>L.M.</given-names>
          </string-name>
          <string-name>
            <surname>Kristensen</surname>
          </string-name>
          .
          <article-title>Modelling and Initial Validation of the DYMO Routing Protocol for Mobile Ad-Hoc Networ ks</article-title>
          .
          <source>In Proc. of ATPN</source>
          , volume
          <volume>5062</volume>
          <source>of LNCS</source>
          , pages
          <fpage>1521</fpage>
          -
          <lpage>70</lpage>
          . Springer,
          <year>2008</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          <article-title>6. The FeaVer Feature Verification System webpage. Online: cm.bell-labs</article-title>
          .com/cm/ cs/what/feaver/.
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          7.
          <string-name>
            <given-names>K.</given-names>
            <surname>Havelund</surname>
          </string-name>
          and
          <string-name>
            <given-names>T.</given-names>
            <surname>Presburger</surname>
          </string-name>
          .
          <article-title>Model Checking Java Programs Using Java PathFinder</article-title>
          . STTT,
          <volume>2</volume>
          (
          <issue>4</issue>
          ):
          <fpage>3663</fpage>
          -
          <lpage>81</lpage>
          ,
          <year>2000</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          8.
          <string-name>
            <given-names>G.J.</given-names>
            <surname>Holzmann</surname>
          </string-name>
          .
          <source>The SPIN Model Checker. Addison-Wesley</source>
          ,
          <year>2003</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          9.
          <string-name>
            <given-names>IEEE</given-names>
            <surname>Standard System C Language Reference</surname>
          </string-name>
          <article-title>Manual</article-title>
          . IEEE-
          <volume>1</volume>
          <fpage>666</fpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          10.
          <string-name>
            <given-names>K.</given-names>
            <surname>Jensen</surname>
          </string-name>
          and
          <string-name>
            <given-names>L.M.</given-names>
            <surname>Kristensen</surname>
          </string-name>
          .
          <source>Coloured Petri Nets - Modelling and Validation of Concurrent Systems</source>
          . Springer,
          <year>2009</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          11.
          <string-name>
            <given-names>L.M.</given-names>
            <surname>Kristensen</surname>
          </string-name>
          and
          <string-name>
            <given-names>K.</given-names>
            <surname>Jensen</surname>
          </string-name>
          .
          <article-title>Specification and Validation of an Edge Router Discovery Protocol for Mobile Ad-hoc Networks</article-title>
          .
          <source>In Integration of Software Specification Techniques for Application in Engineering</source>
          , volume
          <volume>3147</volume>
          <source>of LNCS</source>
          , pages
          <fpage>2482</fpage>
          -
          <lpage>69</lpage>
          . Springer,
          <year>2004</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          12.
          <string-name>
            <surname>L.M. Kristensen</surname>
            ,
            <given-names>J.B.</given-names>
          </string-name>
          <string-name>
            <surname>Jørgensen</surname>
            , and
            <given-names>K.</given-names>
          </string-name>
          <string-name>
            <surname>Jensen</surname>
          </string-name>
          .
          <article-title>Application of Coloured Petri Nets in System Development</article-title>
          .
          <source>In Proc. of 4th Advanced Course on Petri Nets, number 3098 in LNCS</source>
          , pages
          <fpage>6266</fpage>
          -
          <lpage>85</lpage>
          . Springer,
          <year>2004</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          13.
          <string-name>
            <given-names>L.M.</given-names>
            <surname>Kristensen</surname>
          </string-name>
          and
          <string-name>
            <given-names>M.</given-names>
            <surname>Westergaard</surname>
          </string-name>
          .
          <article-title>Automatic Structure-Based Code Generation from Coloured Petri Nets: A Proof of Concept</article-title>
          .
          <source>In Proc. of FMICS'10 , LNCS</source>
          , pages
          <fpage>2152</fpage>
          -
          <lpage>30</lpage>
          . Springer,
          <year>2010</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          14.
          <string-name>
            <given-names>J.L.</given-names>
            <surname>Rasmussen</surname>
          </string-name>
          and
          <string-name>
            <given-names>M.</given-names>
            <surname>Singh</surname>
          </string-name>
          .
          <article-title>Designing a Security System by Means of Coloured Petri Nets</article-title>
          .
          <source>In Proc. ATPN'96</source>
          , volume
          <volume>1091</volume>
          <source>of LNCS</source>
          , pages
          <fpage>4004</fpage>
          -
          <lpage>19</lpage>
          . Springer,
          <year>1996</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref15">
        <mixed-citation>
          15.
          <string-name>
            <surname>W.M.P. van der</surname>
          </string-name>
          <article-title>Aalst and</article-title>
          K. van Hee.
          <source>Workflow Management: Models, Methods, and Systems</source>
          . MIT Press,
          <year>2002</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref16">
        <mixed-citation>
          16.
          <string-name>
            <given-names>M.</given-names>
            <surname>Westergaard</surname>
          </string-name>
          and
          <string-name>
            <given-names>F.M.</given-names>
            <surname>Maggi</surname>
          </string-name>
          .
          <article-title>Modelling and Verification of a Protocol for Operational Support using Coloured Petri Nets</article-title>
          .
          <source>In Proc. of ATPN</source>
          , LNCS. Springer,
          <year>2011</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref17">
        <mixed-citation>
          17.
          <string-name>
            <given-names>A.</given-names>
            <surname>Yakovlev</surname>
          </string-name>
          ,
          <string-name>
            <given-names>L.</given-names>
            <surname>Gomes</surname>
          </string-name>
          , and
          <string-name>
            <given-names>L. Lavagno. Hardware</given-names>
            <surname>Design</surname>
          </string-name>
          and
          <string-name>
            <given-names>Petri</given-names>
            <surname>Nets</surname>
          </string-name>
          . Kluwer Academic Publishers,
          <year>2000</year>
          .
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>