• No results found

Specification and verification of synchronization with condition variables

N/A
N/A
Protected

Academic year: 2021

Share "Specification and verification of synchronization with condition variables"

Copied!
16
0
0

Bezig met laden.... (Bekijk nu de volledige tekst)

Hele tekst

(1)

Contents lists available atScienceDirect

Science

of

Computer

Programming

www.elsevier.com/locate/scico

Specification

and

verification

of

synchronization

with

condition

variables

Pedro de C. Gomes

a

,

,

Dilian Gurov

a

,

Marieke Huisman

b

,

1

,

Cyrille Artho

a aKTHRoyalInstituteofTechnology,Stockholm,Sweden

bUniversityofTwente,Enschede,theNetherlands

a

r

t

i

c

l

e

i

n

f

o

a

b

s

t

r

a

c

t

Articlehistory: Received17May2017

Receivedinrevisedform2May2018 Accepted2May2018

Availableonline8May2018 Keywords:

Concurrency Formalverification Java

Conditionvariables

This paper proposes a technique to specify and verify the correctsynchronization of

concurrentprograms withcondition variables. Wedefine correctnessofsynchronization asthe livenessproperty: “everythread synchronizingunderaset ofcondition variables eventually exits the synchronization block”, under the assumption that every such thread eventually reaches its synchronization block. Ourtechnique does not avoid the combinatorial explosion of interleavings of thread behaviours. Instead, we alleviate it by abstracting away all details that are irrelevant to the synchronizationbehaviour of

theprogram,whichistypically significantlysmallerthanitsoverall behaviour.First,we introduceSyncTask, asimple imperative language to specify parallel computations that synchronizeviacondition variables. We consider aSyncTask program tohave acorrect synchronization iff it terminates. Further, to relieve the programmer from the burden of providing specifications in SyncTask, we introduce an economic annotation scheme forJavaprograms toassistthe automatedextraction ofSyncTaskprograms capturing the synchronizationbehaviouroftheunderlyingprogram.Weshowthatevery Javaprogram annotatedaccordingtothescheme(andsatisfyingtheassumptionmentionedabove)hasa correctsynchronizationiffitscorrespondingSyncTaskprogramterminates.Wethenshow howtotransformtheverificationofterminationoftheSyncTaskprogramintoastandard reachabilityproblemoverColoured PetriNetsthatisefficientlysolvablebyexistingPetri Netanalysistools.BoththeSyncTaskprogramextractionandthegenerationofPetriNets areimplementedinour STaVe tool.Weevaluatetheproposedframeworkonanumberof testcases.

©2018ElsevierB.V.Allrightsreserved.

1. Introduction

Conditionvariablesinconcurrentprograms.Conditionvariables (CV)areacommonlyusedsynchronizationmechanismto coor-dinatemultithreaded programs.Threadswait ona CV,meaningthey suspendtheirexecutionuntilanotherthread notifies theCV,causingthewaitingthreadstoresumetheirexecution.Thesignalling isasynchronous:theeffectofthenotification can be delayed.If nothread is waiting on theCV, then thenotification has noeffect. CVs are usedin conjunctionwith

*

Correspondingauthor.

E-mailaddresses:pedrodcg@kth.se(P. de C. Gomes),dilian@kth.se(D. Gurov),m.huisman@utwente.nl(M. Huisman),artho@kth.se(C. Artho). 1 SupportedbyERCgrant258405fortheVerCorsproject.

https://doi.org/10.1016/j.scico.2018.05.001 0167-6423/©2018ElsevierB.V.Allrightsreserved.

(2)

01 class Utilizer extends Thread { synchronized(lock) { 03 while (!resource_available) { lock.wait(); 05 } } 07 }

class Provider extends Thread { 09 synchronized(lock) { // prepare resource 11 resource_available = true; lock.notify(); 13 } }

Fig. 1. A simple Java program usingwait/notify.

locks;athreadmusthaveacquiredtheassociatedlockfornotifyingorwaitingonaCV,andifnotified,mustreacquirethe lock.

Many widely used programming languages feature condition variables. In Java, for instance, they are provided both nativelyasan object’smonitor [1], i.e., apair ofalockanda CV,andinthe

java.util.concurrent

library,as

one-to-many

Condition

objectsassociatedto a

Lock

object.C/C++ havesimilarmechanismsprovided bythe POSIXthread

(Pthread)library,andC++featuresCVsnativelysince2011 [2] asthe

std::condition_variable

class.Themechanism istypicallyemployedwhentheprogressofthreadsdependsonthestateofasharedvariable,toavoidbusy-waitloopsthat pollthestateofthissharedvariable.

Example1(ConditionvariablesinJava).Fig.1showsasimpleexamplewithtwothreads:Thefirstthread,Utilizer,wantsto useasharedresource.Theresourceisguardedwithacommonlock(line2)toensurethatonlyonethread,thelockholder, canchangethestateoftheresource.Becausenohigh-levelconstructslike

await(resource_available)

existinJava, theUtilizer threadhastocheckiftheconditionholdsbyusingaconditionalstatement(line3).Iftheconditionisfalse,the Utilizer suspendsitselfbycalling

wait

inline4.Thiscallimplicitlyrelinquishesthelock,toallowanotherthreadtoaccess itandmodifytheconditionvariable.Atsomepoint,anotherthreadmaymaketheresourceavailable.Thatthreadthenhas tosignalthestatechangetotheconditionvariable.Inourexample,threadProvider usesthesamelocktoaccesstheshared variable,andcalls

notify

tosignalachangeinline12.

Asaresultofthatsignal,oneofthewaitingthreadsiswokenup.Ithasfirsttore-checkthecondition,sinceitmighthave beenre-invalidatedbyanotherthreadinthemeantime.Todothis,thelockis(implicitly)re-acquired.Incaseanotherthread

hasalready consumedthe resource,and

resource_available

is againfalse, the

while

loop in line3 isre-entered.

Otherwise,the waiting threadmayproceed undertheassumption that

resource_available

istrue. Thisassumption

holdsifallaccessestothesharedconditionvariableareprotectedbyacommonlock,i.e.,ifthewholeprogramisdatarace free.

The

notify

methodwakesupanyonethreadthatiswaitingatthetimethenotificationissent;thereisnomechanism toensurethataparticularthreadgetswokenup.Ifmultiplewaitingthreadsmaycheckorusesharedconditionsindifferent ways(for example,by using a function overmultiple shared variables), thenotifying threadshould call

notifyAll

,to ensureeach waiting threadgets wokenuponce andcanre-check thecondition variabletoseeifthe“right” conditionis true.

WaitingthreadsmaygetinterruptedinrealJavaprograms,sothey havetoguardanycallto

wait

witha

try

/

catch

block,tocatchan

InterruptedException

.Furthermore,theJavaSpecification [3,§ 17.2] permits(butdiscourages)JVM implementationstoperformspuriouswake-ups,andreinforcesthecodingpracticeofinvoking

wait

insideloopsguarded byalogicalconditionnecessaryforthreadprogress.Weelidethesefunctionalitiesinourpaper.

Writingcorrectprogramsusingconditionvariablesischallenging,mainlybecauseofthecomplexity ofreasoningabout asynchronoussignalling. Nevertheless,condition variableshavenotbeen addressedsufficiently withformal techniques,to no smallpart dueto this complexity.For instance,Leino et al. [4] acknowledge that verifyingthe absence of deadlocks whenusingCVsishardbecauseanotificationis“lost”ifnothreadiswaitingonit.Thus,onecannotverifylocallywhether a waitingthread willeventually benotified.Furthermore,the synchronizationconditionscanbe quitecomplex,involving bothcontrol-flow anddata-flowaspectsasarising frommethodcalls;their correctnessthusdependsontheglobalthread composition,i.e.,thetypeandnumberofparallelthreads.Allthesecomplexitiessuggesttheneedforprogrammer-provided annotations toassisttheautomatedanalysis,whichistheapproachwearefollowinghere.

Inthiswork,wepresentaformaltechniqueforspecifyingandverifyingthat“everythreadsynchronizingunderasetof condition variableseventuallyexits thesynchronization”,undertheassumptionthat everysuch threadeventually reaches itssynchronizationblock.Theassumptionitselfisnotaddressedhere,asitdoesnotpertaintocorrectnessofthe synchro-nization,andtherealreadyexisttechniquesfordealingwithsuchproperties(see,e.g., [5]).Notethattheabovecorrectness notionappliestoaone-timesynchronization ona conditionvariableonly;generalizingthenotiontorepeated synchroniza-tions is left for futurework. Tothe best of our knowledge, the present work is the first to address a liveness property involving CVs. As theverification ofsuch properties isundecidable in general, we limit ourtechnique toprograms with boundeddatadomains anda boundednumberofthreads. Still,theverificationproblemissubjecttoacombinatorial ex-plosionofthreadinterleavings.Ourtechniquealleviatesthestate spaceexplosionproblembydelimitingtherelevantaspects ofthesynchronization.

(3)

SyncTask. First,we considercorrectnessofsynchronizationinthe contextofasynchronizationspecificationlanguage.Aswe targetarbitraryprogramminglanguagesthatfeaturelocksandconditionvariables,wedonotbaseourapproachonasubset ofanexistinglanguage,butinsteadintroduceSyncTask,asimpleconcurrentprogramminglanguagewhereallcomputations occur inside synchronizedcodeblocks.Wedefine a SyncTaskprogramto haveacorrectsynchronizationiffitterminates. The SyncTask language hasbeen designedto capturecommonpatterns ofCV usage, whileabstracting away from irrele-vant details. Ithas therelevantconstructs forsynchronization, such aslocks,CVs, conditionalstatements,andarithmetic operations. However, it isnon-procedural,datatypes arebounded, andit doesnot allowdynamic thread creation.These restrictionsrenderthestate-spaceofSyncTaskprogramsfinite,andmaketheterminationproblemdecidable.

Verificationofconcurrentprograms.Next,we address the problemofverifying the correctusage ofCVs inreal concurrent programminglanguages.WeshowhowSyncTaskcanbeusedtocapturethesynchronizationofaJavaprogram,providedit isbounded.Object-orientedlanguagessimilartoJava,suchasC++ andC#,can beanalyzedlikewise.Thereisaconsensus in SoftwareEngineering that synchronizationina concurrent program mustbe kept toa minimum,both in thenumber andcomplexityofthesynchronizationactions,andinthenumberofplaceswhereitoccurs [6,7].Thisavoidsthelatencyof blockingthreads,andminimizestheriskoferrors,suchasdead- andlive-locks.Asaconsequence,manyprogramspresenta finite(thougharbitrarilylarge)synchronizationbehaviour.Thatis,thenumberofvariablesinvolvedinthesynchronization, andtheirdatadomainsarebounded.

Implementation.ToassisttheautomatedextractionoffinitesynchronizationbehaviourfromJavaprogramsasSyncTask pro-grams,weintroduceanannotationscheme,whichrequirestheuserto(correctly)annotate,amongothers,theinitializationof newthreads(i.e.,creationof

Thread

objects),andtoprovidetheinitialstateofthevariablesaccessedinsidethe synchro-nizedblocks.WeestablishthatforcorrectlyannotatedJavaprogramswithboundedsynchronizationbehaviour,correctness ofsynchronizationisequivalenttoterminationoftheextractedSyncTaskprogram.

As a proof-of-concept ofthealgorithmic solvabilityof theterminationproblemfor SyncTaskprograms, we show how totransformitintoareachabilityproblemonhierarchicalColoured PetriNets2 (CPNs) [8].WedefinehowtoextractCPNs

automatically from SyncTask programs, following a previous technique fromWestergaard [9]. Then, we establish that a SyncTaskprogramterminatesifandonlyif theextractedCPNalwaysreachesdeadmarkings(i.e.,CPNconfigurationswithout successors)wherethetokensrepresentingthethreadsareinauniqueendplace.StandardCPNanalysistoolscanefficiently compute thereachabilitygraphs,andcheckwhethertheterminationconditionholds.Also,incasethattheconditiondoes nothold,aninspectionofthereachabilitygrapheasilyprovidesthecauseofnon-termination.

Evaluation. We implement the extraction ofSyncTask programs fromannotated Java andthe translationof SyncTasks to CPNs as the STaVe tool. We evaluate the tool on two test-cases, by generating CPNs fromannotated Java programs and analyzingthesewithCPNTools [10].Thefirsttest-caseevaluatesthescalabilityofthetoolw. r. t. thesizeofprogramcode thatdoesnotaffectthesynchronizationbehaviouroftheprogram.Thesecondtest-caseevaluatesthescalabilityofthetool w. r. t. the numberofsynchronizingthreads.Theresultsshowtheexpectedexponentialblow-up ofthestate-space,butwe werestillabletoanalyzethesynchronizationofseveraldozensofthreads.

In summary,thisworkmakes thefollowingcontributions: (i) theSyncTasklanguageto modelthesynchronization be-haviour of programs withCVs, (ii) an annotationscheme to aid the extraction ofthe synchronization behaviour of Java programs,(iii) anextractionschemeofSyncTaskmodelsfromannotatedJavaprograms,(iv) areductionofthetermination problemforSyncTaskprograms toa reachabilityproblemonCPNs,(v) animplementationoftheframework by meansof STaVe,and(vi) itsexperimentalevaluation.

Outline.Theremainderofthepaperisorganizedasfollows.Section2introducesSyncTask.Section3describesthemapping from annotated Java to SyncTask, while Section 4 presents the translation into CPNs. Section 5 presents STaVe and its experimentalevaluation.WediscussrelatedworkinSection6.Section7concludesandsuggestsfuturework.

2. SyncTask

SyncTaskabstractsfrommostfeaturesoffull-fledgedprogramminglanguages.Forinstance,itdoesnothaveobjects, pro-cedures,exceptions,etc.However,itfeaturestherelevantaspectsofthreadsynchronization.Wenowdescribethelanguage syntax,types,andsemantics.

2.1. Syntaxandtypes

The SyncTask syntax is presentedin Fig.2. Aprogram has two mainparts: ThreadType*, whichdeclares the different typesofparallelexecutionflows,andMain,whichcontainsthevariabledeclarationsandinitializationsanddefineshowthe threadsarecomposed,i.e.,itstaticallydeclareshowmanythreadsofeachtypearespawned.

2 Thechoiceofformalismhasbeenmainlybasedonthesimplicity ofCPNsasageneralmodelofconcurrency,ratherthanontheexistingsupportfor efficientmodelchecking.Forthelatter,modelcheckingtoolsexploitingparametricityorsymmetriesinthemodelsmayprovemoreefficientinpractice.

(4)

SyncTask ::= ThreadType* Main

ThreadType ::= ThreadThreadName{SyncBlock*}

Main ::= main {VarDecl* StartThread*}

StartThread ::= start(Const,ThreadName);

Expr ::= Const|VarName|ExprExpr

| min(VarName)| max(VarName)

VarDecl ::= VarType VarName(Expr*); VarType ::= Bool| Int | Lock | Cond

SyncBlock ::= synchronized (VarName)Block

Block ::= {Stmt*}

Assign ::= VarName=Expr;

Stmt ::= SyncBlock|Block | Assign| skip; | whileExpr Stmt | ifExpr StmtelseStmt | notify(VarName); | notifyAll(VarName); | wait(VarName);

Fig. 2. SyncTask syntax.

01 Thread Producer { synchronized(m_lock){ 03 while(b_els==max(b_els)){ wait(m_cond); 05 } if (b_els<max(b_els)) { 07 b_els=(b_els+1); } else { 09 skip; } 11 notifyAll(m_cond); } 13 } Thread Consumer { 15 synchronized(m_lock){ while((b_els==0)){ 17 wait(m_cond); } 19 if((b_els>0)) { b_els=(b_els-1); 21 } else { skip; 23 } notifyAll(m_cond); 25 } } 27 main { Lock m_lock(); 29 Cond m_cond(m_lock); Int b_els(0,7,1); 31 start(2,Consumer); start(1,Producer); 33 }

Fig. 3. Modelling of synchronization via a shared buffer in SyncTask.

EachThreadType consistsofadjacentSyncBlocks, whicharecriticalsectionsdefinedby acodeblock anda lock.A code

block is defined as a sequence of statements, which may even be another SyncBlock. Notice that this allows nested

SyncBlocks,thusenablingthedefinitionofcomplexsynchronizationschemeswithmorethanonelock.

There are fourprimitive types:booleans (

Bool

), bounded integers (

Int

), reentrantlocks (

Lock

), andcondition vari-ables (

Cond

).ExpressionsareevaluatedasinJava.TheBooleanandintegeroperatorsarethestandardones,while

max

and

min

returnavariable’sbounds.Operationsbetweenintegerswithdifferentbounds(overloading)areallowed.However,an out-of-boundsassignmentleadstheprogramtoanerrorconfiguration.

Conditionvariables aremanipulatedby theunaryoperators

wait

,

notify

,and

notifyAll

.Currently, thelanguage providesonlytwocontrolflow constructs:

while

and

if-else

.Thesesufficefortheillustrationofourtechnique,while theadditionofotherconstructsisstraightforward.

The Main block contains the global variable declarations with initializations (VarDecl*), and the thread composi-tion (StartThread*). A variable is defined by declaring its type and name, followed by the initialization arguments. The numberofparametersvariespertype:

Lock

takesnoarguments;

Cond

isinitializedwithalockvariable;

Bool

takes ei-thera

true

ora

false

literal;

Int

takesthreeintegerliteralsasarguments:thelowerandupperbounds,andtheinitial value,whichmustbeinthegivenrange.Finally,

start

takesapositivenumberandathreadtype,signifyingthenumber ofthreadsofthattypethatitspawns.

Example2 (SyncTaskprogram). The program inFig. 3models synchronization via a sharedbuffer.

Producer

and

Con-sumer

representthesynchronizationbehaviour: threadssynchronizeviatheCV

m_cond

toaddorremoveelements,and wait ifthebuffer isfull orempty, respectively. Waiting threads arewoken upby

notifyAll

afteran operationis per-formedonthebuffer,andcompeteforthemonitortoresumeexecution.The

main

blockcontainsvariabledeclarationsand initialization.Thelock

m_lock

isassociatedto

m_cond

.

b_els

isaboundedintegerintheinterval[0,7],withinitialvalue

setto

1

,andrepresentsthenumberofelements inthebuffer.One

Producer

andtwo

Consumer

threads arespawned

with

start

.

NoticethatthisSyncTaskprogramsimulatestheusageofaJavamonitorsinceitusesapairoflockandCVfor synchro-nization.However,itcouldbemoreefficientlyimplementedwithtwoCVsassociatedtothesamelock:onetonotifywhen thebuffer isfull,andanotherwhenitis empty.Thisalternative approachsimulatestheusage of

Condition

and

Lock

fromthe

java.util.concurrent

concurrencypackage. 2.2. Structuraloperationalsemantics

WenowdefinethesemanticsofSyncTask,toprovidethemeansforestablishingaformalcorrectnessresult.

Thesemanticdomainsaredefinedasfollows.Booleansarerepresentedasusual.Integervariablesaretriples

Z × Z × Z

, where thefirst two elements are the lower andupperbound, andthe thirdis the currentvalue. Alock o is definedas

(

Thread_id

× N

+

)

∪ ⊥

,whichiseither

ifthelockisfree,orapairoftheidofthethreadholdingthelock,andacounter ofhowmanytimesthelockwasacquiredbythisthread.

(5)

[s1]a T|(θ, synchronized(o)b,R),μ−→T|(θ, synchronized’(o)b,R),μ[o→ (θ,1)] [s2]b T|(θ, synchronized(o)b,R),μ−→T|(θ, synchronized’(o)b,R),μ[o→ (θ,n+1)] [s3]b T|(θ,b1,R),μ−→T|(θ,b2,X),μ  T|(θ, synchronized’(o)b1,R)),μ−→T|(θ, synchronized’(o)b2,X),μ [s4]c T|(θ, synchronized’(o),R)),μ−→T|(θ,,R),μ[o→ (θ,n−1)] [s5]d T|(θ, synchronized’(o),R),μ−→T|(θ,,R),μ[o→ ⊥] [wt]e T|(θ, wait(d),R),μT|(θ,, (W,d,n)),μ[lock(d)→ ⊥] [nf1]ef T|(θ, notify(d),R),μT|(θ,,R),μ [nf2]eg T|(θ, notify(d),R)|(θ,t, (W,d,n)),μT|(θ,,R)|(θ,t, (N,d,n)),μ [na1]ef T|(θ, notifyAll(d),R),μT|(θ,,R),μ [na2]egT|(θ, notifyAll(d),R)|TWd T|(θ,,R)|{(θ,t, (N,d,n))|(θ,t, (W,d,n))TdW},μ [rs]h T|(θ,t, (N,d,n)),μT|(θ,t,R),μ[lock(d)→ (θ,n)] aμ(o)= ⊥ bμ(o)= (θ,n) cμ(o)= (θ,n)n>1 dμ(o)= (θ,1) eμ(lock(d))= (θ,n) fwaitset(d)= ∅ gwaitset(d) = ∅ hμ(lock(d))= ⊥

Fig. 4. Operational rules for synchronization.

Aconditionvariabled onlymapstoitsassociatedlock(Lock isthedatadomain);hereiswheretheone-to-manyrelation from lockstoCVs is defined. Theauxiliary function lock

(

d

)

returns theassociated lockto d.Notethat the setofthreads waitingonaconditionvariableisnot storedontheCVitself;belowwedefinethatthisisstoredatthethreadstate.

SyncTaskcontains globalvariables only,andall memoryoperationsaresynchronized.Thus,weassume thememoryto be sequentiallyconsistent [11].Let

μ

representaprogram’s memory.Wewrite

μ

(

l

)

todenotethevalue ofvariable l,and

μ

[

l

→

v

]

todenotetheupdateof l in

μ

withvalue v.

A threadstate iseitherrunning (R)ifthe threadis executing,waiting (W ) ifithas suspendedthe executionona CV, ornotified (N)ifanotherthreadhaswokenup thesuspendedthread,butthelockhasnotbeenreacquiredyet.Thestates W and N alsocontaintheCVd that athreadis/waswaiting on,andthenumbern oftimesitmustreacquirethelockto proceedwiththeexecution.Theauxiliaryfunctionwaitset

(

d

)

returnstheid’sofallthreadswaitingonaCV d.

We represent a thread as

(θ,

t

,

X

)

, where

θ

denotes its id, t the executing code, and X its thread state. We write T

= (θ

i

,

ti

,

Xi

)

|(θ

j

,

tj

,

Xj

)

for a parallel thread composition, with

θ

i

= θ

j. Also, T

|(θ,

t

,

X

)

denotes a thread composition,

assuming that

θ

is notdefinedin T .Forconvenience,we abusesetnotation todenotethe compositionofthreads inthe set;e.g., TdW

= {(θ,

t

,

(

W

,

d

,

n

))

}

representsthecompositionofallthreadsinthewait setofd.Aprogramconfiguration isa pair

(

T

,

μ

)

ofthethreads’compositionanditsmemory.Athreadterminatesiftheprogramreachesaconfigurationwhere its code t isempty (



); aprogram terminatesifall its threads terminate.We saythat a SyncTaskprogram hasa correct synchronization iffitterminates.

The initialconfigurationisdefinedwiththedeclarationsinMain.Asexpected, thevariableinitializations settheinitial valueof

μ

.Forexample,

Int

i(lb,ub,v)

definesanewvariablesuchthat

μ

(

i

)

= (

lb

,

ub

,

v

),

lb

v

ub,and

Lock

o()

initializes a lock

μ

(

o

)

= ⊥

. The thread composition is definedby the

start

declarations; e.g.,

start(2,t)

adds two threadsoftype

t

tothethreadcomposition:

(θ,

t

,

R

)

|(θ



,

t

,

R

)

.

Fig. 4 presents the operational rules, with superscripts ah denoting conditions. Rule names withprefixes s, wt, nf, na and rs are short for synchronized, wait, notify, notifyAll and resume, respectively. We only define the rules for the synchronizationstatements,astherulesfortheremainingstatementsarestandard [12,§ 3.4-8].

In rule[s1],athreadacquiresa lock,ifavailable,i.e., ifitisnot assignedto anyotherthreadandthecounter iszero. Rule [s2] represents lockreentrancy andincreases the lock counter. Both rules replace

synchronized

witha primed versiontodenotethattheexecutionofsynchronizationblockhasbegun.Rule[s3]appliestothecomputationofstatements inside synchronizedblocks,andrequiresthatthe threadholdsthelock.Rule [s4]decreasesthecounter uponterminating theexecutionofasynchronizedblock,butpreservesthelock.Inrule[s5],athreadfinishestheexecutionofasynchronized block,andrelinquishesthelock.

Inthe[wt]rule,athreadchangesitsstateto W ,storesthecounteroftheCV’slock,andreleasesit.Therules[nf1]and [na1]applywhenathreadnotifiesaCVwithanemptywaitset;thebehaviouristhesameasforthe

skip

statement.By rule [nf2],a threadnotifiesaCV, andone threadinitswait setisselectednon-deterministically, andits state ischanged

(6)

Resource annotation:

@resource [ResourceId](classes)

[@object Id [-> Sid]] @value Id [-> Sid] @capacity Id [@defaultval Int] [@defaultcap Int] @predicate(methods)

@inline [@maps Id->@{ Code }@] @code -> @{ Code }@

@operation(methods)

@inline [@maps Id->@{ Code }@] @code -> @{ Code }@

Synchronization annotation:

@syncblock [ThreadId](synchronized blocks)

@resource Id[:ResourceId] -> Sid @lock Id -> Sid

@condvar Id -> Sid @monitor Id -> Sid

Initialization annotation:

@synctask [STid](methods)

@resource Id[:ResourceId] -> Sid @lock Id -> Sid

@condvar Id -> Sid @monitor Id -> Sid @thread [Int:ThreadId]

Fig. 5. Annotation language for Java programs.

to N.Rule[na2]issimilar, butall threadsinthewaitsetare awoken.Bytherule[rs],athreadreacquiresallthelocksit hadrelinquished,changesthestateto R,andresumestheexecutionafterthecontrolpointwhereitinvoked

wait

. 3. FromannotatedJavatoSyncTask

Theannotationprocesssupportedby STaVe reliesontheprogrammer’sknowledgeabouttheintendedsynchronization, andconsistsofprovidinghintstothetooltoautomaticallymapthesynchronizationtoaSyncTaskprogram.Inthissection we present an annotationscheme for writingsuch hints,illustrate SyncTask extraction on an example,define ournotion ofsynchronizationcorrectness forJavaprograms, andcharacterizethenotionasterminationofthecorrespondingSyncTask program.

3.1. AnannotationlanguageandannotationschemeforJava

An annotationin STaVe binds toa specifictype ofJava declaration (e.g.,classes ormethods). Theannotationstarts in a commentblock immediatelyabove adeclaration,withadditionalannotationsinside thedeclaration’sbody.Annotations sharecommonkeywords(thoughwithadifferentsemantics), andoverlapinthedeclarationtypesthey maybindto.The ambiguityisresolvedbythefirstkeyword (calledaswitch)foundinthecommentblock.Commentsthatdonotstartwith akeywordareignored.

Fig.5presentstheannotationlanguage.Argumentsgivenwithinsquarebracketsareoptional,allowingtheprogrammer to(attempt to) leavetheir inference to STaVe, whiletext withinparenthesestellswhich declarationtypestheannotation binds to. The programmer has to provide, by means of annotations, the following threetypesofinformation: resources, synchronizationandinitialization.Below, wedescribetheseinformationtypes,andhow theyshouldbe provided,i.e.,our annotationscheme.

A resource annotates data types of variables that are manipulated by the synchronizationand influence its progress, such as loop guards. The annotationdefines an abstraction ofthe data structure state into a bounded integer, andhow the methods operate onit. Potentially the boundedinteger is a ghostvariable (as in [13]),andin this casewe say that thevariableextends theprogram memory.Forexample,theannotationabstractsalinked listorabufferto itssize.More elaborated, compounddatatypesmaybe annotated, suchasstacks orlistscontaining elements fromaboundeddomain. However,ifathread’sprogressdependsonanelement’svalue,thenthestructurecannotbeabstractedintoasinglebounded integer;instead,werequireaninitializationannotation(seebelow)foreachelementofthedatastructure.

Resourcesbindtoclassesonly.Theswitch

@resource

startsthedeclaration.Incasethataresourcedefinitionisspread acrossseveralclasses(becauseofinheritance),itrequiresacommon

ResourceId

foreachannotatedclass.The

@object

keyword is optionaland instructs STaVe thatthe data structure to analyze is a given variable orfield in theannotated class.

@value

defines whichclass member, orghost variable, storesthe abstract state. Both allow an optionalmapping

to an alias Sid, which becomes mandatory incase the resource is definedin more than one class.

@capacity

defines

theupperboundfor

@value

.

@defaultval

and

@defaultcap

definetheresource’sdefault

@value

and

@capacity

,

respectively; these may be overwritten in the initializationannotation (see below). The keyword

@operation

binds to methoddeclarations,andspecifies thatthe methodpotentiallyalterstheresource state.Similarly,

@predicate

bindsto methodsandspecifiesthatthemethodreturnsapredicateaboutthestate.

There are two ways to extract an annotated method’s behaviour.

@code

tells STaVe not to process the method, but instead toassociate itto thecode enclosed between

@{

and

}@

,while

@inline

tells STaVe totry toinfer the method declaration. The inline is potentially aided by

@maps

declarations, which syntactically replaces a Java command (e.g., a methodinvocation)withaSyncTaskcodesnippet.

The synchronization annotation defines the observation scope. It binds to

synchronized

blocks andmethods, and

(7)

01 class Producer extends Thread { Buffer pbuf;

03 Producer(Buffer b){pbuf=b;} public void run() { 05 /*@syncblock @monitor pbuf -> m 07 @resource pbuf:Buffer->b_els*/ synchronized(pbuf) { 09 while (pbuf.full()) pbuf.wait(); 11 pbuf.add(); pbuf.notifyAll(); 13 } } 15 }

class Consumer extends Thread { 17 Buffer cbuf;

Consumer(Buffer b){cbuf=b;} 19 public void run() {

/*@syncblock 21 @monitor cbuf -> m @resource cbuf:Buffer->b_els*/ 23 synchronized(cbuf) { while (cbuf.empty()) 25 cbuf.wait(); cbuf.remove(); 27 cbuf.notifyAll(); } 29 } }

31 /*@resource @capacity cap @object els -> els 33 @value els -> els */

class Buffer {

35 int els; final int cap; /* @operation @inline */ 37 void remove(){if (els>0)els--;}

/* @operation @inline */ 39 void add(){if (els<cap)els++;}

/* @predicate @inline */

41 boolean full(){return els==cap;} /* @predicate @inline */

43 boolean empty(){return els==0;} /*@synctask Buffer

45 @monitor b -> m

@resource b:Buffer->b_els */ 47 static void main(String[] s) {

Buffer b = new Buffer(); 49 b.els = 1; b.cap = 7;

/* @thread */

51 Consumer c1 = new Consumer(b); /* @thread */

53 Consumer c2 = new Consumer(b); /* @thread */

55 Producer p = new Producer(b); c1.start();

57 p.start(); c2.start(); 59 }

}

Fig. 6. Annotated Java program synchronizing via shared buffer.

in casethe annotationis definedin morethan one method orblock. Nested,inner synchronization blocksandmethods are not annotated; allthe requiredinformation hasto beprovided atthe top-levelannotation. Here,

@resource

isnot a switch, and thus has a different meaning. It defines that a local variable Id is a reference to a shared object of an (optional) annotatedresourcetype(ResourceId), andisreferencedbyan alias

Sid

acrossother

@syncblock

declarations.

The keywords

@lock

and

@condvar

define which mutex and condition variable object are observed.

@monitor

has

the combinedeffect ofboth keywords foran object’smonitor, i.e.,a pair ofa lockanda condition variable.Similarlyto

@resource

,theserequireamappinganaliasthatiscommontoothersynchronizationdeclarations.

Initialization annotationsdefinetheglobalpre-conditionfortheelements involvedinthesynchronization, i.e.,they de-fine initialvaluesforlocks,condition variablesandresourcedeclarations.Theyalsodefine theglobalthreadcomposition, i.e.,howmanyandwhichtypeofthreadsparticipateinthesynchronization.Initializationsbindtomethods,andtheswitch

@synctask

startsthedeclaration.Here,

@resource

,

@lock

,

@condvar

and

@monitor

instantiatewithprogram vari-ables the shared aliases defined at

@syncblock

. Finally,

@thread

defines that the following object corresponds to a spawnedthreadthatsynchronizeswithintheobservedsynchronizationobjects.Theobject’stypeisautomaticallydetected, andmusthavebeenannotatedwithasynchronizationannotation.Alternatively,theannotationcanbefollowedbyathread typeandanumberindicatinghowmanyofthesearespawned,sothatthethreadinstantiationbecomeslessverbose.

Some oftheaboveinformation STaVe iscapableofinferringitself; theremaininginformationneeds tobeprovidedby the programmer. STaVe will always indicatewhen theprovided hints areinsufficient. Thisis discussedin moredetail in Section5.

Example3(AnnotatedJavaprogram).TheSyncTaskprograminFig.3wasgeneratedfromtheJavaprograminFig.6.Wenow discusshowtheannotationsdelimittheexpectedsynchronization,indirectlyillustratingtheSyncTaskextraction.

The

@syncblock

annotations (lines 5/20) add the following

synchronized

blocks to the observed synchroniza-tionbehaviour, andits arguments

@monitor

and

@resource

(lines 6/21and7/22,respectively)maplocalreferencesto shared aliases. The

@resource

annotation (line 31) starts the definitionof a resource type.

@value

,

@object

,

@ca-pacity

(lines 31/32/33) define how the abstract state isrepresented by a bounded integer. Here, to keep the running example simple,the abstractstatehasbeenchosen tobe equaltotheboundedinteger

els

.However, inatypical buffer implementationtheabstractionwouldbefromthebuffercontenttoaghostvariablecontainingthenumberofelementsin thebuffer.The

@operation

(lines36/38)and

@predicate

(lines40/42)annotationsdefinehowthemethodsoperateon thestate.NoticethattheannotatedmethodshavebeeninlinedinFig.3,i.e.,

add

isinlinedinlines6–10.The

@synctask

annotation above

main

starts thedeclarationoflocks,CVsandresources, and

@thread

annotations addthe underneath objectstotheglobalthreadcomposition.

Theannotationsprovidedinthisexampleweresufficientfor STaVe toinferthatdifferentvariablesthatarespreadalong thecodeactuallypointtotherelevantartifacts.Furthermore, STaVe waseitherabletoinferorinlinetheotherinformation itneeded(methods’controlflow,initializations,etc.),ortheinformationwasprovidedintheannotations.

(8)

static void main(String[] s) { Buffer b = new Buffer(); b.els = 1; b.cap = 7; Consumer c1; Consumer c2; Producer p; while (true) { c1 = new Consumer(b); c2 = new Consumer(b); p = new Producer(b);

c1.start(); p.start(); c2.start(); c1.join(); c2.join(); p.join(); b.els = 1; b.cap = 7;

} }

Fig. 7. Example of support for sessions.

Annotationscanbeunderstoodasprograminvariants intheusualstaticanalysissense.Thatis,ascontrol-pointinvariants whichholdeverytimeprogramexecutionisatagivencontrolpoint(atwhichtheannotationisplaced).Aprogramisthen considered to be correctlyannotated wheneverthe provided annotations hold. Although outsidethe scope ofthe present work,theannotationscanpotentiallybechecked,orpartiallygenerated,withexistingstaticanalysistechniques,suchas [14,

4].We shallhenceforthassumethat theprogrammer hascorrectlyannotatedtheprogram.Furthermore,we shallassume thememorymodelofsynchronizedactionsinaJavaprogramtobesequentiallyconsistent.

3.2. Synchronizationcorrectness

Thesynchronizationpropertyofinteresthereisthat“everythreadsynchronizingunderasetofconditionvariableseventually exitsthesynchronization”. We work under the assumption that every such thread eventually reaches its synchronization block. Thereexisttechniques [5] forcheckingthelivenesspropertythata giventhreadeventuallyreachesagivencontrol point;checkingvalidityoftheaboveassumptionisthereforeoutofthescopeofthepresentwork.

Thefollowingdefinitionofcorrectsynchronizationappliestoaone-timesynchronization ofaJavaprogram.However,the notioneasilygeneralizestoprogramsthatoperateinsessions byrepeatedlyre-spawningthesynchronizingthreads(i.e.,the one-timesynchronizationscheme),providedthat thesynchronizationvariablesareresetatthestartofeachsession.Fig.7

illustratesthisnotionwithamodifiedversionofthe

main

methodfromExample3.

Weshouldstressthatweusethetermcorrectness heretoreferexclusivelytothepropertymentionedabove;wedonot referwithittootherundesirablesynchronizationphenomena,suchasdataracefreedom.

Definition1 (Synchronizationcorrectness). Let

P

be a Java programwith a one-timesynchronization, whereevery thread eventuallyreachestheentrypointofitssynchronizationblock. Wesaythat

P

hasacorrectsynchronization iffeverythread eventuallyreachestheexitpointoftheblock.

WenowconnectsynchronizationschemesofcorrectlyannotatedJavaprogramswithSyncTaskprograms.

Theorem1(Characterization).AcorrectlyannotatedJavaprogramhasacorrectsynchronizationiffitscorrespondingSyncTask termi-nates.

Proofsketch. To provethe result, we define abinary relation R betweenthe configurations ofthe Javaprogram andits correspondingSyncTaskprogram,andshowittobeaweakbisimulation (see [15])forasuitablychosennotionofobservable andsilent transitionsbetweenconfigurations. Oneaspectofthe choiceisthat theannotations guaranteethatthe control flow oftheoriginal programispreserved, andthus,noinfinitesilent behavioursare possiblewithin thesynchronization. Therefore,aweakbisimulationrelationisadequateandsufficienttoestablishthedesiredprogressproperty.Werefertothe accompanyingtechnicalreport [16] forthefullformalizationandforthemostinterestingproofcases,namelythe

notify

and

wait

instructions.

TheJavaannotations defineabidirectionalmappingbetween(someof)theJavaprogram variablesandghost variables andthecorrespondingboundedvariablesinSyncTask.Thus,wedefine R torelateconfigurationsthatagreeontheircommon variables. Similarly, we define the set of observabletransitions as the ones that update common variables, andtreat all remaining transitionsassilent.We arguethat R isa weakbisimulation inthestandard fashion:We establishthat (i) the initialvaluesofthecommonvariablesarethesameforbothprograms,and(ii) assumingthatobservedvariablesinaJava programare onlyupdated insideannotatedsynchronizedblocks,we establishthatanyoperation thatupdatesa common variablehasthesameeffectonitinbothprograms.

Toprove(i)itsufficestoshowthattheinitialvaluesintheJavaprogramarethesameastheonesprovidedinthe ini-tializationannotation,asdescribedinSection3.1.Theproofof(ii)requirestoshowthatupdatestoacommonvariableyield thesameresultinbothprograms.ThisgoesbycaseanalysisontheJavainstructionsset.Eachcaseshowsthatforany con-figurationpairof R,theoperationalrulesforthegivenJavainstructionandforthecorrespondingSyncTaskinstructionlead toapairofconfigurationsthatagainagreeonthecommonvariables.AsthesemanticsofSyncTaskpresentedinSection2

(9)

Fig. 8. Top-level component and condition variables operations.

4. Verificationofsynchronizationcorrectness

Inthissection weshow howterminationofSyncTaskprogramscanbe reducedtoareachabilityproblemonColoured PetriNets(CPN).

4.1. SyncTaskprogramsasColoured PetriNets

Varioustechniquesexisttoproveterminationofconcurrentsystems.ForSyncTask,itisessential thatsuchatechnique efficientlyencodestheconcurrentthreadinterleaving,theprogram’scontrolflow,synchronizationprimitives,andbasicdata manipulation.Here,wehavechosentoreducetheproblemofterminationofSyncTaskprograms toareachabilityproblem on hierarchical CPNs extracted fromthe program. CPNs are supported by analysis toolssuch asCPN Tools, andallow a naturaltranslationofcommonlanguageconstructs intoCPNcomponents.Forthiswe reuseresultsfromWestergaard [9], andonly hadtomodelthe constructsinvolvingCVs that wepresentbelow. Weassume some familiaritywithCPNs,and referthereaderto [8] foradetailedexposition.

The colour set THREAD associates a colour toeach

Thread

type declaration,anda thread isrepresentedby a token with acolour from theset.Some components areparametrized by THREAD,meaning thatthey declare transitions,arcs, orplacesforeachthreadtype.Forillustrationpurposes,wepresenttheparametrizedcomponentsinan examplescenario withthreethreadtypes:blue (B),red (R),andyellow (Y).

TheproductionrulesinFig.2aremappedintohierarchicalCPNcomponents,wheresubstitutetransitions (STs;depictedas doublyoutlinedrectangles)representthenon-terminalsontheright-hand side.Fig.8a showsthecomponentforthestart symbol SyncTask.The Start placecontainsallthreadtokens intheinitial configuration,connectedbyarcs(onepercolour)

(10)

totheSTsdenotingthethreadtypes,and End,whichcollectstheterminatedthreadtokens.Italsocontainstheplacesthat representglobalvariables.

Fig.8b showsthemodellingof

wait

.The transition

wait

cond

produces two tokens:one intotheplace modelling theCV, andoneintothe placemodellingthelock, representingits release.Theother transitionmodels anotifiedthread reacquiringthe lock, and resumingthe execution. Fig. 8cshowsthe modelling of

notify

. The

Empty_cond

transition isenablediftheCVisempty, andtheother transitions,withone placepercolour,modelthenon-deterministicchoiceof whichthreadtonotify.Thecomponentfor

notifyAll

(notshown)issimilar.

The initialization inMain declares the initialset oftokens forthe placesrepresenting variables, andthenumber and colours ofthread tokens. A

Lock

createsa place containing a single token; it beingempty representsthat some thread holds the lock. The colour set CPOINT represents the control points of

wait

statements. A

Condition

variable gives rise toan emptyplace representingthewaiting set,withcolour set CONDITION. Here,colours are pairsof THREAD and CPOINT.Bothdataarenecessarytoroutecorrectlynotifiedthreadstothecorrectplacewheretheyresumeexecution. 4.2. SyncTaskterminationasCPNreachability

We nowenunciate the resultthat reducesterminationof a SyncTaskprogram to areachability problemon its corre-spondingCPN.

Theorem2(SyncTasktermination).ASyncTaskprogramterminatesiffitscorrespondingCPNunavoidablyreachesadeadconfiguration inwhichtheEndplacehasthesamemarkingastheStartplaceintheinitialconfiguration.

Proofsketch. A CPNdeclares a placeforeach SyncTask variable.Moreover, there isa clearcorrespondencebetweenthe operationalsemantics ofaSyncTaskconstructanditscorresponding CPNcomponent. Itcan beshownbymeans ofweak bisimulation that every configuration ofa SyncTask program is matched by a unique sequence ofconsecutive CPN con-figurations. Therefore, if the End place in a dead configuration has the same marking as the Start place in the initial configuration,theneverythreadintheSyncTaskprogramterminatesitsexecution,forevery possiblescheduling(notethat thenon-deterministicthreadschedulerissimulatedbythenon-deterministicfiringoftransitions).

2

CPN terminationitself can be verified algorithmically by computing the reachabilitygraph of thegenerated CPN and checkingthat:(i) thegraphhasnocycles,and(ii) theonlyreachabledeadconfigurationsaretheoneswherethemarking inthe End placeisthesameasthemarkinginthe Start placeintheinitialconfiguration.

5. The STAVEtool

Inthissectionwepresenttheimplementationofourtool,discussitscapabilitiestoinfersomeoftheinformationneeded forthetranslationtoSyncTask,andpresenttheresultsofourexperimentalevaluation.

5.1. Implementation

We have implemented the parsingof annotated Javaprograms to generateSyncTask programs, and the extractionof hierarchicalCPNsfromSyncTask,asthe STaVe tool.IthasbeenwritteninJava,andisavailableat [17].

STaVe processes the annotations in an intricate scheme. It takesthe annotated Java program as input, and uses the JavaParserlibrarytogeneratetheAST.ThenitconvertstheJavaParser’s ASTintotheoneoftheOpenJDKcompiler,totake advantageofits symboltablequerying,type checkingandcodeoptimization. WehaveadoptedJavaParser fortheparsing becauseitassociatesthecommentsper-ASTnode,whileOpenJDK’s parserdiscardsannotationsofafinergranularitythan methods. Forinstance, theuse of JavaParser allows theannotation of

synchronized

blocks. Next, STaVe traversesthe Java AST three times to extract the SyncTask program’s AST. The first pass processes resource annotations, and extracts informationabout howthreads operate onshared variables. Thesecond pass processes synchronizationannotations,and usestheinformationfromthepreviouspasstogeneratethecontrolflowstructureofthethreads.Thethirdpassprocesses initializationannotations,andchecksifthedeclaredvariablesandthreadtypeshavebeenproperlyparsedintheprevious steps. After the SyncTask AST is created, it is traversed following the mapping described in Section 4 to generate the correspondingCPN.

Twopartsof STaVe turnedouttobeusefulinitself,i.e.,usefulforotherprojects.ThefirstisJavaParser2JCTree,3alibrary thattranslatesJavaParserASTstoOpenJDKASTs.Thesecondislibcpntools,4 alibrarythatgenerateshierarchicalCPNsinthe

CPNTools’sXML-basedfileformat.

3 Availableathttps://github.com/pcgomes/javaparser2jctree. 4 Availableathttps://github.com/pcgomes/libcpntools.

(11)

5.2. Staticanalysis

Some oftheinformationaboutthesynchronizationbehaviouroftheanalyzedprogram,whichisneededforthe extrac-tionoftheSyncTaskprogram,canbededucedby STaVe itself.Basically,thisistheinformationwhichtheJavacompilercan deduce.Thus,thetoolcanautomatically(theexamplesinparenthesesrefertoFig.6):

deduceinitializationinvolvingconstants:thenumberofthreads,aresourcecapacity,etc.(lines50–55);

deducesimplecontrol-flowofthesynchronizationblocks,includingthecaseofmethodinvocationswithoutrecursion;

nameaSyncTaskconstructfromitsoriginatingJavacounterpart,asforinstance,anannotatedsynchronizedblock will benamedaftertheJavaclassthatdefinesit(class

Consumer

);

assignautomaticallyalabeltovariableswiththesamenameandtype,evenifdeclaredandusedindistinctfilesand/or methods;

inferinformationthatinvolvestheclasshierarchy,asforinstance,itisabletounderstanda“resource”thathassome methodsdefinedinaparentclass,whileothermethodsintheannotatedclass.

Our tool could be extended with severaladditional, specialized staticanalyses that wouldautomate theinference of varioustypesofinformation,neededforthetranslationtoSyncTask.Themaincandidatewouldbeapointeranalysis,which wouldinferwhentwovariablesindistinctpartsofthecodeinvariablypointtothesameobject.Currentlythetoolrequires the userto “tie”such variables usinglabels. Thatis,the usermanually assigns a globallabelto aJava variable,andthe labelwill becomethe nameoftherespectiveSyncTask variable.Forinstance,lines 6,21and45inFig.6 definethat the Javavariablesnamed

buffer

,

buffer

and

b

intheirrespectivemethods,actuallyreferencethesameobject

m

(whichisa labeltorefertothatobject).

5.3. Experimentalevaluation

Wenowdescribetheexperimentalevaluationofourframework.ThisincludestheprocessofannotatingJavaprograms, extractionofthecorrespondingCPNs,andtheanalysisofthenetsusingCPNTools.

Our first test case evaluates the usage of STaVe and the annotation process in a real-world program. For this, we annotatedPIPE [18] (version4.3.2),aratherlargeCPNanalysistool writteninJava.Itcontains asingle (andsimple) syn-chronization schemewithtwothreads usingCVs:whenthereisanewconnectionattemptfromaremoteclient,athread establishestheconnectionandthennotifiesthesharedCV;theotherthreadwriteslogstotheclient,andwaitsontheCVif thesocketisnotready.ThistestcaseillustratesthatsynchronizationinvolvingCVsistypicallysimpleandbounded.Italso exemplifiesasessionsynchronizationsincetheonlyvariable,abooleanthatflagsifthesocketisready,hasthesamevalue (false)atthestartofeachsession.Westress,however,that STaVe analyzesitasbeingaone-timesynchronization.Manually annotatingtheprogramtookjustafewminutes,oncethesynchronizationschemewasunderstood.TheCPNextractiontime wasnegligible,andtheverificationprocesstookjustafewmillisecondstoestablishcorrectness.

Oursecondtestcaseevaluatesthescalabilityofourapproachusing STaVe andstate-spaceexploration(withCPNTools) w. r. t.thenumberofthreads.WetookExample3,andinstantiateditwithavaryingnumberofthreads,buffercapacity,and initialvalue.

Asareference,weusedJavaPathfindertoanalyzethesameprogram.JavaPathfinder [19] (JPF)isanobviouschoicefor analyzingJavaprogramswithwait/notify,asitcandetectthesametypesofdeadlock(lackofprogress)that STaVe analyzes. JPFsupportsthe fullbytecodeinstructionsetandcananalyzethefull statespaceofconcurrentapplicationsthat haveno nativemethods (methodsthat executemachinecodelibrariesonthe hostsystem).Fornativemethods,modelclassescan beprovidedtoreplacethemwithequivalentcodeinJava,butthisisoftenacomplextask [20].

When using STaVe, its back-end, CPN Tools, generated the state graph, which we later queried using its ML-based API [21].We remark that, differentfromthe preliminary version ofthispaper [22], herewe take into account thetime ofamandatoryinitializationphasecalledEntertheStateSpace.Asexpected,thisleadstohigherverificationtimes.Asbefore, wecollectourstatisticsbyconsideringthestate-spacegeneration,computationofthestronglyconnectedcomponents,and verificationofthethreeterminationconditions.Namely:whetherthereisatleastonedeadconfiguration;whether,forall dead configurations,the End placehasthe samemarkingasthe Start place inthe initialconfiguration; andwhetherthe numberofstronglyconnectedcomponentsisequaltothesizeofthestategraph,implyingtheabsenceofcycles.

The experimentswere executedinaLinuxmachine with16 GB ofRAMandaquad-coreInteli5CPUof1.30 GHz.The JPF experimentswere executed with version 8.0rev 32,on Java 1.8.0_121.We gave JPF4 GB ofheap space(an amount that wasneverfullyused)andrantheexperimentswithoutatimeoutofonehour.Inadditiontotheexecutiontimes,JPF showsthenumberofexploredstatesandthenumberofexecutedbytecodeinstructions.TheCPNToolsexperimentswere performedwithversion4.0.1 inaWindows 7virtualmachine runningunderVirtualBox version5.1.32 with8 GB ofRAM and2processors.

(12)

Table 1

StatisticsforProducer/Consumer.Forgivenconfigurations,thenumberofprogramstatesandtheanalysistimeisshownforbothtools.ForJavaPathfinder, wealsoshowthenumberofbytecodeinstructionsexecutedduringthewholeanalysis.

Problem size Analysis results

Threads Buffer Java Pathfinder STaVe/CPN tools

producers consumers capacity elements terminates? # states # instr. time [mm:ss] # states time [mm:ss]

1 2 1 1 yes 1,466 43,603 0:01 42 0:05 1 2 2 0 no 22 3,878 0:00 43 0:05 2 2 1 0 yes 10,533 294,823 0:03 91 0:05 3 3 1 0 yes 613,052 21,035,480 2:12 283 0:05 4 3 1 0 yes 4,864,766 187,705,560 20:08 448 0:05 4 3 1 1 no 64 4,754 0:00 440 0:06

6 5 1 0 yes timeout after one hour 2,152 0:07

6 5 1 1 no 122 5,740 0:00 2,131 0:05

6 5 5 1 yes timeout after one hour 950 0:06

6 5 5 4 yes timeout after one hour 968 0:05

7 1 5 0 no 74 4,946 0:00 157 0:05

7 6 1 1 no 154 6,260 0:00 3,938 0:06

7 6 7 1 yes timeout after one hour 1,395 0:06

11 11 1 0 yes timeout after one hour 29,143 0:18

11 9 7 6 no 172 7,564 0:00 6,573 0:07

14 13 1 1 no 434 10,404 0:00 64,075 0:51

14 13 7 1 yes timeout after one hour 29,573 0:16

16 21 5 5 yes timeout after one hour 164,921 3:48

17 16 16 16 no 131 10,077 0:00 24,833 0:13

18 18 1 1 yes timeout after one hour 197,563 5:25

18 18 5 1 yes timeout after one hour 133,824 2:34

20 18 2 1 no 704 14,120 0:00 217,702 6:09

22 21 16 16 no 364 12,590 0:00 84,603 0:51

26 24 25 24 no 199 13,615 0:00 78,191 0:39

Table 1presents the practical evaluationfor a numberof initial configurations withvarying number ofthreads (Pro-ducer andConsumer),buffercapacity andposition5 (elements).Columnterminates? showsifaninitialprogramconfiguration has correctsynchronizationw. r. t. Definition 1.For thecases where JPFtimedout, the presented resultscome fromthe STaVe/CPNtoolsanalysisonly.As expected,the otherresultsmatchandcomefromboth analysis.The termstate replaces CPNconfiguration at STaVe statisticstoavoidconfusionwiththeconceptshowninProblemsize,andtofacilitatethe compar-isonbetweenthestate-spacesizes.Timespresentedas0:00meanlessthanonesecond.

We observe an expectedcorrelation between the numberof tokens representingthreads, the size of the state space, andthe verificationtime. Lessexpected foruswas the observed influenceofthe buffer capacities andinitial states.We conjecturethat theinitial configurationswhichmodelhighcontention, i.e.,manythreads waitingon CVs,inducea larger statespace.ThiseffectisparticularlystrongwithJavaPathfinder,whichhastoexecuteallrelevantconfigurationsexplicitly asprogram code. The experiments alsoshow how termination dependson the threadcomposition andthe initial state. Hence,asinglechangeinanyparametermayaffecttheverificationresult.

5.4. StatespaceexplosionwithJavaPathfinder

Toconfirmthetrendofsharplyexplodingstatespacesforunfalsifiableinstances,weranJPFwithanumberofadditional configurationsofExample3.

5.4.1. Correctconfigurations

Table2 showsconfigurations inwhichJPF detected noerrors.We testedan initial configurationwitha various num-ber of producerand consumer threads andvarious buffer sizes, withone initial element. While the totalstate spacein configurations ofup tosixthreads intotalis easily tractable(JPF takesbetweena fewsecondsandtwo minutes), larger configurationsareproblematic.Configurationswithseventhreadstookbetween15and20minutestocomplete,whileeight threadscouldnotcompletewithinonehour.

(13)

Table 2

RuntimesofJPFtoanalyzethefullstatespaceinvariousscenarios.Thebufferwasfilledwithoneelementinitsinitialstate.Weshowscenarioswith verysimilaroutcomesbyshowingtherangeofparametersandmeasuredresults(asminimum. . . maximumvalues).

Threads Buffer Analysis result

prod. cons. capacity # states # instructions time [mm:ss]

1 1 1. . . 10 186. . . 230 8,112. . . 8,887 0:00. . . 0:00 1 2 1. . . 10 1,466. . . 1,608 43,597. . . 46,186 0:01. . . 0:01 2 1 2. . . 10 1,744. . . 1,844 52,638. . . 54,697 0:01. . . 0:01 2 2 1. . . 10 10,981. . . 12,449 339,300. . . 387,612 0:03. . . 0:04 2 3 1. . . 10 82,806. . . 83,396 2,714,476. . . 2,814,139 0:17. . . 0:19 3 1 3. . . 10 12,825. . . 13,045 418,015. . . 423,135 0:04. . . 0:04 3 2 2. . . 10 86,701. . . 90,241 3,082,752. . . 3,125,704 0:18. . . 0:19 3 3 1. . . 10 585,200. . . 646,643 22,420,306. . . 23,968,679 2:11. . . 2:23 3 4 1. . . 10 3,963,321. . . 4,735,873 161,745,713. . . 183,001,505 18:11. . . 21:01 4 1 4. . . 10 85,277. . . 85,753 3,119,794. . . 3,132,367 0:18. . . 0:18 4 2 3. . . 10 563,183. . . 589,886 22,484,301. . . 23,038,076 2:08. . . 2:14 4 3 2. . . 10 3,820,353. . . 4,644,356 163,788,830. . . 189,499,018 16:22. . . 19:53

4 4 1 timeout after one hour

5 1 5. . . 10 536,276. . . 537,296 21,800,221. . . 21,830,503 2:02. . . 2:02 5 2 4. . . 10 3,491,907. . . 3,600,149 153,771,259. . . 156,364,195 15:14. . . 15:24

5 3 3 timeout after one hour

Table 3

RuntimesofJPFtodetectfaultsinvariousscenarios.Thebufferwasfilledwithoneelementinitsinitialstate.Weshowscenarioswithverysimilarresults byshowingtherangeofparametersandmeasuredresults(asminimum. . . maximumvalues).

Threads Buffer Analysis result

prod. cons. capacity trace length # states # instructions time [mm:ss] 1 3. . . 10 1. . . 10 25. . . 74 26. . . 75 4,078. . . 5,520 0:00 2 1 1 10 11 3,831 0:00 3 1 1. . . 2 14 15 4,020. . . 4,041 0:00 3 2 1 37 38 4,282 0:00 4 1 1. . . 3 18. . . 20 19. . . 21 4,211. . . 4,252 0:00 4 2 1. . . 2 43. . . 47 44. . . 48 4,473. . . 4,498 0:00 4 3 1 63 64 4,748 0:00 5 1 1. . . 4 22. . . 26 23. . . 27 4,402. . . 4,461 0:00 5 2 1. . . 3 49. . . 57 50. . . 58 4,664. . . 4,714 0:00 5 3 1. . . 2 69. . . 73 70. . . 74 4,939. . . 4,964 0:00 5 4 1 91 92 5,232 0:00 . . . 10 9 1 261 262 7,922 0:00 5.4.2. Faultyconfigurations

Table3showsconfigurationsinwhichJPFdetectedadeadlock,whereaproducerorconsumerthreadcouldnotproceed because the buffer was either full or empty, respectively, andno active threads that could change that condition were available. Wetestedan initial configurationwithavariousnumberofproducer andconsumer threads andvariousbuffer sizes,withoneinitialelement.

Alargernumberofthreadsincreasesthestatespaceonlyslightly;thisismostly visiblebyalongererrortraceincases wheremorethreads areinvolved.Still,thenumberofstatesisalways small,andJPFfinds theerrorrightaway,asshown bytheverysmallnumberofinstructionsexecuted,andaruntimethatwasalwaysbelowonesecond(seeTable3).

Therefore,itcanbeseenthatJPFisveryeffectiveatfindingdefects,andcompetitivewithSyncTaskintermsofrun-time incaseswheredefectsarepresent.Forcasesthatarecorrect,JPFscalestoacoupleofthreads,butitfailsifthenumberof threads growslarger.GiventhatnoannotationsarerequiredforJPF,itisthereforeagoodchoicetotryan exampleinJPF first,beforeannotatingittotrytoprovelivenessinlargercases.

(14)

6. Relatedwork

Wepresentrelatedmethodsandtoolsthatarebasedonthefollowingapproaches:

1. softwaremodelchecking,asystematicanalysisofallpossibleoutcomesbyexecutingthesoftwareunderallschedules; 2. deductivereasoning,usingcompositionaltechniquestoreasonaboutthebehaviour ofconcurrentprograms;

3. abstractinterpretation,andinparticularthread-modulartreatments;

4. schedule synthesis andpermutation, where a safescheduleis to be found,or subsetsofall thread interleavings are investigated;

5. andaconversionoftheprogramstructuretoPetriNets. 6.1. Approachesbasedonsoftwaremodelchecking

JavaPathfinder [19] iscloselyrelatedtoourworkinthatitchecksallpossibleoutcomesofdifferentthreadinterleavings ofaconcurrentJavaprogram.Bydefault,itcheckswhetheranyassertionfailureoruncaughtexceptionoccurs,andwhether aprogramexhibitsadeadlockstate,whichisastate whereatleastoneactivethreadexiststhatcannot continuebecause itisblockedonaresource.Athreadmayblockonaresourcebecauseitmaywaitforinputfromafileornetworkchannel, trytoobtainalock,orwaitforasignalinside

wait

.Thelattertypeofdeadlockcorrespondstotheoneanalyzedby STaVe. Java Pathfinder optimizesthe state spacesearch by matching equivalent program statesandby ignoring interleavings that do not affectthe global program state [19]. Unlike our tool, Java Pathfinder executesthe full bytecode ofthe Java application undertest, so it generally doesnot scale to programs withmany threads. However, by executing the actual bytecode,itdoesnotrequireannotationstocheckagainstlivelocksinprogramsusingconditionvariables(CVs).Adrawback of Java Pathfinder is that it cannot execute native methods. Large applications typically need elaborate model libraries to execute functionality such as network communication [20], whereas STaVe only considers annotations, which can be modelled totakeintoaccountanycomplexlibraries.

Inprinciple,JavaPathfindercouldhandleasimplifiedprogram(equivalenttotheSyncTaskprogram)betterthanthefull program,becausetheabstractionwouldeliminatenativecodeandreducethecomplexityoftheprogram.Itmaybepossible toisolatesubsetsofthefullprogrambyusingtheSyncTaskannotations,butthisisleftasfuturework.

Musuvathiet al. [23] present

CHESS

,atoolthatsystematicallyteststhreadinterleavingtotrytouncoversubtle concur-rencybugs.Thetool supports theWindows 32API,which featuresCVs. Ourworkshares similarities tothisone,such as theexplorationofthespaceofthreadinterleaving.However,

CHESS

isconcernedwithprogramsafety,i.e.,aprogramshall notreachan errorstate.Thepresentwork,ontheotherhand,focusonalivenessproperty,i.e.,every waitingthreadwill eventuallybenotifiedandprogress.

6.2. Approachesbasedondeductivereasoning

Leinoet al. [4] proposeacompositional techniqueto verifythe absenceofdeadlocksinconcurrentsystemswithboth locksandchannels.Theyusedeductivereasoningtodefine whichlocksathreadmayacquire, orto imposeanobligation fora threadto senda message.Theauthors acknowledgethat their quantitativeapproach tochannelsdoesnot apply to CVs,asmessagespassedthroughachannelarereceivedsynchronously,whileanotificationonaconditionvariableiseither received,orelseislost.

PopeeaandRybalchenko [5] presentacompositionaltechniquetoproveterminationofmulti-threadedprograms,which combinespredicateabstraction andrefinementwithrely-guarantee reasoning.The techniqueis onlydefinedforprograms that synchronizewith locks, and it cannot be easily generalized to support CVs. The reason for thisis that the thread terminationcriterionistheabsenceofinfinitecomputations;however,afinitecomputationwhereawaitingthreadisnever notifiedisincorrectlycharacterizedasterminating.

6.3. Approachesbasedonabstractinterpretation

A powerfulframework for the staticanalysisof programs is abstractinterpretation, whichallows programs to be (ab-stractly)executedinspecializedabstractdomainstoobtainalgorithmicallysoundfactsabouttheirbehaviour.Theframework isflexibleinthatitallowsprecisionoftheanalysestobetradedforperformance,andviceversa.

Todealwiththecombinatorialexplosion ofmulti-threadedprograms, someworksdevelop thread-modular analysesto achieve scalability. Miné [24] forinstance, considers locks (mutexes) as explicitsynchronization primitives, andincludes a yieldstatement. Thelocks arenot reentrant:acquiringanalreadyacquiredlockhasno effect,andsimilarly releasinga lockthatisnotacquiredbyathread.No proceduresareconsidered(butinliningcanbeusedfornon-recursiveprocedural programs),andnodynamicthreadcreation.Theaimoftheproposedmethodistodiscoverdataraces.

Inrecentfollow-upwork, MonatandMiné [25] extend theanalysistorelationaldomains, ina flow-sensitivemanner, to achieve a higher precision. The focus of the work is on numeric properties of small, but intricate mutual exclusion algorithms. The experimental results show that the method scales well, andallows the analysis of several hundreds of (small)threads.

(15)

Otherworksalsouseathread-modularanalysistodetectpotentiallyunsafeaccesses.High-leveldataracesdenoteunsafe accesspatternstotuplesofvalues [26].Localatomicityviolationsdenoteunsafeusesofshareddata [27,28].Both typesof atomicity violationshaverecentlybeenunified [29].Atomicityviolationsshow that thevalue ofaCVmaynot alwaysbe correctw. r. t.theglobalstateoftheprogram.

Anotheranalysisthatisclosetooursisadataracedetectiontoolbasedonkeyconcurrencyoperationsextractedfrom thegivenprogram [30].Similarlytoourtool,thatapproachbuildsanabstractmodelthatcontainsallrelevantconcurrency operationsonshareddata.Like STaVe’sanalysis,theirsisnotcompletelythread-modular.

Asalreadymentioned,onestrongpointoftheabove-mentionedmethodsisthatmostofthemarethread-modular.The mutual dependenciesare handled by data-flowanalysis orrely-guaranteestyle reasoning,which means that an iterative fixed-point computation is performed that invokes the thread-modular analyses on the threads in rounds, until global stabilization.

However,dataraceandatomicityanalysesdonotcoverthesignalling betweenthreads,andthereforedonotcompletely cover the semantics ofCVs. Sincewait-notify synchronizationis inherently non-local,it doesnot lend itself naturally to completely thread-modular analyses. Furthermore, it is not obvious how the analysis has to be set up to compute the interferences(asthelocaleffectsarecalled)inthecaseofCVs,andhowprecisethiscanbemade.

6.4. Schedulesynthesisandpermutation

Raychevet al. [7] presentanalgorithmthattakesasinputanon-deterministicparallelprogram,andsynthesizesa syn-chronization specificationusingCVs(andother synchronizationprimitives) sothat theprogrambecomesdeterministic, in thesensethatitproducesthesameoutputforthesameinput,regardlessofthescheduling.Thisworkdifferssubstantially fromourssincewedonotfocusondeterministicprograms(intheabovesense),andweextractasynchronization specifica-tionratherthancreateone.However,thetwoworkssharesimilarities.Forinstance,bothfocusonprogramswithconstant numberofthreads duetothe complexityofreasoningabouttheasynchronoussignalling ofCVs. Also,theyabstractaway fromothersourcesofnon-determinismthanthreadinterleaving.

Wang andHoang [31] propose a technique that permutes actions of execution traces to verify the absence of syn-chronization bugs.Theirprogrammodelconsiderslocksandconditionvariables.However,they cannotverifytheproperty consideredhere,sincetheirmethoddoesnotpermutematchingpairsofwait-notify.Forinstance,itwillnotreorderatrace where,first,athreadwaits,andthen,anotherthreadnotifies.Thus,theirmethodcannotdetectthecasewherethenotifying threadisscheduledfirst,andthewaitingthreadsuspendstheexecutionindefinitely.

6.5. ConversiontoPetri Nets

Kaiser and Pradat-Peyre [32] propose the modelling of Java monitors in Ada, and the extraction of CPNs from Ada programs. However, they donot precisely describehow theCPNs are verified,nor providea correctnessargumentabout their technique. Also, they onlyvalidate their toolon toy exampleswithfew threads.Ourtool isvalidatedon largertest cases,andonarealprogram.

Kavi et al. [33] presentPN componentsfor the synchronizationprimitives inthe Pthread libraryfor C/C++,including conditionvariables.However,theirmodellingofCVsjustallowsthesynchronizationbetweentwothreads,andnoargument ispresentedonhowtouseitwithmorethreads.

Westergaard [9] presentsatechniquetoextractCPNsforprogramsinatoyconcurrentlanguage,withlocksastheonly synchronization primitive.Our work borrows much from thiswork w. r. t. the CPN modellingand analysis. However, we analyzefull-fledgedprogramminglanguages,andaddressthecomplicationsofanalyzingprogramswithconditionvariables. Finally,VanderAalstet al. [34] presentstrategiesformodellingcomplexparallelapplicationsas CPNs.Weborrowmany ideas fromthiswork,especially themodellingofhierarchicalCPNs.However, their formalismis over-complicatedforour needs,andwethereforesimplifyittoproducemoremanageableCPNs.

7. Conclusion

We presenta technique to prove the correct synchronizationof Java programs using condition variables.Correctness here meansthat if all threads reachtheir synchronizationblocks,then all will eventually terminate thesynchronization. Ourtechniquedoesnotavoidtheexponentialblow-upofthestate spacecausedbytheinterleavingofthreads;instead,it alleviatestheproblembyisolatingthesynchronizationbehaviour.

We introduceSyncTask,asimplelanguagetocapturetherelevantaspectsofsynchronizationusingcondition variables. Also, wedefineanannotationschemeforprogrammerstomaptheexpectedsynchronizationinaJavaprogramtoa Sync-Task program.Weestablishthat thesynchronizationiscorrectw. r. t.theabove-mentionedproperty iff thecorresponding SyncTask terminates. As a proof-of-concept, to check termination we define a translation from SyncTask programs into Coloured PetriNetssuchthattheprogram terminatesiff thenetinvariablyreachesaspecialconfiguration.Theextraction ofSyncTaskfromannotatedJavaprograms,andthetranslationtoCPNs,isimplementedasthe STaVe tool.Wevalidateour technique onsome test-cases using CPNTools. Experimentsshow that our approach scales well to programs withmany threads,attheexpenseofrequiringdetailedannotationsoftheoriginalJavaprogram.

Referenties

GERELATEERDE DOCUMENTEN

Door bornen bier en daar terug te kappen en elders juist een dichte struiklaag intact te laten, kunnen we binnen zo'n betrekke­ lijk klein bosje varia tie

Qualitative analysis showed either mild slowing (at the border) or arrest of finger gesture (ventral premotor area), and arrest of tool-use pantomime in 1 out of 2 patients

We use seismic ambient noise recorded on more than 50 stations located on Algeria, Italy (Lampedusa, Linosa, Pantelleria, Sardinia (LISARD seismic network), Sicily), Libya, Malta,

tive, as it is constructed to reduce the energy consumption in manufacturing, and the sub-systems can interact voluntarily. Furthermore, it is designed as a conceptual and permanent

De waarde van de grens wordt bepaald, daarna wordt voor het geval dat er niet van alle funktiegroepen de leeftijdsverdeling bepaald moet worden, van de

Electron momentum transfer cross-section in cesium and related calculations of the local parameters of Cs + Ar MHD plasmas.. Citation for published

Aan de provincie is toen gevraagd of er andere gelijkwaardige wegen zijn aan te wijzen waar in 1990 enJof in 1991 snelheidsmetingen werden verricht en waar geen

The sample from this pit was taken from the deposit on the floor which was rich in carbonized materiaL The sample was passed through a flotation unit, after