a framework for deadlock detection in java

63
Un framework per l’analisi statica di Deadlock in Java Vincenzo Lomonaco, Marco Tiseo, Andrea Benetti, Alfred Dhoga Dipartimento di Informatica, Universit` a di Bologna, Italia. Abstract. In questo report, riassumiamo brevemente l’attivit` a svolta durante il corso di Analisi Statica di Programmi circa la definizione ed implementazione di un framework per l’analisi statica di Deadlock in Java. Dapprima ci si ` e concentrati sulla definizione di una sintassi ed una grammatica in ANTLR4 per il bytecode Java e successivamente alla stesura della semantica operazionale del linguaggio. Infine, alla creazione di un sistema di tipi comportamentali per l’ estrazione delle dipendenze tra entit` a utili alla rilevazione di deadlock per il back-end gi` a studiato ed implementato in [2]. 1 Introduzione Nell’ambito del corso di Analisi Statica di Programmi abbiamo avuto modo di studiare ed ap- profondire un framework per l’analisi statica di deadlock in coreABS. In [2] viene descritto det- tagliatamente l’approccio teorico e metodologico per la rilevazione di deadlock, partendo dalla sintassi specifica di coreABS e giungendo ad una rappresentazione astratta circa le dipendenze tra le entit` a di un programma. Mediante un sofisticato algoritmo, quindi, ` e possibile individuare le circolarit` a rappresentanti la possibilit` a che si verifichi una situazione di deadlock a runtime. Sulla scia di questo importante lavoro, si ` e voluto tentare un analogo approccio lavorando di- rettamente sul bytecode Java e quindi bypassando l’eterogeneit` a sintattica delle possibili librerie Java dedite al parallelismo. L’obiettivo finale ` e giungere ad una rappresentazione astratta delle dipendenze identica a quella riportata in [2], potendo cos` ı utilizzare il relativo algoritmo di rileva- mento deadlock (back-end) gi` a esistente e verificato. Nella sezione 2 viene descritta la sintassi del bytecode Java direttamente nel formato g4 di ANTLR4. Nella sezione 3 ` e illustrata la semantica operazionale e nella sezione 4 vengono riportati degli esempi di deadlock che si possono verificare tra due thread in esecuzione. Infine nella sezione 5 si presenta il sistema di tipi comportamentali. 2 La sintassi In questa sezione viene riportata la grammatica nella sintassi ANTLR4 che permette la creazione automatica del parser Java utile alla costruzione dell’ Abstract Sintax Tree a partire da una sintassi ridotta del bytecode che tiene conto solo delle istruzioni che operano su oggetti e su tipi di dato intero. 1 grammar bytecodeConcurrency; 3 classfile : (classDec innerClass? constantPool ’{’ fields* methodDeclaration+ ’}’ innerClass?) EOF 5 ; 7 classDec : classModifier? ( ’class’ | ’enum’ ) packageAndClassName ( ’extends’ packageAndClassName)? (( ’implements’ packageAndClassName) ( ’,’ packageAndClassName)*)? 1

Upload: vincenzo-lomonaco

Post on 07-Aug-2015

301 views

Category:

Science


0 download

TRANSCRIPT

Page 1: A Framework for Deadlock Detection in Java

Un framework per l’analisi statica di Deadlock in Java

Vincenzo Lomonaco, Marco Tiseo, Andrea Benetti, Alfred Dhoga

Dipartimento di Informatica, Universita di Bologna, Italia.

Abstract. In questo report, riassumiamo brevemente l’attivita svolta durante il corso diAnalisi Statica di Programmi circa la definizione ed implementazione di un frameworkper l’analisi statica di Deadlock in Java. Dapprima ci si e concentrati sulla definizione diuna sintassi ed una grammatica in ANTLR4 per il bytecode Java e successivamente allastesura della semantica operazionale del linguaggio. Infine, alla creazione di un sistema ditipi comportamentali per l’ estrazione delle dipendenze tra entita utili alla rilevazione dideadlock per il back-end gia studiato ed implementato in [2].

1 Introduzione

Nell’ambito del corso di Analisi Statica di Programmi abbiamo avuto modo di studiare ed ap-profondire un framework per l’analisi statica di deadlock in coreABS. In [2] viene descritto det-tagliatamente l’approccio teorico e metodologico per la rilevazione di deadlock, partendo dallasintassi specifica di coreABS e giungendo ad una rappresentazione astratta circa le dipendenzetra le entita di un programma. Mediante un sofisticato algoritmo, quindi, e possibile individuarele circolarita rappresentanti la possibilita che si verifichi una situazione di deadlock a runtime.Sulla scia di questo importante lavoro, si e voluto tentare un analogo approccio lavorando di-rettamente sul bytecode Java e quindi bypassando l’eterogeneita sintattica delle possibili librerieJava dedite al parallelismo. L’obiettivo finale e giungere ad una rappresentazione astratta delledipendenze identica a quella riportata in [2], potendo cosı utilizzare il relativo algoritmo di rileva-mento deadlock (back-end) gia esistente e verificato. Nella sezione 2 viene descritta la sintassi delbytecode Java direttamente nel formato g4 di ANTLR4. Nella sezione 3 e illustrata la semanticaoperazionale e nella sezione 4 vengono riportati degli esempi di deadlock che si possono verificaretra due thread in esecuzione. Infine nella sezione 5 si presenta il sistema di tipi comportamentali.

2 La sintassi

In questa sezione viene riportata la grammatica nella sintassi ANTLR4 che permette la creazioneautomatica del parser Java utile alla costruzione dell’ Abstract Sintax Tree a partire da unasintassi ridotta del bytecode che tiene conto solo delle istruzioni che operano su oggetti e su tipidi dato intero.

1 grammar bytecodeConcurrency;

3 classfile

: (classDec innerClass? constantPool ’{’ fields*

methodDeclaration+ ’}’ innerClass ?) EOF

5 ;

7 classDec

: classModifier? (’class’|’enum’) packageAndClassName (’extends ’

packageAndClassName)? ((’implements ’ packageAndClassName) (’,’

packageAndClassName)*)?

1

Page 2: A Framework for Deadlock Detection in Java

9 ;

11 classModifier

: ’public ’

13 | ’static ’

| ’final’

15 | ’abstract ’

;

17

innerClass

19 : ’InnerClasses: ’ ((’static ’ (’= ’|ref|’of’)+ | ref) ’;’)+

;

21

fields

23 : fieldModifier* type fieldName ’;’

;

25

fieldModifier

27 : classModifier

| ’protected ’

29 | ’private ’

;

31

fieldName: packageAndClassName;

33

constantPool

35 : ’Constant pool:’ tableEntries

;

37

tableEntries: tableEntry+;

39

41 tableEntry

: ref ’= ’ constantAndInfo

43 ;

45

47 constantAndInfo

: ’Class’ ref

49 | ’Fieldref ’ ref’.’ref

| ’Methodref ’ ref’.’ref

51 | ’InterfaceMethodref ’ ref’.’ref

| STRING ref

53 | ’Integer ’ num

| ’Float’ DEC

55 | ’Long’ num’l’

| ’Double ’ DEC

57 | ’NameAndType ’ ref’:’ref

| ’Utf8’ (( Identifier | identifierExtended) | NAT | ’%’ | ’;’ | ’

(’ | ’)’|’/’ | ’-’ | ’<’ | ’>’ | ’;’ | ’[’ | ’]’ | ’.’ | ’:’ |

’\"’ | ’!’ | ’?’ | ’^’ |’\\’|’,’)*

59 ;

2

Page 3: A Framework for Deadlock Detection in Java

61 methodDeclaration

: methodModifier* (methodHeader| ’{}’) ’;’ methodBody

63 ;

65 methodModifier

: fieldModifier

67 | ’abstract ’

| ’synchronized ’

69 | ’native ’

| ’strictfp ’

71 ;

73 methodHeader

: result? methodDeclarator throws_?

75 ;

77 result

: { ! _input.LT(1).getText ().substring(_input.LT(1).getText ().

length () - 1).equals ("(") }? type

79 | ’void’

;

81

type

83 : primitiveType

| referenceType

85 ;

87

primitiveType

89 : numericType

;

91

93 numericType

: integralType

95 ;

97

integralType

99 | ’int’

;

101

referenceType

103 : packageAndClassName

;

105

packageAndClassName

107 : (( Identifier|identifierExtended) ’[’* ’]’*)

| packageAndClassName ’.’ (( Identifier|identifierExtended) ’[’*

’]’*)

109 ;

3

Page 4: A Framework for Deadlock Detection in Java

111 methodDeclarator

: methodName ’(’ formalParameters? ’)’

113 ;

115 methodName: packageAndClassName;

117 formalParameters

: formalParameter (’,’ formalParameter)*

119 ;

121 formalParameter

: ’final’? (type |THIS)

123 ;

125 throws_

: ’throws ’ exceptionTypeList

127 ;

129 exceptionTypeList

: exceptionType (’,’ exceptionType)*

131 ;

133 exceptionType

: packageAndClassName

135 ;

137 methodBody

: ’Code:’ instructions

139 ;

141 instructions: instruction+;

143 instruction

: INDEX (’aconst_null ’

145 | ’aload’ NAT

| ALOAD

147 | ’areturn ’

| ’astore ’ NAT

149 | ASTORE

| ’athrow ’

151 | ’dup’

| ’getfield ’ ref

153 | ’getstatic ’ ref

| ’goto’ NAT

155 | ’iadd’

| ’iconst_m1 ’

157 | ’iconst_0 ’

| ’iconst_1 ’

159 | ’iconst_2 ’

| ’iconst_3 ’

161 | ’iconst_4 ’

| ’iconst_5 ’

163 | ’bipush ’ num

4

Page 5: A Framework for Deadlock Detection in Java

| ’idiv’

165 | ’if_acmpeq ’

| ’if_acmpne ’

167 | ’if_icmpeq ’ NAT

| ’if_icmpne ’ NAT

169 | ’if_icmplt ’ NAT

| ’if_icmpge ’ NAT

171 | ’if_icmpgt ’ NAT

| ’if_icmple ’ NAT

173 | ’ifeq’ NAT

| ’ifne’ NAT

175 | ’iflt’ NAT

| ’ifle’ NAT

177 | ’ifgt’ NAT

| ’ifge’ NAT

179 | ’ifnonnull ’

| ’ifnull ’

181 | ’iinc’ NAT num

| ’iload’ NAT

183 | ILOAD

| ’imul’

185 | ’invokespecial ’ ref

| ’invokestatic ’ ref

187 | ’invokevirtual ’ ref

| ’irem’

189 | ’ireturn ’

| ’istore ’ NAT

191 | ISTORE

| ’isub’

193 | ’ldc’ ref

| ’ldc_w’ ref

195 | ’monitorenter ’

| ’monitorexit ’

197 | ’new’ ref

| ’pop’

199 | ’putfield ’ ref

| ’putstatic ’ ref

201 | ’return ’)

;

203

INDEX

205 : NAT’:’

;

207

ref

209 : REFNUM

;

211

ALOAD

213 : ’aload_ ’ NAT

;

215

ASTORE

5

Page 6: A Framework for Deadlock Detection in Java

217 : ’astore_ ’NAT

;

219

ILOAD

221 : ’iload_ ’NAT

;

223

ISTORE

225 : ’istore_ ’NAT

;

227

REFNUM

229 : ’#’[1 -9][0 -9]*

;

231

num

233 : NAT

| INT

235 ;

237 NAT

: [0-9]+

239 ;

241

INT

243 : ’-’? NAT

;

245

DEC

247 : ’-’? [0-9]*’.’[0-9]*

;

249

THIS

251 : ’this’

;

253

STRING

255 : ’String ’

;

257

Identifier

259 : JavaLetter JavaLetterOrDigit*

;

261

identifierExtended

263 : Identifier

| STRING

265 | THIS

;

267

fragment

269 JavaLetter

6

Page 7: A Framework for Deadlock Detection in Java

: [a-zA -Z$_]

271 | ~[\u0000 -\ u00FF\uD800 -\ uDBFF]{ Character.isJavaIdentifierStart(

_input.LA(-1))}?

| [\uD800 -\ uDBFF] [\uDC00 -\ uDFFF]{ Character.isJavaIdentifierStart

(Character.toCodePoint ((char)_input.LA(-2), (char)_input.LA

(-1)))}?

273 ;

275 fragment

JavaLetterOrDigit

277 : [a-zA -Z0 -9$_]

| ~[\u0000 -\ u00FF\uD800 -\ uDBFF]{ Character.isJavaIdentifierPart(

_input.LA(-1))}?

279 | [\uD800 -\ uDBFF] [\uDC00 -\ uDFFF]{ Character.isJavaIdentifierPart(

Character.toCodePoint ((char)_input.LA(-2), (char)_input.LA(-1)

))}?

;

281

CLASSFILE: ’Classfile ’ ~[\r\n]+ {skip(); System.out.println (" skippato

CLASSFILE ");};

283

LAST: ’Last modified ’ [0-9|a -z|A -Z|’,’|’\-’|’;’|’ ’]+ ’ size ’ [0-9]+ ’

bytes ’ ’\r’? ’\n’ {skip(); System.out.println (" skippato LAST");};

285

MD5: ’MD5 checksum ’ [0-9|a-z]+ ’\r’? ’\n’ {skip(); System.out.println ("

skippato MD5");};

287

COMPILED: ’Compiled from ’ [’"’|a -z|A -Z|’.’]+ ’\r’? ’\n’{skip(); System.

out.println (" skippato COMPILED ");};

289

ENCLOSINGMETHOD: ’EnclosingMethod: ’ [’#’|0 -9|’.’]+ {skip(); System.out.

println (" skippato ENCLOSINGMETHOD ");};

291

SOURCE: ’SourceFile: ’ [’"’|a-z|A -Z|’.’]+ ’\r’? ’\n’{skip(); System.out.

println (" skippato SOURCE ");};

293

MINOR: ’minor version: ’ [0 -9]+ ’\r’? ’\n’{skip(); System.out.println ("

skippato MINOR ");};

295

MAJOR: ’major version: ’ [0 -9]+ ’\r’? ’\n’{skip(); System.out.println ("

skippato MAJOR ");};

297

FLAGS: ’flags: ’ [ A-Z|’_’|’,’]* ’\r’? ’\n’{skip(); System.out.println ("

skippato FLAGS ");};

299

DESCRIPTOR: ’descriptor: ’ ~[\r\n]* {skip(); System.out.println (" skippato

DESCRIPTOR ");};

301

EXCEPTIONTABLE: ’Exception table: ’ ’\r’? ’\n’{skip(); System.out.println

(" skippato EXCEPTIONTABLE ");};

303

FROMTO: ’from’ ’ ’+ ’to’ ’ ’+ ’target ’ ’ ’+ ’type’ ’\r’? ’\n’{skip();

System.out.println (" skippato FROMTO ");};

7

Page 8: A Framework for Deadlock Detection in Java

305

FROMTONUMBERS: NAT [’ ’|’/t’]+ NAT [’ ’|’/t’]+ NAT [’ ’|’/t’]+ [a-z]+ ’\

r’? ’\n’{skip(); System.out.println (" skippato FROMTONUMBERS ");};

307

LINENUMBERTABLE: ’LineNumberTable: ’ ’\r’? ’\n’ {skip(); System.out.

println (" skippato LINENUMBERTABLE ");};

309

LINENUMBERTABLECONTENT: ’line ’ [0-9]+ ’: ’ [0-9]+ ’\r’? ’\n’{skip();

System.out.println (" skippato LINENUMBERTABLECONTENT ");};

311

LOCALVARIABLETABLE: ’LocalVariableTable: ’ ’\r’? ’\n’ {skip(); System.out

.println (" skippato LOCALVARIABLETABLE ");};

313

LOCALVARIABLECONTENT: ’Start Length Slot Name Signature ’ ’\r’? ’\n’{

skip(); System.out.println (" skippato LOCALVARIABLETABLECONTENT ");};

315

LOCALVARIABLELINE: [0-9]+ [’ ’|’/t’]+ [0-9]+ [’ ’|’/t’]+ [0-9]+ [’ ’|’/t’

]+ ~[\r\n]+ {skip(); System.out.println (" skippato

LOCALVARIABLETABLELINE ");};

317

STACKMAPTABLE: ’StackMapTable: number_of_entries = ’ [0 -9]+ ’\r’? ’\n’{

skip(); System.out.println (" skippato STACKMAPTABLE ");};

319

FRAMETYPE: ’frame_type = ’ [0-9]+ [’ ’|’*’|’/’|A -Z|a -z|’_’|0 -9]* ’\r’? ’

\n’{skip(); System.out.println (" skippato FRAMETYPE ");};

321

OFFSETDELTA: ’offset_delta = ’ [0 -9]+ [’ ’|’*’|’/’|A-Z|a -z]* ’\r’? ’\n’{

skip(); System.out.println (" skippato OFFSETDELTA ");};

323

LOCALS: ’locals = ’ ’[’ [A-Z|a -z|’,’|’/’|’ ’]* ’]’ ’\r’? ’\n’{skip();

System.out.println (" skippato LOCALS ");};

325

STACK: ’stack =’ ~[\r\n]* {skip(); System.out.println (" skippato STACK ");

};

327

STACKLOCALARGSSIZE: ’stack=’ ( |[0-9]+ ’, locals=’[0-9]+ ’, args_size=’

[0 -9]+) ’\r’? ’\n’{skip(); System.out.println (" skippato

STACKLOCALARGSSIZE ");};

329

EXCEPTION: ’Exceptions: ’ ’\r’? ’\n’{skip(); System.out.println (" skippato

EXCEPTION ");};

331

THROWS: ’throws ’ [A-Z|a -z|’.’]+ ’\r’? ’\n’{skip(); System.out.println ("

skippato THROWS ");};

333

// INNER: ’InnerClasses: ’ ’\r’? ’\n’{skip(); System.out.println (" skippato

INNERCLASS ");};

335

// INNERCLASSESREF: REFNUM ’;’ {skip(); System.out.println (" skippato

INNERCLASSREF ");};

337

// STATICINNERCLASS: ’static #’[0-9]+ ~[\r\n]* {skip(); System.out.println

(" skippato STATICINNERCLASS ");};

8

Page 9: A Framework for Deadlock Detection in Java

339

WS : [ \r\n\t] -> skip // skip spaces, tabs, newlines

341 ;

343

345 COMMENT

: ’/*’ .*? ’*/’ {skip(); System.out.println (" skippato COMMENT ");}

347 ;

349 LINE_COMMENT

: ’//’ ~[\r\n]* {skip();}

351 ;

3 La semantica operazionale

In questa sezione, prendendo spunto da quanto fatto in [2], si riporta una introduzione generalealla semantica operazionale. A seguire vengono elencate la totalita delle regole semantiche infunzione delle istruzioni che e possibile trovare all’interno del bytecode generato all’atto dellacompilazione.

Partendo da un contesto formato da un insieme di classi P , da un’astrazione generalizzante Cpoolper le singole constant pool presenti in ciascuna classe e da un’astrazione generalizzante ExcTableche racchiude tutte le tabelle delle eccezioni dei metodi delle classi, ogni istruzione esegue unatransizione tra configurazioni. Ogni configurazione e della forma:

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, opStack1) · s1, z1〉 , · · · ,

〈(pcD.m, lvarn, opStackn) · sn, zn〉 ; W

A sinistra del `H , come anticipato in precedenza, abbiamo il contesto formato da P , Cpool edExcTable. Per quanto riguarda la Cpool, in particolare, useremo la notazione CpoolC per denotarel’insieme delle costanti della classe C. H, invece, rappresenta lo Heap dove sono contenuti glioggetti creati dinamicamente e verra descritto meglio in seguito. A destra del `H , vi sono l’insiemedi thread del programma presenti nella Java Virtual Machine in un dato istante. In particolare,nella suddetta configurazione, vi sono n thread attualmente attivi, ognuno dei quali e racchiusotra parentesi angolari, ed un insieme di thread in attesa di riprendere l’esecuzione che si assumesiano contenuti nell’insieme W dei thread che aspettano di essere risvegliati da un qualche evento.Entrando nello specifico ogni Thread contiene:

– Una pila LIFO s contenente una serie di record di attivazione (o frames), racchiusi traparentesi tonde, e che a loro volta contengono le informazioni relative a ciascun metodochiamato durante l’esecuzione.

– Un set z di oggetti di cui si detiene il lock.

In ogni frame a sua volta sono contenute le seguenti informazioni:

9

Page 10: A Framework for Deadlock Detection in Java

– Un program counter pc che punta all’indirizzo della prossima istruzione da eseguire. In par-ticolare pcC.m puntera ad un’istruzione all’interno del metodo m della classe C. Per ottenereil nome di questa istruzione dall’indirizzo puntato dal program counter useremo la notazioneP [pcC.m].

– Un insieme di variabili locali lvar tra cui sono contenuti anche gli argomenti passati comeparametri al metodo. Inoltre con la notazione lvar(this) e possibile ottenere il riferimentoall’oggetto su cui il metodo e stato chiamato, oppure il riferimento alla classe se il metodo estatico.

– un operand Stack LIFO opStack in cui vengono inseriti i riferimenti ad oggetti ed i valoriinteri necessari per effettuare le operazioni locali al metodo.

Lo Heap in questa semantica contiene:

– Tutti gli oggetti allocati tramite le istruzioni new. Ognuno di questi oggetti sara costituitoda:• un insieme di campi d’istanza. Il valore di un campo a di un oggetto o sara accessibile con

la notazione H(o).a. Per aggiornarne il valore a v si usera invece la notazione H(o).a 7→ v• la classe di appartenenza dell’oggetto. Ed esempio, per recuperare la classe di apparte-

nenza di un oggetto o si usera la notazione H(o).class• un wait set che contiene i riferimenti ai thread che hanno invocato wait() sull’oggetto.• un contatore l che tiene traccia del numero di lock che un thread ha acquisito sull’oggetto

(solo un thread per volta puo possedere il lock di un oggetto). Questo campo e accessibileed aggiornabile con la stessa notazione usata per i normali campi dell’oggetto, cioe conH(o).l e H(o).l 7→ n (le istruzioni getstatic, putstatic, getfield, putfield non possonoagire su questo campo). Se il valore del campo l dell’oggetto e uguale a 0 significa chenessun thread ne ha il lock.

– Un oggetto speciale per ogni classe del programma, il cui scopo e quello di rappresentarela classe stessa e di permettere di accedere ai relativi campi statici. Sara quindi possibile,ad esempio, recuperare il valore di un campo statico a della classe C mediante la notazioneH(C).a e aggiornarne il valore con H(C).a 7→ v. Inoltre, come per gli oggetti istanziati conle new, ad ognuno di tali oggetti speciali che identificano una classe e associato un campol che permette di acquisire e rilasciare il lock della classe corrispondente. Ad esempio, peraccedere al valore del campo l della classe C si usera la notazione H(C).l e per rilasciare illock di tale classe si usera la notazione H(C).l 7→ 0

Inoltre viene utilizzata la seguente notazione:

– v per valori interi, o per i riferimenti agli oggetti, e per entrambi– H(o) 7→ (ρC⊥, C) per allocare lo spazio per l’oggetto o della classe C nello heap assegnando

un valore indefinito ai rispettivi campi d’istanza ed inizializzando il suo campo class con laclasse opportuna. Questa situazione si ha eseguendo un’istruzione new, i campi dell’oggettorimangono indefiniti in quanto la creazione di un istanza di una classe non e completa finchel’oggetto non viene inizializzato mediante una chiamata invokespecial al costruttore.

– H(o) 7→ ρCargs per inizializzare i campi dell’oggetto o di classe C con gli argomenti args passatiall’opportuno costruttore. I rimanti campi non gestiti dal costruttore verranno inizializzaticon 0 nel caso si tratti di interi e null nel caso si tratti di riferimenti. Questo assegnamentocompleta la creazione di un nuovo oggetto allocato precedentemente con la new.

– CpoolC(ref) = [“Costante”, “V alore”] per indicare che ad una determinato indirizzo refdella Cpool della classe C si trova una entry costante-valore. La costante di una entry dellaConstant Pool e una tra quelle definite nella Java V irtual Machine Specification edidentifica il tipo di informazione che sara contenuta nella parte valore della entry.

10

Page 11: A Framework for Deadlock Detection in Java

– ExcTableC.m(pcC.m, H(o).class) = L per indicare che la tabella delle eccezioni relativa almetodo C.m e in grado di gestire un’eccezione (che e un oggetto a tutti gli effetti) o ditipo H(o).class che si verifica alla riga puntata da pcC.m mediante un Exception Handler(una sequenza di istruzioni bytecode) che si trova all’indirizzo L (che deve essere per forzaun’indirizzo interno al metodo C.m). Se invece tale ExcTableC.m non fosse in grado di gestireuna tale eccezione, quando questa si verifica a quella riga, la notazione sarebbe la seguente:ExcTableC.m(pcC.m, H(o).class) = ⊥

Per concludere, l’insieme dei waiting set W e definito come: W = {Wo1 , . . . ,Won

, Jo1 , . . . , Jon}. Ognuno dei Woi raggruppa l’insieme dei processi in attesa che un altro thread ef-fettui una notify sull’oggetto oi. Mentre ognuno dei Joi raggruppa l’insieme dei thread in attesadella terminazione dell’oggetto oi. Si assume quindi, in quest’ultimo caso, che oi sia un thread,ovvero un oggetto istanza della classe Thread su cui e possibile invocare oi.join() per attendernela terminazione Per il singolo waiting set utilizziamo la notazione Woi = {〈(pck, lvark, opStackk)·sk, zk〉nk | k ∈ K} dove K rappresenta l’insieme dei Thread indicizzati ed in attesa della notifysull’oggetto oi. Mentre per il singolo waiting set Joi utilizziamo la notazione Joi = {〈(pck, lvark, opStackk)·sk, zk〉oi | k ∈ K} dove K rappresenta l’insieme dei thread indicizzati ed in attesa della termi-nazione dell’oggetto oi che contiene il metodo run() del thread corrispondente. Infine abbiamo:

– ∅woi che indica che non c’e nessun thread in attesa di una notify sull’oggetto oi.– ∅joi che indica che non c’e nessun thread in attesa della terminazione

dell’oggetto/thread oi

Di seguito sono riportate le regole semantiche di riduzione. Ogni regola riporta solamente lecomponenti che partecipano alla riscrittura anche se ovviamente tale riscrittura si applica adogni configurazione che contiene tali componenti.

Partiamo dalle regole piu semplici: pop, iinc, iload, aload, istore, astore, goto, etc...

11

Page 12: A Framework for Deadlock Detection in Java

P [pcC.m] = pop

P,Cpool, ExcTable `H 〈(pcC.m, lvar, e · opStack) · s, z〉 →`H 〈pcC.m + 1, lvar, opStack) · s, z〉

P [pcC.m] = iinc index v

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar[index 7→ lvar(index) + v], opStack) · s, z〉

P [pcC.m] = iload index

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, lvar(index) · opStack) · s, z〉

P [pcC.m] = iload index

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, lvar(index) · opStack) · s, z〉

P [pcC.m] = aload index

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, lvar(index) · opStack) · s, z〉

P [pcC.m] = aload index

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, lvar(index) · opStack · s, z〉

12

Page 13: A Framework for Deadlock Detection in Java

P [pcC.m] = istore index

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar[index 7→ v], opStack) · s, z〉

P [pcC.m] = istore index

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar[index 7→ v], opStack) · s, z〉

P [pcC.m] = astore index

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar[index 7→ o], opStack) · s, z〉

P [pcC.m] = astore index

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar[index 7→ o], opStack) · s, z〉

P [pcC.m] = goto LC.m

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

13

Page 14: A Framework for Deadlock Detection in Java

P [pcC.m] = iadd

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′ · v′′ · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, v′′ + v′ · opStack) · s, z〉

P [pcC.m] = isub

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′ · v′′ · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, v′′ − v′ · opStack) · s, z〉

P [pcC.m] = imul

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′ · v′′ · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, v′′ × v′ · opStack) · s, z〉

P [pcC.m] = idiv

v′ 6= 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′ · v′′ · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, v′′/v′ · opStack) · s, z〉

P [pcC.m] = irem

v′ 6= 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′ · v′′ · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, v′′%v′ · opStack) · s, z〉

14

Page 15: A Framework for Deadlock Detection in Java

P [pcC.m] = iconst m1

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar,−1 · opStack) · s, z〉

P [pcC.m] = iconst n0 ≤ n ≤ 5

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, n · opStack) · s, z〉

P [pcC.m] = aconst null

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z)〉 →`H 〈(pcC.m + 1, lvar, null · opStack) · s, z〉

P [pcC.m] = bipush v−128 ≤ v ≤ 127

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, v · opStack) · s, z〉

P [pcC.m] = dup

P,Cpool, ExcTable `H 〈(pcC.m, lvar, e · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, e · e · opStack) · s, z〉

15

Page 16: A Framework for Deadlock Detection in Java

Vediamo adesso le istruzioni di salto condizionale:

P [pcC.m] = if acmpeq LC.m

o′ = o′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o′ · o′′ · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

P [pcC.m] = if acmpeq LC.m

o′ 6= o′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o′ · o′′ · opStack) · s, z)〉 →`H 〈(pcC.m + 1, lvar, opStack) · s, z〉

P [pcC.m] = if acmpne LC.m

o′ 6= o′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o′ · o′′ · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

P [pcC.m] = if acmpne LC.m

o′ = o′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o′ · o′′ · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, opStack) · s, z〉

16

Page 17: A Framework for Deadlock Detection in Java

P [pcC.m] = if icmpeq LC.m

v′ = v′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′ · v′′ · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

P [pcC.m] = if icmpeq LC.m

v′ 6= v′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′ · v′′ · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, opStack) · s, z〉

P [pcC.m] = if icmpne LC.m

v′ 6= v′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′ · v′′ · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

P [pcC.m] = if icmpne LC.m

v′ = v′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′ · v′′ · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, opStack) · s, z〉

17

Page 18: A Framework for Deadlock Detection in Java

P [pcC.m] = if icmple LC.m

v′ > v′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′′ · v′ · opStack) · s, z〉 →`H 〈(pc+ 1C.m, lvar, opStack) · s, z〉

P [pcC.m] = if icmple LC.m

v′ ≤ v′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′′ · v′ · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

P [pcC.m] = if icmplt LC.m

v′ ≥ v′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′′ · v′ · opStack) · s, z〉 →`H 〈(pc+ 1C.m, lvar, opStack) · s, z〉

P [pcC.m] = if icmplt LC.m

v′ < v′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′′ · v′ · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

18

Page 19: A Framework for Deadlock Detection in Java

P [pcC.m] = if icmpge LC.m

v′ < v′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′′ · v′ · opStack) · s, z〉 →`H 〈(pc+ 1C.m, lvar, opStack) · s, z〉

P [pcC.m] = if icmpge LC.m

v′ ≥ v′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′′ · v′ · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

P [pcC.m] = if icmpgt LC.m

v′ ≤ v′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′′ · v′ · opStack) · s, z〉 →`H 〈(pc+ 1C.m, lvar, opStack) · s, z〉

P [pcC.m] = if icmpgt LC.m

v′ > v′′

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v′′ · v′ · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

19

Page 20: A Framework for Deadlock Detection in Java

P [pcC.m] = ifeq LC.m

P,Cpool, ExcTable `H 〈(pcC.m, lvar, 0 · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

P [pcC.m] = ifeq LC.m

v 6= 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, opStack) · s, z〉

P [pcC.m] = ifne LC.m

P,Cpool, ExcTable `H 〈(pcC.m, lvar, 0 · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, opStack) · s, z〉

P [pcC.m] = ifne LC.m

v 6= 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

20

Page 21: A Framework for Deadlock Detection in Java

P [pcC.m] = iflt LC.m

v ≥ 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, opStack) · s, z〉

P [pcC.m] = iflt LC.m

v < 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

P [pcC.m] = ifle LC.m

v > 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, opStack, ·s, z〉

P [pcC.m] = ifle LC.m

v ≤ 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

21

Page 22: A Framework for Deadlock Detection in Java

P [pcC.m] = ifgt LC.m

v ≤ 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, opStack) · s, z〉

P [pcC.m] = ifgt LC.m

v > 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

P [pcC.m] = ifge LC.m

v < 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v · opStack) · s, z〉 →`H 〈(pc+ 1C.m, lvar, opStack) · s, z〉

P [pcC.m] = ifge LC.m

v ≥ 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, v · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

22

Page 23: A Framework for Deadlock Detection in Java

P [pcC.m] = ifnull LC.m

P,Cpool, ExcTable `H 〈(pcC.m, lvar, null · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

P [pcC.m] = ifnull LC.m

o 6= null

P, Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z〉 →`H 〈(pc+ 1C.m, lvar, opStack) · s, z〉

P [pcC.m] = ifnonnull LC.m

P,Cpool, ExcTable `H 〈(pcC.m, lvar, null · opStack) · s, z〉 →`H 〈(pc+ 1C.m, lvar, opStack) · s, z〉

P [pcC.m] = ifnonnull LC.m

o 6= null

P, Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z〉 →`H 〈(LC.m, lvar, opStack) · s, z〉

23

Page 24: A Framework for Deadlock Detection in Java

Consideriamo adesso le regole formali per le invokespecial, invokestatic e le invokevirtual. Leprime vengono utilizzate per invocare un costrutture, le seconde per invocare metodi statici e leterze per tutti gli altri metodi.

P [pcC.m] = invokespecial refCpoolC(ref) = [“Methodref”, ref1.ref2]

CpoolC(ref1) = [“Class”, “D”]CpoolC(ref2) = [“NameAndType”, ref3 : ref4]

CpoolC(ref3) = [“Utf8”, “ < init > ”]CpoolC(ref4) = [“Utf8”, “(Tpar1 , . . . , Tparn)V ”]

H(o) = (ρD⊥ , D)H ′ = H[o 7→ ρDargs]

P,Cpool, ExcTable `H 〈(pcC.m, lvar, argn · . . . · arg1 · o · opStack) · s, z〉 →`H′ 〈(pcC.m + 1, lvar, opStack) · s, z〉

24

Page 25: A Framework for Deadlock Detection in Java

P [pcC.m] = invokestatic refCpoolc(ref) = [“Methodref”, ref1.ref2]

Cpoolc(ref1) = [“Class”, “D”]Cpoolc(ref2) = [“NameAndType”, ref3 : ref4]

Cpoolc(ref3) = [“Utf8”, “foo”]Cpoolc(ref4) = [“Utf8”, “(Tpar1 , . . . , Tparn)Tres”]

synchronized /∈ modifier(D.foo)

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, argn·, . . . , ·arg1 · opStack1) · s, z〉 →`H 〈(1D.foo, lvar2[0 7→ arg1, . . . , n− 1 7→ argn, this 7→ D], ε) ·

(pcC.m + 1, lvar1, opStack1) · s, z〉

P [pcC.m] = invokestatic refCpoolC(ref) = [“Methodref”, ref1.ref2]

CpoolC(ref1) = [“Class”, “D”]CpoolC(ref2) = [“NameAndType”, ref3 : ref4]

CpoolC(ref3) = [“Utf8”, “foo”]CpoolC(ref4) = [“Utf8”, “(Tpar1 , . . . , Tparn)Tres”]

synchronized ∈ modifier(D.foo)H(D).l = n, n > 0H ′ = H(D).l 7→ n+ 1

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, argn · . . . · arg1 · opStack1) · s, z ∪ {D}〉 →`H′ 〈(1D.foo, lvar2[0 7→ arg1, . . . , n− 1 7→ argn, this 7→ D], ε) ·

(pcC.m + 1, lvar1, opStack1) · s, z ∪ {D}〉

P [pcC.m] = invokestatic refCpoolc(ref) = [“Methodref”, ref1.ref2]

Cpoolc(ref1) = [“Class”, “D”]Cpoolc(ref2) = [“NameAndType”, ref3 : ref4]

Cpoolc(ref3) = [“Utf8”, “foo”]Cpoolc(ref4) = [“Utf8”, “(Tpar1 , . . . , Tparn)Tres”]

syncronized ∈ modifier(D.foo)H(D).l = 0

H ′ = H(D).l 7→ 1

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, argn · . . . · arg1 · opStack1) · s, z\{D}〉 →`H′ 〈(1D.foo, lvar2[0 7→ arg1, . . . , n− 1 7→ argn, this 7→ D], ε) ·

(pcC.m + 1, lvar1, opStack1) · s, z ] {D}〉

25

Page 26: A Framework for Deadlock Detection in Java

P [pcC.m] = invokevirtual refCpoolc(ref) = [“Methodref”, ref1.ref2]

Cpoolc(ref1) = [“Class”, “D”]Cpoolc(ref2) = [“NameAndType”, ref3 : ref4]

Cpoolc(ref3) = [“Utf8”, “foo”]Cpoolc(ref4) = [“Utf8”, “(Tpar1 , . . . , Tparn)Tres”]

synchronized /∈ modifier(D.foo)

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, argn · . . . · arg1 · o · opStack1) · s, z〉 →`H 〈(1D.foo, lvar2[0 7→ o, 1 7→ arg1, . . . , n 7→ argn, this 7→ o], ε) ·

(pcC.m + 1, lvar1, opStack1) · s, z〉

P [pcC.m] = invokevirtual refCpoolC(ref) = [“Methodref”, ref1.ref2]

CpoolC(ref1) = [“Class”, “D”]CpoolC(ref2) = [“NameAndType”, ref3 : ref4]

CpoolC(ref3) = [“Utf8”, “foo”]CpoolC(ref4) = [“Utf8”, “(Tpar1 , . . . , Tparn)V ”]

synchronized ∈ modifier(D.foo)H(o).l = n, n > 0H ′ = H(o).l 7→ n+ 1

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, argn · . . . · arg1 · o · opStack1) · s, z ∪ {o}〉 →`H′ 〈(1D.foo, lvar2[0 7→ o, 1 7→ arg1, . . . , n 7→ argn, this 7→ o], ε) ·

(pcC.m + 1, lvar1, opStack1) · s, z ∪ {o}〉

P [pcC.m] = invokevirtual refCpoolc(ref) = [“Methodref”, ref1.ref2]

Cpoolc(ref1) = [“Class”, “D”]Cpoolc(ref2) = [“NameAndType”, ref3 : ref4]

Cpoolc(ref3) = [“Utf8”, “foo”]Cpoolc(ref4) = [“”Utf8”, “(Tpar1, . . . , Tparn)Tres”]

syncronized ∈ modifier(D.foo)H(o).l = 0

Hi = H(o).l 7→ 1

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, argn · . . . · arg1 · o · opStack1) · s, z\{o}〉 →`H 〈(1D.foo, lvar2[0 7→ o, 1 7→ arg1, . . . , n 7→ argn, this 7→ o], ε) ·

(pcC.m + 1, lvar1, opStack1) · s, z ] {o}〉

26

Page 27: A Framework for Deadlock Detection in Java

La regola seguente gestisce la creazione di un nuovo thread in seguito all’invocazione del metodostart.

P [pcC.m] = invokevirtual refo instance of java/lang/Thread

CpoolC(ref) = [“Methodref”, ref1.ref2]CpoolC(ref1) = [“Class”, ”java/lang/Thread”]CpoolC(ref2) = [“NameAndType”, ref3 : ref4]

CpoolC(ref3) = [“Utf8”, “start”]CpoolC(ref4) = [“Utf8”, “()V ”]

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, o · opStack1) · s, z〉 →`H 〈(pcC.m + 1, lvar1, opStack1) · s, z〉 ,

〈(1java/lang/Thread.run, lvar2[0 7→ o, this 7→ o], ε), ε〉

P [pcC.m] = invokevirtual refCpoolC(ref) = [“Methodref”, ref1.ref2]

CpoolC(ref1) = [“Class”, “java/lang/Thread”]CpoolC(ref2) = [“NameAndType”, ref3 : ref4]

CpoolC(ref3) = [“Utf8”, “join”]CpoolC(ref4) = [“Utf8”, “()V ”]

o = lvart21 (this)

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, o · opStack1) · st1 , zt1〉 ,〈st2 · (pcjava/lang/Thread.run, lvart21 , opStack

t21 ), zt2〉; Jo →

`H 〈st2 · (pcjava/lang/Thread.run, lvart21 , opStackt21 ), zt2〉;

Jo ] 〈(pcC.m + 1, lvar1, opStack1) · st1 , zt1〉o

La seguente regola e relativa alla ripartenza dei thread che si erano precedentemente messi in attesadella terminazione di uno stesso thread (oggetto o) mediante la chiamata a join(). Appena tale threadtermina tutti quelli che erano in attesa ripartono.

P [pcjava/lang/Thread.run] = return

o = lvar(this)

P,Cpool, ExcTable `H 〈(pcjava/lang/Thread.run, lvar, opStack), z1〉;∅jo ] (〈(pck, lvark, opStackk) · sk, zk)〉o)k∈K →`H (〈(pck, lvark, opStackk) · sk, zk)〉)k∈K ; ∅jo

27

Page 28: A Framework for Deadlock Detection in Java

P [pcC.m] = invokevirtual refCpoolc(ref) = [“Methodref”, ref1.ref2]

Cpoolc(ref1) = [“Class”, “java/lang/Object”]Cpoolc(ref2) = [“NameAndType”, ref3 : ref4]

Cpoolc(ref3) = [“Utf8”, “notify”]Cpoolc(ref4) = [“Utf8”, “()V ”]

H(o).l = n, n > 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, o · opStack1) · s1, z1 ∪ {o}〉;Wo ] {〈(pcD.m, lvar2, opStack2) · s2, z2〉n} →

`H 〈(pcC.m + 1, lvar1, opStack1) · s1, z1 ∪ {o}〉 , 〈(pcD.m, lvar2, opStack2) · s2, z2〉n ;Wo

Nella regola seguente il wait set dell’oggetto o e vuoto e pertanto nessuna notifica viene fatta

P [pcC.m] = invokevirtual refCpoolc(ref) = [“Methodref”, ref1.ref2]

Cpoolc(ref1) = [“Class”, “java/lang/Object”]Cpoolc(ref2) = [“NameAndType”, ref3 : ref4]

Cpoolc(ref3) = [“Utf8”, “notify”]Cpoolc(ref4) = [“Utf8”, “()V ”]

H(o).l = n, n > 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z ∪ {o}〉; ∅wo →`H 〈(pcC.m + 1, lvar, opStack) · s, z ∪ {o}〉; ∅wo

P [pcC.m] = invokevirtual refCpoolc(ref) = [“Methodref”, ref1.ref2]

Cpoolc(ref1) = [“Class”, “java/lang/Object”]Cpoolc(ref2) = [“NameAndType”, ref3 : ref4]

Cpoolc(ref3) = [“Utf8”, “notifyAll”]Cpoolc(ref4) = [“Utf8”, “()V ”]

H(o).l = n, n > 0Wo = {〈(pck, lvark, opStackk) · sk, zk)〉nk | k ∈ K}o

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z ∪ {o}〉;Wo →`H 〈(pcC.m + 1, lvar, opStack) · s, z ∪ {o}〉, (〈(pck, lvark, opStackk) · sk, zk)〉nk )k∈K ; ∅wo

28

Page 29: A Framework for Deadlock Detection in Java

P [pcC.mt1 ] = invokevirtual ref

Cpoolc(ref) = [“Methodref”, ref1.ref2]Cpoolc(ref1) = [“Class”, “java/lang/Object”]Cpoolc(ref2) = [“NameAndType”, ref3 : ref4]

Cpoolc(ref3) = [“Utf8”, “wait”]Cpoolc(ref4) = [“Utf8”, “()V ”]

H(o).l = n, n > 0H ′ = H(o).l 7→ 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z ∪ {o}〉;Wo →`H′ ;Wo ] 〈(pcC.m, lvar, opStack) · s, z ∪ {o}〉n

Un thread che viene risvegliato da una notify (o notifyAll) puo continuare la sua esecuzionesolamente quando il lock dell’oggetto in cima al suo stack (quello su cui aveva invocato la wait)viene rilasciato. In questo caso il thread puo riacquisire il lock di tale oggetto settandone il relativocampo l al valore n in modo da ripristinare il numero di lock acquisiti prima della chiamata wait.

H(o).l = 0H ′ = H(o).l 7→ n

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z〉n →`H′ 〈(pcC.m + 1, lvar, opStack) · s, z〉

29

Page 30: A Framework for Deadlock Detection in Java

Consideriamo adesso le varie return che siano esse utilizzate per ritornare un tipo void, un interooppure un oggetto.

P [pcC.m] = return

synchronized /∈ modifier(C.m)

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, opStack1) · (pcD.m, lvar2, opStack2) · s, z〉 →`H 〈pcD.m, lvar2, opStack2) · s, z〉

P [pcC.m] = return

synchronized ∈ modifier(C.m)o = lvar1(this)H(o).l = 1

H ′ = H(o).l 7→ 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, opStack1) · (pcD.m, lvar2, opStack2) · s, z ] {o}〉 →`H′ 〈(pcD.m, lvar2, opStack2) · s, z〉

P [pcC.m] = return

synchronized ∈ modifier(C.m)o = lvar1(this)H(o).l = n, n > 1

H ′ = H(o).l 7→ n− 1

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, opStack1) · (pcD.m, 〈lvar2, opStack2) · s, z ∪ {o}〉 →`H′ 〈(pcD.m, lvar2, opStack2 · s, z ∪ {o}〉

30

Page 31: A Framework for Deadlock Detection in Java

P [pcC.m] = ireturn

synchronized /∈ modifier(C.m)

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, v · opStack1) · (pcD.m, lvar2, opStack2) · s, z〉 →`H′ 〈(pcD.m, lvar2, v · opStack2) · s, z〉

P [pcC.m] = ireturn

synchronized ∈ modifier(C.m)o = lvar1(this)H(o).l = n, n > 1

H ′ = H(o).l 7→ n− 1

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, v · opStack1) · (pcD.m, lvar2, opStack2) · s, z ∪ {o}〉 →`H′ 〈(pcD.m, lvar2, v · opStack2) · s, z ∪ {o}〉

P [pcC.m] = ireturn

synchronized ∈ modifier(C.m)o = lvar1(this)H(o).l = 1

H ′ = H(o).l 7→ 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, v · opStack1) · (pcD.m, lvar2, opStack2) · s, z ] {o}〉 →`H′ 〈(pcD.m, lvar2, v · opStack2) · s, z〉

31

Page 32: A Framework for Deadlock Detection in Java

P [pcC.m] = areturn

synchronized /∈ modifier(C.m)

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, o · opStack1) · (pcD.m, lvar2, opStack2) · s, z〉 →`H 〈(pcD.m, lvar2, o · opStack2) · s, z〉

P [pcC.m] = areturn

synchronized ∈ modifier(C.m)o′ = lvar1(this)H(o′).l = 1

H ′ = H(o′).l 7→ 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, o · opStack1) · (pcD.m, lvar2, opStack2) · s, z ] {o′}〉 →`H′ 〈(pcD.m, lvar2, o · opStack2) · s, z〉

P [pcC.m] = areturn

synchronized ∈ modifier(C.m)o′ = lvar1(this)H(o′).l = n, n > 1

H ′ = H(o′).l 7→ n− 1

P,Cpool, ExcTable `H 〈(pcC.m, lvar1, o · opStack1) · (pcD.m, lvar2, opStack2) · s, z ∪ {o′}〉 →`H′ 〈(pcD.m, lvar2, o · opStack2) · s, z ∪ {o′}〉

32

Page 33: A Framework for Deadlock Detection in Java

Consideriamo adesso putstatic, getstatic, putfield e getfield utilizzate per settare e recuperare unvalore rispettivamente da un campi statici o d’istanza.

P [pcC.m] = putstatic refCpoolC(ref) = [“Fieldref”, ref1.ref2]

CpoolC(ref1) = [“Class”, ref3]CpoolC(ref3) = [“Utf8”, “D”]

CpoolC(ref2) = [“NameAndType”, ref4 : ref5]CpoolC(ref4) = [“Utf8”, “a”]CpoolC(ref5) = [“Utf8”, “T”]

H ′ = H(D).a 7→ e

P,Cpool, ExcTable `H 〈(pcC.m, lvar, e · opStack) · s, z〉 →`H′ 〈(pcC.m + 1, lvar, opStack) · s, z)

P [pcC.m] = getstatic refCpoolc(ref) = [“Fieldref”, ref1.ref2]

Cpoolc(ref1) = [“Class”, ref3]Cpoolc(ref3) = [“Utf8”, “D”]

Cpoolc(ref2) = [“NameAndType”, ref4 : ref5]Cpoolc(ref4) = [“Utf8”, “a”]Cpoolc(ref5) = [“Utf8”, “T”]

H(D).a = e

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(pc+ 1C.m, lvar, e · opStack) · s, z〉

33

Page 34: A Framework for Deadlock Detection in Java

P [pcC.m] = putfield refCpoolc(ref) = [“Fieldref”, ref1.ref2]

Cpoolc(ref1) = [“Class”, ref3]Cpoolc(ref3) = [“Utf8”, “D”]

Cpoolc(ref2) = [“NameAndType”, ref4 : ref5]Cpoolc(ref4) = [“Utf8”, “a”]Cpoolc(ref5) = [“Utf8”, “T”]

H ′ = H(o).a 7→ e

P,Cpool, ExcTable `H 〈(pcC.m, lvar, e · o · opStack) · s, z〉 →`H′ 〈(pcC.m + 1, lvar, opStack) · s, z〉

P [pcC.m] = getfield refCpoolc(ref) = [“Fieldref”, ref1.ref2]

Cpoolc(ref1) = [“Class”, ref3]Cpoolc(ref3) = [“Utf8”, “D”]

Cpoolc(ref2) = [“NameAndType”, ref4 : ref5]Cpoolc(ref4) = [“Utf8”, “a”]Cpoolc(ref5) = [“Utf8”, “T”]

H(o).a = e

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, e · opStack) · s, z〉

34

Page 35: A Framework for Deadlock Detection in Java

Una delle istruzioni piu importanti da considerare e quella relativa alla creazione di nuovi oggettimediante l’operatore new.

P [pcC.m] = new refCpoolc(ref) = [“Class”, ref1]Cpoolc(ref1) = [“Utf8”, “D”]

o /∈ dom(H)H ′ = H[o 7→ (ρD⊥ , D)]

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H′ 〈(pcC.m + 1, lvar, o · opStack) · s, z〉

Di seguito si riportano, invece, le importanti operazioni di presa e rilascio del lock tramite mon-itorenter e monitorexit.

P [pcC.m] = monitorexit

H(o).l = 1H ′ = H(o).l 7→ 0

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z ] {o}〉 →`H′ 〈(pcC.m + 1, lvar, opStack) · s, z〉

P [pcC.m] = monitorexit

H(o).l = n, n > 1H ′ = H(o).l 7→ n− 1

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z ∪ {o}〉 →`H′ 〈(pcC.m + 1, lvar, opStack) · s, z ∪ {o}〉

P [pcC.m] = monitorenter

H = H(o).l = 0H ′ = H(o).l→ 1

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z\{o}〉 →`H′ 〈(pcC.m + 1, lvar, opStack) · s, z ] {o}〉

35

Page 36: A Framework for Deadlock Detection in Java

P [pcC.m] = monitorenter

H = H(o).l = n, n > 0H ′ = H(o).l→ n+ 1

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z ∪ {o}〉 →`H′ 〈(pcC.m + 1, lvar, opStack) · s, z ∪ {o}〉

Consideriamo adesso le istruzioni per recuperare una costante dalla Constant Pool ed inserirlasull’ operand Stack1.

P [pcC.m] = ldc refCpoolC(ref) = [“Integer”, v]

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, v · opStack) · s, z〉

P [pcC.m] = ldc refCpoolC(ref) = [“String”, ref1]CpoolC(ref1) = [“Utf8”, “text”]

String o = “text”

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, o · opStack) · s, z〉

P [pcC.m] = ldc refCpoolC(ref) = [“Class”, ref1]CpoolC(ref1) = [“Utf8”, “D”]

o = D

P,Cpool, ExcTable `H 〈(pcC.m, lvar, opStack) · s, z〉 →`H 〈(pcC.m + 1, lvar, o · opStack) · s, z〉

1 ldc w ha le stesse regole semantiche di ldc ma puo puntare ad indirizzi di memoria piu estesi all’internodella Constant pool.

36

Page 37: A Framework for Deadlock Detection in Java

Di seguito le istruzioni inerenti al lancio di un’eccezione

P [pcC.m] = athrow

synchronized /∈ modifier(C.m)ExcTableC.m(pcC.m, H(o).class) = L

P,Cpool, ExcTable `H 〈(pcC.m, lvar, o · opStack) · s, z〉 →`H 〈(L, lvar, o) · s, z〉

P [pcCn.mn ] = athrow

synchronized /∈ modifier(Cn.mn)ExcTableCn.mn(pcCn.mn , H(o).class) = ⊥ExcTableCi.mi(pcCi.mi , H(o).class) = L

P,Cpool, ExcTable `H 〈(pcCn.mn , lvarn, o · opStackn) · . . . ·(pcCi.mi , lvari, opStacki) · . . . · (pcC1.m1 , lvar1, opStack1), z〉 →

`H 〈(L, lvari, o) · . . . · (pcC1.m1 , lvar1, opStack1), z〉

P [pcCn.mn ] = athrow

synchronized ∈ modifier(Cn.mn)ExcTableCn.mn(pcCn.mn , H(o).class) = ⊥ExcTableCi.mi(pcCi.mi , H(o).class) = L

o′ = lvarn(this)H(o′).l = 1

H ′ = H(o′).l 7→ 0

P,Cpool, ExcTable `H 〈(pcCn.mn , lvarn, o · opStackn) · . . . ·(pcCi.mi , lvari, opStacki) · . . . · (pcC1.m1 , lvar1, opStack1), z ] {o′}〉 →

`H′ 〈(L, lvari, o) · . . . · (pcC1.m1 , lvar1, opStack1), z〉

P [pcCn.mn ] = athrow

synchronized ∈ modifier(Cn.mn)ExcTableCn.mn(pcCn.mn , H(o).class) = ⊥ExcTableCi.mi(pcCi.mi , H(o).class) = L

o′ = lvarn(this)H(o′).l = n, n > 1

H ′ = H(o′).l 7→ n− 1

P,Cpool, ExcTable `H 〈(pcCn.mn , lvarn, o · opStackn) · . . . ·(pcCi.mi , lvari, opStacki) · . . . · (pcC1.m1 , lvar1, opStack1), z ∪ {o′}〉 →

`H′ 〈(L, lvari, o) · . . . · (pcC1.m1 , lvar1, opStack1), z ∪ {o′}〉

37

Page 38: A Framework for Deadlock Detection in Java

4 Esempi di deadlock tra due thread in esecuzione parallela

(1)

P [pcT1.m] = monitorenterP [pcT2.m] = monitorenter

〈(pcT1.m, lvar1, o · opstack1) · s1, z1 ∪ {o′} and z1\{o} 〉,〈(pcT2.m, lvar2, o

′ · opstack2) · s2, z2 ∪ {o} and z2\{o′}〉

(2) In questa regola si guarda il caso con invokevirtual ma lo stesso vale per invokestatic se siconsiderano i lock sulle classi.

P [pcT1.m] = invokevirtual o′.M (synchronized ∈ modifier(o′.M))P [pcT2.m] = invokevirtual o.M (synchronized ∈ modifier(o.M))

〈(pcT1.m, lvar1, argn · . . . · arg1 · o · opstack1) · s1, z1 ∪ {o′} and z1\{o} 〉,〈(pcT2.m, lvar2, argn · . . . · arg1 · o′ · opstack2) · s2, z2 ∪ {o} and z2\{o′}〉

(3)

P [pcT1.m] = invokevirtual o′.waitP [pcT2.m] = invokevirtual o.join

lvar1(this) = o

;Wo′ ] 〈(pcT1.m, lvar1, opStack1), z1〉nJo ] 〈(pcT2.m, lvar2, opStack2) · s2, z2)〉o

38

Page 39: A Framework for Deadlock Detection in Java

(4)

PC[pcT1.m] = invokevirtual o′.waitPC[pcT2.m] = monitorenter

〈(pcT2.m, lvar2, o′′ · opstack2) · s2, z2\{o′′}〉;

Wo′ ] 〈(pcT1.m, lvar1, opStack1), z1 ∪ {o′′}〉n

(5)

P [pcT1.m] = invokevirtual o′.waitP [pcT2.m] = invokevirtual o.M (synchronized ∈ modifier(o.M))

〈(pcT2.m, lvar2, argn · . . . · arg1 · o · opstack2) · s2, z2\{o}〉;Wo′ ] 〈(pcT1.m, lvar1, opStack1), z1 ∪ {o}〉n

(6)

P [pcT1.m] = invokevirtual o.joinP [pcT2.m] = invokevirtual o′.join

lvar1(this) = o′

lvar2(this) = o

; Jo ] 〈(pcT1.m, lvar1, opStack1) · s1, z1)〉oJo′ ] 〈(pcT2.m, lvar2, opStack2) · s2, z2)〉o′

39

Page 40: A Framework for Deadlock Detection in Java

(7)

P [pcT1.m] = monitorenterP [pcT2.m] = invokevirtual o′.M (synchronized ∈ modifier(o′.M))

〈(pcT1.m, lvar1, o · opstack1) · s1, z1 ∪ {o′} and z1\{o} 〉,〈(pcT2.m, lvar2, argn · . . . · arg1 · o′ · opstack2) · s2, z2 ∪ {o} and z2\{o′}〉

(8)

P [pcT1.m] = invokevirtual o.joinP [pcT2.m] = monitorenter

lvar2(this) = o

〈(pcT2.m, lvar2, o′ · opstack2) · s2, z2\{o′}〉;

Jo ] 〈(pcT1.m, lvar1, opStack1) · s1, z1 ∪ {o′})〉o

(9)

P [pcT1.m] = invokevirtual o.joinP [pcT2.m] = invokevirtual o′.M (synchronized ∈ modifier(o′.M))

lvar2(this) = o

〈(pcT2.m, lvar2, argn · . . . · arg1 · o′ · opstack2) · s2, z2\{o′}〉;Jo ] 〈(pcT1.m, lvar1, opStack1) · s1, z1 ∪ {o′})〉o

40

Page 41: A Framework for Deadlock Detection in Java

5 Sistema di tipi comportamentali

In questa sezione introduciamo il sistema di tipi comportamentali utile alla definizione delleLAM. Il linguaggio delle LAM costituisce una rappresentazione astratta di un programma, giautilizzata in [2], che raccoglie in se le informazioni minimali ed indispensabili all’individuazionedelle dipendenze funzionali e quindi dei possibili deadlock.Riconducendoci direttamente al linguaggio delle LAM, inoltre, e possibile applicare in manieradiretta l’algoritmo decisionale studiato ed implementato in [2].Prima di addentrarci direttamente nella definizione delle regole di tipaggio, effettuiamo alcuneconsiderazioni in merito alla notazione utilizzata.Sia P il nostro programma in cui sono in esecuzione un certo numero di thread e sia Pσ lasequenza di istruzioni eseguite da un singolo thread. Come abbiamo discusso in precedenza ogniPσ e costituito da uno stack di chiamate di metodo mn · . . . ·m1 dove mn e l’ultima invocazioneeffettuata ed m1 e il metodo run() alla base dell’esecuzione del thread. Ognuno di questi metodiha associato un insieme di variabili locali Fσ ed un operand stack Sσ.Ogni tipo di oggetto nel programmaAbbiamo associato ad ogni istruzione bytecode esaminata precedentemente una regola di tipaggioche ci permette di associare a tale istruzione il relativo comportamento. In tal modo possiamoutilizzare la sequenza dei comportamenti delle singole istruzioni per ottenere la LAM di ogniPσ che, una volta combinate ci permettono di ottenere la LAM di tutto il programma P . Inparticolare, per indicare che da un contesto Fσ, Sσ, Zσ, Tσ deriviamo la LAM L di un Pσ,usiamo la seguente notazione:

Fσ, Sσ, Zσ, Tσ ` Pσ : L .

dove:

– Fσ[i] e una mappa che, data un’istruzione i, restituisce l’array di tipi presenti nelle variabililocali del metodo al momento dell’esecuzione di tale istruzione.

– Sσ[i] e una sequenza di tipi presenti sull’operand stack all’istruzione i del metodo.– Zσ[i] e una pila di tipi di oggetti di cui il Thread detiene il lock all’istruzione i.– Tσ[i] e l’insieme di tipi di oggetti corrispondenti ai thread mandati in esecuzione dal thread

corrente che sono attivi all’istruzione i.– infine L e l’insieme delle LAMs, quindi il tipo comportamentale, assegnato al nostro pro-

gramma Pσ

L’applicazione di una mappa parziale G ad un indirizzo i, nelle nostre regole di tipaggio vieneabbreviata con Gi.

Il tipo generico τ , oltre al tipo top, utlizzato per assegnare un tipo iniziale alla variabili localidi un metodo, comprende anche interi int, tipi oggetto Θ e tipi di oggetti indicizzati Θ. Questiultimi sono definiti come:

Θ = {σi[aj : τ j∈Jj ] | σ[aj : τ j∈Jj ] ∈ Θ and i fresh}

Mediante la notazione σ[aj : τ j∈Jj ] intendiamo specificare nome e tipo dei campi di un oggettodi tipo σ.Per rappresentare i tipi oggetto nelle formule si utilizza σ mentre, per rappresentare i tipi deglioggetti indicizzati, si utilizza σi oppure σ a seconda che sia necessario/oppurtuno esplicitare omeno l’indice del tipo indicizzato. Il tipo τσ, invece, puo essere utilizzato per rappresentare un

41

Page 42: A Framework for Deadlock Detection in Java

tipo σ o σi. Sia inoltre Type una funzione parziale da tipi a tipi definita come segue: Type[σi] = σ,e Type[τ ] = τ altrimenti.

Un indice fresh i viene assegnato ad un tipo σ al momento della sua creazione (istruzionenew). Quando quest’ultimo verra duplicato mediante un’istruzione dup sullo stack, l’indice dellasua copia rimarra inalterato. In altre parole, tutte le variabili che hanno lo stesso tipo σi sonoaliases. Per assegnare correttamente l’indice i delle copie, utilizziamo la seguente funzione diindicizzazione τi, definita come segue:

1. τi = τ , se τ = int or τ = top (solo le copie dei riferimenti sono rilevanti);2. τi = σ, se τ = σ (successive copie della variabile ne mantengono il tipo della prima copia).

Per ogni tipo σ definiamo σ come l’insieme di campi [aj : τ j∈Jj ] specificati nella definizione diclasse corrispondente. Ad esempio per indicare che il campo a della classe di tipo σ ha tipo τusiamo la notazione σ.a : τ . Assumiamo che i campi di un oggetto non possano essere modificati (omeglio possano essere modificati assegnando loro lo stesso valore che gia possedevano) e pertantoil loro tipo rimarra sempre lo stesso e l’uso della regola putfield e putstatic, per assegnareun valore ad un determinato campo di un oggetto o di una classe, sara consentita solamente seassegnera a tale campo lo stesso tipo che questo gia possedeva. Se a e un campo di tipo τj definitoin un oggetto di tipo σ useremo la notazione τ σ.aj per indicare in modo univoco il tipo immutabiledi tale campo. La funzione τi se applicata al tipo di un campo si comportera esattamente comefa quando applicata ai tipi indicizzati cioe restituira il tipo stesso senza modificarlo.La regola che prova Fσ, Sσ, Zσ, Tσ ` Pσ : L e:

Fσ[1σ] = FσtopSσ[1σ] = εZσ[1σ] = εTσ[1σ] = ε

∀i ∈ dom[Pσ]. Fσ, Sσ, Zσ, Tσ, i ` Pσ : Liσ

Fσ, Sσ, Zσ, Tσ ` Pσ : L1σ ; . . . ;Lnσ

dove:

– l’istruzione 1σ e la prima istruzione del metodo run dell’oggetto thread di tipo σ– Fσtop e la funzione che inizializza l’array delle variabili locali del metodo run() mappando 0

a σ e gli indici delle altre variabili al tipo TOP– Li e la LAM dell’istruzione i

Come detto prima ogni flusso di esecuzione di un thread sara costituito da uno o piu invocazionidi metodo. Le regole usate per la tipizzazione di un generico metodo m(σthis[aj : τ j∈Jj ], τ1[ak :

τk∈Kk ], . . . , τn[aw : τw∈Ww ]), che provano cioe Fσm, Sσm, Z

σm, T

σm ` m(σthis[aj : τ j∈Jj ], τ1[ak : τk∈Kk ], . . . , τn[aw :

τw∈Ww ]) : Lm, sono due a seconda che il metodo sia o meno synchronized. Per un metodo

m(σthis[aj : τ j∈Jj ], τ1[ak : τk∈Kk ], . . . , τn[aw : τw∈Ww ]) non synchronized la regola e la seguente:

Fσm[1m] = FmtopSσm[1m] = εZσm[1m] = εTσm[1m] = ε

∀i ∈ dom[Pm]. Fσm, Sσm, Z

σm, T

σm, i `

m(σthis[aj : τ j∈Jj ], τ1[ak : τk∈Kk ], . . . , τn[aw : τw∈Ww ]) : Lim

Fσm, Sσm, Z

σm, T

σm `

m(σthis[aj : τ j∈Jj ], τ1[ak : τk∈Kk ], . . . , τn[aw : τw∈Ww ]) : L1m ; . . . ;Lnm

42

Page 43: A Framework for Deadlock Detection in Java

mentre per un metodo m(σthis[aj : τ j∈Jj ], τ1[ak : τk∈Kk ], . . . , τn[aw : τw∈Ww ]) dichiarato synchro-nized abbiamo:

Fσm[1m] = FmtopSσm[1m] = ε

Zσm[1m] = σthisTσm[1m] = ε

∀i ∈ dom[Pm]. Fσm, Sσm, Z

σm, T

σm, i `

m(σthis[aj : τ j∈Jj ], τ1[ak : τk∈Kk ], . . . , τn[aw : τw∈Ww ]) : Lim

Fσm, Sσm, Z

σm, T

σm `

m(σthis[aj : τ j∈Jj ], τ1[ak : τk∈Kk ], . . . , τn[aw : τw∈Ww ]) : L1m ; . . . ;Lnm

Come si puo vedere, in quest’ultimo caso, a differenza del precedente, la sequenza Z all’inizio delmetodo conterra gia il tipo σthis dell’oggetto su cui il metodo e stato invocato (che e il tipo delriferimento this che e salvato nella posizione 0 dell’array delle variabili locali). Infine, in entrambii casi Fmtop e la funzione che inizializza l’array delle variabili locali mettendo nella posizione 0 iltipo σthis, nelle posizioni seguenti i tipi dei parametri passati al metodo ed infine inizializzandoi tipi delle altre variabili locali a TOP.Infine, consideriamo le funzioni che a partire dalla pila Z e da T calcolano le LAM a secondadelle regole di tipaggio.

T = {run(σi) & run(σi+1) | 1 ≤ i ≤ n− 1 ∧ σ ∈ T}Z = σn · . . . · σ1ˆZ = {(σi+1, σi) | 1 ≤ i ≤ n− 1 ∧ σi+1 /∈ [σi−1 · . . . · σ1] ∧ σi+1 6= σi}Z = σn . . . σi+1 · σi · σi−1 . . . σ1 dove (σi+1, σi), (σi, σi−1) ∈ ˆZ ∀i 1 < i < n− 1

dove oi rappresenta un oggetto e top(Z) e l’elemento in cima alla pila Z.

Di seguito vengono mostrate le regole di tipaggio per il giudizio Fσ, Sσ, Zσ, Tσ, i ` Pσ : Li. Intali regole viene omesso l’apice σ, e si assume che i tipi dei campi di ogni classe del programmaP siano noti (essendo presenti nella Constant Pool).

43

Page 44: A Framework for Deadlock Detection in Java

P [i] = pop

Fi = Fi+1

Si = τ · Si+1

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = iinc index INTindex ∈ dom[Fi]Fi[index] = INT

Fi = Fi+1

Si = Si+1

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = iload indexindex ∈ dom[Fi]Fi[index] = INT

Fi = Fi+1

INT · Si = Si+1

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

44

Page 45: A Framework for Deadlock Detection in Java

P [i] = aload indexindex ∈ dom[Fi]

Fi[index] = σ[aj : τ j∈Jj ]

Fi = Fi+1

σ[aj : τ j∈Jj ] · Si = Si+1

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = istore indexindex ∈ dom[Fi]

Fi[index 7→ INT ] = Fi+1

Si = INT · Si+1

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = astore indexindex ∈ dom[Fi]

Fi[index 7→ σ[aj : τ j∈Jj ]] = Fi+1

Si = σ[aj : τ j∈Jj ] · Si+1

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = goto LFi = FL

Si = SL

Ti = TL

L ∈ dom[P ]Zi = ZL

F, S, Z, T, i ` P : Ti & ˆZi

45

Page 46: A Framework for Deadlock Detection in Java

P [i] = aconst null

Fi = Fi+1

Type[σ] = NULLσ · Si = Si+1

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = bipush n−128 ≤ n ≤ 127

Fi = Fi+1

INT · Si = Si+1

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = iadd

Fi = Fi+1

Si = INT · INT · S′

Si+1 = INT · S′

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = isub

Fi = Fi+1

Si = INT · INT · S′

Si+1 = INT · S′

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

46

Page 47: A Framework for Deadlock Detection in Java

P [i] = imul

Fi = Fi+1

Si = INT · INT · S′

Si+1 = INT · S′

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = idiv

Fi = Fi+1

Si = INT · INT · S′

Si+1 = INT · S′

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = irem

Fi = Fi+1

Si = INT · INT · S′

Si+1 = INT · S′

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = iconst m1

Fi = Fi+1

INT · Si = Si+1

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

47

Page 48: A Framework for Deadlock Detection in Java

P [i] = iconst n0 ≤ n ≤ 5Fi = Fi+1

INT · Si = Si+1

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = dup

Fi = Fi+1

Si = τi[aj : τ j∈Jj ] · S′

Si+1 = τi[aj : τ j∈Jj ] · τi[aj : τ j∈J

j ] · S′

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = ifne LFi = Fi+1 = FL

Si = INT · Si+1 = INT · SL

Ti = Ti+1

i+ 1, L ∈ dom[P ]Zi = Zi+1 = ZL

F, S, Z, T, i ` P : Ti & ˆZi

Le altre istruzioni di salto condizionale (if) viste nella semantica operazionale vengono qui omesse dalmomento che le loro premesse e la loro conclusione sono identiche a quelle dell’istruzione ifne

48

Page 49: A Framework for Deadlock Detection in Java

P [i] = invokespecial < init > (σthis[aj : ⊥j∈J ], τ1[ak : τk∈Kk ], . . . , τn[aw : τw∈W

w ])V OIDFi = Fi+1

Si = τn[aw : τw∈Ww ] · . . . · τ1[ak : τk∈K

k ] · σ[aj : ⊥j∈J ] · Si+1

Type[σ] = σthis[aj : τ j∈Jj ]

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi+1 = Zi

F, S, Z, T, i ` P : Ti & ˆZi & < init > (σ[aj : ⊥j∈J ], τ1[ak : τk∈Kk ], . . . , τn[aw : τw∈W

w ])

P [i] = invokevirtual m(σthis[aj : τ j∈Jj ], τ1[ak : τk∈K

k ], . . . , τn[aw : τw∈Ww ])INT

Fi = Fi+1

Si = τn[aw : τw∈Ww ] · . . . · τ1[ak : τk∈K

k ] · σ[aj : τ j∈Jj ] · S′

Si+1 = INT · S′

Type[σ[aj : τ j∈Jj ]] = σthis[aj : τ j∈J

j ]

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi+1 = Zi

F, S, Z, T, i ` P : Ti & ˆZi & m(σ[aj : τ j∈Jj ], τ1[ak : τk∈K

k ], . . . , τn[aw : τw∈Ww ]) & (top(Zi), σ[aj : τ j∈J

j ])

P [i] = invokevirtual m(σthis[aj : τ j∈Jj ], τ1[ak : τk∈K

k ], . . . , τn[aw : τw∈Ww ])σ[av : τv∈V

v ]

Fi = Fi+1

Type[τi[av : τv∈Vv ]] = σ[av : τv∈V

v ]

Si = τn[aw : τw∈Ww ] · . . . · τ1[ak : τk∈K

k ] · σ[aj : τ j∈Jj ] · S′

Si+1 = τx[av : τv∈Vv ] · S′

Type[σ[aj : τ j∈Jj ]] = σthis[aj : τ j∈J

j ]

Type[τx[av : τv∈Vv ]] = σ[av : τv∈V

v ]Ti = Ti+1

i+ 1 ∈ dom[P ]Zi+1 = Zi

F, S, Z, T, i ` P : Ti & ˆZi & m(σ[aj : τ j∈Jj ], τ1[ak : τk∈K

k ], . . . , τn[aw : τw∈Ww ]) & (top(Zi), σ[aj : τ j∈J

j ])

P [i] = invokevirtual m(σthis[aj : τ j∈Jj ], τ1[ak : τk∈K

k ], . . . , τn[aw : τw∈Ww ])V OID

Fi = Fi+1

Si = τn[aw : τw∈Ww ] · . . . · τ1[ak : τk∈K

k ] · σ[aj : τ j∈Jj ] · Si+1

Type[σ[aj : τ j∈Jj ]] = σthis[aj : τ j∈J

j ]

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi+1 = Zi

F, S, Z, T, i ` P : Ti & ˆZi & m(σ[aj : τ j∈Jj ], τ1[ak : τk∈K

k ], . . . , τn[aw : τw∈Ww ]) & (top(Zi), σ[aj : τ j∈J

j ])

49

Page 50: A Framework for Deadlock Detection in Java

P [i] = invokestatic σ[aj : τ j∈Jj ].m(τ1[ak : τk∈K

k ], . . . , τn[aw : τw∈Ww ])V OID

Fi = Fi+1

Si = τn[aw : τw∈Ww ] · . . . · τ1[ak : τk∈K

k ] · Si+1

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi+1 = Zi

F, S, Z, T, i ` P : Ti & ˆZi & m(σ[aj : τ j∈Jj ], τ1[ak : τk∈K

k ], . . . , τn[aw : τw∈Ww ]) & (top(Zi), σ[aj : τ j∈J

j ])

P [i] = invokestatic σ[aj : τ j∈Jj ].m(τ1[ak : τk∈K

k ], . . . , τn[aw : τw∈Ww ])INT

Fi = Fi+1

Si = τn[aw : τw∈Ww ] · . . . · τ1[ak : τk∈K

k ] · S′

Si+1 = INT · S′

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi+1 = Zi

F, S, Z, T, i ` P : Ti & ˆZi & m(σ[aj : τ j∈Jj ], τ1[ak : τk∈K

k ], . . . , τn[aw : τw∈Ww ]) & (top(Zi), σ[aj : τ j∈J

j ])

P [i] = invokestatic σ[aj : τ j∈Jj ].m(τ1[ak : τk∈K

k ], . . . , τn[aw : τw∈Ww ])σ′[av : τv∈V

v ]

Fi = Fi+1

Si = τn[aw : τw∈Ww ] · . . . · τ1[ak : τk∈K

k ] · S′

Si+1 = τx[av : τv∈Vv ] · S′

Type[τx[av : τv∈Vv ]] = σ′[av : τv∈V

v ]Ti = Ti+1

i+ 1 ∈ dom[P ]Zi+1 = Zi

F, S, Z, T, i ` P : Ti & ˆZi & m(σ[aj : τ j∈Jj ], τ1[ak : τk∈K

k ], . . . , τn[aw : τw∈Ww ]) & (top(Zi), σ[aj : τ j∈J

j ])

50

Page 51: A Framework for Deadlock Detection in Java

P [i] = invokevirtual java/lang/Thread.start()Fi = Fi+1

Si = σ[aj : τ j∈Jj ] · Si+1

i+ 1 ∈ dom[P ]Zi = Zi+1

Ti+1 = Ti ] { ˆσ[aj : τ j∈Jj ]}

F, S, Z, T, i ` P : ˆZi & Ti

P [i] = invokevirtual java/lang/Thread.join()Fi = Fi+1

Si = σ[aj : τ j∈Jj ] · Si+1

i+ 1 ∈ dom[P ]Zi = Zi+1

Ti+1 = Ti \ {σ}

F, S, Z, T, i ` P : Ti & ˆZi & (top(Z), σ[aj : τ j∈Jj ]

P [i] = new σ[aj : ⊥j∈J ]Fi = Fi+1

Si+1 = σi[aj : ⊥j∈J ] · Si

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

51

Page 52: A Framework for Deadlock Detection in Java

P [i] = return

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = ireturn

Si = INT · S′

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = areturn

Si = σ[aj : τ j∈Jj ] · S′

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = ldc INTFi = Fi+1

Si+1 = INT · Si

i+ 1 ∈ dom[P ]Ti = Ti+1

Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = ldc σ[aj : τ j∈Jj ]

Fi = Fi+1

Si+1 = σ[aj : τ j∈Jj ] · Si

Type[σ[aj : τ j∈Jj ]] = σ[aj : τ j∈J

j ]

i+ 1 ∈ dom[P ]Ti = Ti+1

Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

52

Page 53: A Framework for Deadlock Detection in Java

Come si puo vedere dalle regola putfield e putstatic si assume che i campi di un oggetto possono esseremodificati solo assegnando loro lo stesso valore o se non inizializzati. Il loro tipo pertanto non potravariare.

P [i] = putfield σ.a : τσ.a : τkFi = Fi+1

Si = τx · σ[aj : τ j∈Jj ] · Si+1

Type[σ[aj : τ j∈Jj ]] = σ[aj : τ j∈J

j ]

τk = ⊥ ∨ τk = τxTi = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = getfield σ.a : τσ.a : τxFi = Fi+1

Si = σ[aj : τ j∈Jj ] · S′

Si+1 = τx · S′

Type[σ[aj : τ j∈Jj ]] = σ[aj : τ j∈J

j ]

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = putstatic σ.a : τσ.a : τkFi = Fi+1

Si = τx · Si+1

τk = ⊥ ∨ τk = τxTi = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = getstatic σ.a : τσ.a : τxFi = Fi+1

Si+1 = τx · Si

Ti = Ti+1

i+ 1 ∈ dom[P ]Zi = Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

53

Page 54: A Framework for Deadlock Detection in Java

P [i] = monitorenter

Fi = Fi+1

Si = σ[aj : τ j∈Jj ] · Si+1

i+ 1 ∈ dom[P ]Ti = Ti+1

Zi+1 = σ[aj : τ j∈Jj ] · Zi

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = monitorexit

Fi = Fi+1

Si = σ[aj : τ j∈Jj ] · Si+1

i+ 1 ∈ dom[P ]Ti = Ti+1

Zi = σ[aj : τ j∈Jj ] · Zi+1

F, S, Z, T, i ` P : Ti & ˆZi

Infine vediamo le regole legate al lancio delle eccezioni. Qui la notazione PExcTable(i, σ) restituiscel’indirizzo dell’ExceptionHandler delegato alla gestione dell’eccezione di tipo σ quando questa si verificaall’istruzione i del metodo oppure ⊥ se l’eccezione non e gestita.

P [i] = athrow

PExcTable(i, σ[aj : τ j∈Jj ]) = k

Fi = Fk

Si = σ[aj : τ j∈Jj ] · S′

Sk = σ[aj : τ j∈Jj ]

Ti = Tk

k ∈ dom[P ]Zi = Zk

Type[σ[aj : τ j∈Jj ]] = java/lang/Throwable

F, S, Z, T, i ` P : Ti & ˆZi

P [i] = athrow

PExcTable(i, σ[aj : τ j∈Jj ]) = ⊥

Si = σ[aj : τ j∈Jj ] · S′

Type[σ[aj : τ j∈Jj ]] = java/lang/Throwable

F, S, Z, T, i ` P : Ti & ˆZi

54

Page 55: A Framework for Deadlock Detection in Java

Di seguito mostriamo come, partendo da un programma Java e analizzandone le relative istruzionibytecode, e possibile assegnare ad ogni metodo la relativa LAM ed andare poi a cercare eventualicircolarita che segnalino la presenza di un possibile deadlock.

package deadlock;

// pc1 = monitorenter , pc2 = monitorenter

public class Deadlock1 {

private Object a = new Object();

private Object b = new Object();

public void takelock() throws InterruptedException{

synchronized (a) {

synchronized (b) {

}

}

}

public void takelock2() throws InterruptedException{

synchronized (b) {

synchronized (a) {

}

}

}

public static void main(String[]args) throws InterruptedException{

Deadlock1 d = new Deadlock1();

Thread t1 = new Thread(){

@Override

public void run() {

try {

d.takelock();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

};

t1.start();

Thread t2 = new Thread() {

@Override

public void run() {

try {

55

Page 56: A Framework for Deadlock Detection in Java

d.takelock2();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

};

t2.start();

}

}

Vediamo di seguito, per ogni metodo, il relativo bytecode e la LAM corrispondente. Nei parametridei metodi viene usata la notazione τ[i] per indicare il tipo τ del parametro formale in posizione inella lista dei parametri. Tale tipo verra trattato come se fosse un tipo gia indicizzato τi e quindinon verra modificato da un eventuale load (o dup) del tipo sullo stack.A partire dalla LAM del metodo main si andra ad identificare una circolarita che indica il possibilestato di deadlock del programma. Per semplicita nel bytecode viene omesso il codice relativo allagestione delle eccezioni ed utilizzata le seguenti abbreviazioni:

– D per Deadlock1.– O per Object (che nel bytecode e tradotto in lava/lang/Object).– T1 per Deadlock1$1 cioe il primo Thread.– T2 per Deadlock1$2 cioe il secondo Thread.

56

Page 57: A Framework for Deadlock Detection in Java

i P [i] Si Ti

1 new D ε ∅2 dup D2[a : ⊥, b : ⊥] ∅3 invokespecial < init > (D) D2[a : ⊥, b : ⊥] ·D2[a : ⊥, b : ⊥] ∅4 astore 1 D2[a : O3, b : O4] ∅5 new T1 ε ∅6 dup T15[d : ⊥] ∅7 aload 1 T15[d : ⊥] · T15[d : ⊥] ∅8 invokespecial < init > (T1, D) D2[a : O3, b : O4] · T15[d : ⊥] · T15[d : ⊥] ∅9 astore 2 T15[d : D2] ∅

10 aload 2 ε ∅11 invokevirtual start() T15[d : D2] ∅12 new T2 ε {T15[d : D2]}13 dup T2[d : ⊥] {T15[d : D2]}14 aload 1 T2[d : ⊥] · T2[d : ⊥] {T15[d : D2]}15 invokespecial < init > (T2, D) D2[a : O3, b : O4] · T2[d : ⊥] · T2[d : ⊥] {T15[d : D2]}16 astore 3 T26[d : D2] {T15[d : D2]}17 aload 3 ε {T15[d : D2]}18 invokevirtual start()V T26[d : D2] {T15[d : D2]}19 return ε {T15[d : D2], T2[d : D2]}

i F [0] Fi[1] Fi[2] Fi[3]

1 TOP TOP TOP TOP2 TOP TOP TOP TOP3 TOP TOP TOP TOP4 TOP TOP TOP TOP5 TOP D2[a : O3, b : O4] TOP TOP6 TOP D2[a : O3, b : O4] TOP TOP7 TOP D2[a : O3, b : O4] TOP TOP8 TOP D2[a : O3, b : O4] TOP TOP9 TOP D2[a : O3, b : O4] TOP TOP

10 TOP D2[a : O3, b : O4] T15[d : D2] TOP11 TOP D2[a : O3, b : O4] T15[d : D2] TOP12 TOP D2[a : O3, b : O4] T15[d : D2] TOP13 TOP D2[a : O3, b : O4] T15[d : D2] TOP14 TOP D2[a : O3, b : O4] T15[d : D2] TOP15 TOP D2[a : O3, b : O4] T15[d : D2] TOP16 TOP D2[a : O3, b : O4] T15[d : D2] TOP17 TOP D2[a : O3, b : O4] T15[d : D2] T26[d : D2]18 TOP D2[a : O3, b : O4] T15[d : D2] T26[d : D2]19 TOP D2[a : O3, b : O4] T15[d : D2] T26[d : D2]

LAM(main(String[])) =

T1 & ˆZ1 ; T2 & ˆZ2 ; T3 & ˆZ3 & < init > (D2[a : ⊥, b : ⊥]) ; T4 & ˆZ4 ; T5 & ˆZ5 ; T6 & ˆZ6 ; T7 & ˆZ7 ; T8 & ˆZ8 & < init >

(T15[d : ⊥], D2[a : O3, b : O4]) ; T9 & ˆZ9 ; T10 & ˆZ10 ; T11 & ˆZ11 ; T12 & ˆZ12 ; T13 & ˆZ13 ; T14 & ˆZ14 ;

T15 & ˆZ15 & < init > (T26[d : ⊥], D2[a : O3, b : O4]) ; T16 & ˆZ16 ; T17 & ˆZ17 ; T18 & ˆZ18 ; T19 & ˆZ19 ;

= 0 ; 0 ;< init > (D2[a : ⊥, b : ⊥]) ; 0 ; 0 ; 0 ; 0 ; < init > (T15[d : ⊥], D2[a : O3, b : O4]) ; 0 ; 0 ; 0 ;

run(T15[d : D2]) ; run(T15[d : D2]) ; run(T15[d : D2]) ;

run(T15[d : D2]) & < init > (T26[d : ⊥], D2[a : O3, b : O4]) ;

run(T15[d : D2]) ; run(T15[d : D2]) ; run(T15[d : D2]) ; run(T15[d : D2]) & run(T26[d : D2]) ;

=< init > (D2[a : ⊥, b : ⊥]) ; < init > (T15[d : ⊥], D2[a : O3, b : O4]) ; run(T15[d : D2]) ;

run(T15[d : D2]) & < init > (T26[d : ⊥], D2[a : O3, b : O4]) ; run(T15[d : D2]) & run(T26[d : D2]) ;

Fig. 1. Metodo main() che lancia i due thread e relativa LAM

57

Page 58: A Framework for Deadlock Detection in Java

i P [i] Fi[0] Si

1 aload 0 D[0][a : ⊥, b : ⊥] ε2 invokespecial < init > (O)V D[0][a : ⊥, b : ⊥] D[0][a : ⊥, b : ⊥]3 aload 0 D[0][a : ⊥, b : ⊥] ε4 new O D[0][a : ⊥, b : ⊥] D[0][a : ⊥, b : ⊥]

5 dup D[0][a : ⊥, b : ⊥] O⊥7 ·D[0][a : ⊥, b : ⊥]

6 invokespecial < init > (O)V D[0][a : ⊥, b : ⊥] O⊥7 ·O⊥

7 ·D[0][a : ⊥, b : ⊥]7 putfield D.a : O D[0][a : ⊥, b : ⊥] O3 ·D[0][a : ⊥, b : ⊥]8 aload 0 D[0][a : O3, b : ⊥] ε9 new O D[0][a : O3, b : ⊥] D[0][a : O3, b : ⊥]

10 dup D[0][a : O3, b : ⊥] O⊥8 ·D[0][a : O3, b : ⊥]

11 invokespecial < init > (O)V D[0][a : O3, b : ⊥] O⊥8 ·O⊥

8 ·D[0][a : O3, b : ⊥]12 putfield D.b : O D[0][a : O3, b : ⊥] O4 ·D[0][a : O3, b : ⊥]13 return D[0][a : O3, b : O4] ε

LAM(< init > (D[0][a : ⊥, b : ⊥]))=

T1 & ˆZ1 ; T2 & ˆZ2 ; T3 & ˆZ3 ; T4 & ˆZ4 ; T5 & ˆZ5 ; T6 & ˆZ6 & < init > (O⊥7 ); T7 & ˆZ7 ; T8 & ˆZ8 ; T9 & ˆZ9 ; T10 & ˆZ10 ;

T11 & ˆZ11 & < init > (O⊥8 ); T12 & ˆZ12 ; T13 & ˆZ13 ;

= 0; 0; 0; 0; 0; < init > (O⊥7 ); 0; 0; 0; 0; < init > (O⊥

8 ); 0; 0;

= < init > (O⊥7 ); < init > (O⊥

8 ); = 0

Fig. 2. Metodo < init > (D[0][a : ⊥, b : ⊥]) e relativa LAM

A riga 2 del precedente codice viene invocato il costruttore della superclasse java/lang/Object; Nelle LAMnon prendiamo in considerazione la relativa invocazione < init > (java/lang/Object)V perche chiama ilcostruttore di una classe definita nella libreria standard di Java e non in una delle classi del nostro programma.Lo stesso facciamo con l’invocazione < init > (java/lang/Thread)V dei due metodi seguenti.

58

Page 59: A Framework for Deadlock Detection in Java

i P [i] Fi[0] Fi[1] Si

1 aload 0 T1[0][d : ⊥] D[1][a : O9, b : O10] ε2 aload 1 T1[0][d : ⊥] D[1][a : O9, b : O10] T1[0][d : ⊥]3 putfield T1.d : D T1[0][d : ⊥] D[1][a : O9, b : O10] D[1][a : O9, b : O10] · T1[0][d : ⊥]4 aload 0 T1[0][d : D[1]] D[1][a : O9, b : O10] ε5 invokespecial< init > (java/lang/Thread)V T1[0][d : D[1]] D[1][a : O9, b : O10] T1[0]

6 return T1[0][d : D[1]] D[1][a : O9, b : O10] ε

LAM(< init > (T1[0][d : ⊥], D[1][a : O9, b : O10]))= T1 & ˆZ1 ; T2 & ˆZ2 ; T3 & ˆZ3 ; T4 & ˆZ4 ; T5 & ˆZ5 ; T6 & ˆZ6 ;

= 0; 0; 0; 0; 0; 0; = 0;

Fig. 3. Metodo < init > (T1[0][d : ⊥], D[1][a : O9, b : O10]) del primo thread e relativa LAM

i P [i] Fi[0] Fi[1] Si

1 aload 0 T2[0][d : ⊥] D[1][a : O11, b : O12] ε2 aload 1 T2[0][d : ⊥] D[1][a : O11, b : O12] T2[0][d : ⊥]3 putfield T2.d : D T2[0][d : ⊥] D[1][a : O11, b : O12] D[1][a : O11, b : O12] · T2[0][d : ⊥]4 aload 0 T2[0][d : D[1]] D[1][a : O11, b : O12] ε5 invokespecial< init > (java/lang/Thread)V T2[0][d : D[1]] D[1][a : O11, b : O12] T2[0]

6 return T2[0][d : D[1]] D[1][a : O11, b : O12] ε

LAM(< init > (T2[0][d : ⊥], D[1][a : O11, b : O12]))= T1 & ˆZ1 ; T2 & ˆZ2 ; T3 & ˆZ3 ; T4 & ˆZ4 ; T5 & ˆZ5 ; T6 & ˆZ6 ;

= 0; 0; 0; 0; 0; 0; = 0;

Fig. 4. Metodo < init > (T2[0][d : ⊥], D[1][a : O11, b : O12]) del secondo thread e relativa LAM

59

Page 60: A Framework for Deadlock Detection in Java

i P [i] Fi[0] Si Zi

1 aload 0 T1[0][d : D13] ε ε2 getfield T1.d : D T1[0][d : D13] T1[0][d : D13] ε

3 invokevirtual takelock(D)V T1[0][d : D13] DT1[0].d

13 ε4 return T1[0][d : D13] ε ε

LAM(run(T1[0][d : D13])) =

T1 & ˆZ1 ; T2 & ˆZ2 ; T3 & ˆZ3 & takelock(DT1[0].d

13 ) & (top(Z), DT1[0].d

13 ); T4 & ˆZ4 ;

= 0; 0; takelock(DT1[0].d

13 ) ; 0;

= takelock(DT1[0].d

13 ) ;

Fig. 5. Metodo run(T1[0][d : D13]) del primo thread e relativa LAM

i P [i] Fi[0] Si Zi

1 aload 0 T2[0][d : D14] ε ε2 getfield T2.d : D T2[0][d : D14] T2[0][d : D14] ε

3 invokevirtual takelock(D)V T2[0][d : D14] DT2[0].d

14 ε4 return T2[0][d : D14] ε ε

LAM(run(T2[0][d : D14])) =

T1 & ˆZ1 ; T2 & ˆZ2 ; T3 & ˆZ3 & takelock(DT2[0].d

14 ) & (top(Z), DT2[0].d

14 ); T4 & ˆZ4 ;

= 0; 0; takelock(DT2[0].d

14 ) ; 0;

= takelock(DT2[0].d

14 ) ;

Fig. 6. Metodo run(T2[0][d : D14]) del secondo thread e relativa LAM

60

Page 61: A Framework for Deadlock Detection in Java

Nelle regole di seguito σ′ e σ′′ stanno rispettivamente per OD[0].a15 e O

D[0].b16 :

i P [i] Fi[0] Fi[1] Fi[2] Si Zi

1 aload 0 D[0][a : O15, b : O16] TOP TOP ε ε2 getfield D.a : O D[0][a : O15, b : O16] TOP TOP D[0][a : O15, b : O16] ε3 dup D[0][a : O15, b : O16] TOP TOP σ′ ε4 astore 1 D[0][a : O15, b : O16] TOP TOP σ′ · σ′ ε5 monitorenter D[0][a : O15, b : O16] σ′ TOP σ′ ε6 aload 0 D[0][a : O15, b : O16] σ′ TOP ε σ′

7 getfield D.b : O D[0][a : O15, b : O16] σ′ TOP D[0][a : O15, b : O16] σ′

8 dup D[0][a : O15, b : O16] σ′ TOP σ′′ σ′

9 astore 2 D[0][a : O15, b : O16] σ′ TOP σ′′ · σ′′ σ′

10 monitorenter D[0][a : O15, b : O16] σ′ σ′′ σ′′ σ′

11 aload 2 D[0][a : O15, b : O16] σ′ σ′′ ε σ′′ · σ′

12 monitorexit D[0][a : O15, b : O16] σ′ σ′′ σ′′ σ′′ · σ′

13 aload 1 D[0][a : O15, b : O16] σ′ σ′′ ε σ′

14 monitorexit D[0][a : O15, b : O16] σ′ σ′′ σ′ σ′

15 return D[0][a : O15, b : O16] σ′ σ′′ ε ε

LAM(takelock(D[0][a : O15, b : O16]))=

T1 & ˆZ1 ; T2 & ˆZ2 ; T3 & ˆZ3 ; T4 & ˆZ4 ; T5 & ˆZ5 ; T6 & ˆZ6 ; T7 & ˆZ7 ; T8 & ˆZ8 ;

T9 & ˆZ9 ; T10 & ˆZ10; T11 & ˆZ11 ; T12 & ˆZ12 ; T13 & ˆZ13 ; T14 & ˆZ14 ; T15 & ˆZ15 ;

= 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; (σ′, σ′′) ; (σ′, σ′′) ; 0 ; 0 ; 0 ;

= (σ′, σ′′);

Fig. 7. Metodo takelock(D[0][a : O15, b : O16]) eseguito dal primo thread

61

Page 62: A Framework for Deadlock Detection in Java

i P [i] Fi[0] Fi[1] Fi[2] Si Zi

1 aload 0 D[0][a : O17, b : O18] TOP TOP ε ε2 getfield D.b : O D[0][a : O17, b : O18] TOP TOP D[0][a : O17, b : O18] ε3 dup D[0][a : O17, b : O18] TOP TOP σ′′ ε4 astore 1 D[0][a : O17, b : O18] TOP TOP σ′′ · σ′′ ε5 monitorenter D[0][a : O17, b : O18] σ′′ TOP σ′′ ε6 aload 0 D[0][a : O17, b : O18] σ′′ TOP ε σ′′

7 getfield D.a : O D[0][a : O17, b : O18] σ′′ TOP D[0][a : O17, b : O18] σ′′

8 dup D[0][a : O17, b : O18] σ′′ TOP σ′ σ′′

9 astore 2 D[0][a : O17, b : O18] σ′′ TOP σ′ · σ′ σ′′

10 monitorenter D[0][a : O17, b : O18] σ′′ σ′ σ′ σ′′

11 aload 2 D[0][a : O17, b : O18] σ′′ σ′ ε σ′ · σ′′

12 monitorexit D[0][a : O17, b : O18] σ′′ σ′ σ′ σ′ · σ′′

13 aload 1 D[0][a : O17, b : O18] σ′′ σ′ ε σ′′

14 monitorexit D[0][a : O17, b : O18] σ′′ σ′ σ′′ σ′′

15 return D[0][a : O17, b : O18] σ′′ σ′ ε ε

LAM(takelock2(D[0][a : O17, b : O18]))=

T1 & ˆZ1 ; T2 & ˆZ2 ; T3 & ˆZ3 ; T4 & ˆZ4 ; T5 & ˆZ5 ; T6 & ˆZ6 ; T7 & ˆZ7 ; T8 & ˆZ8 ;

T9 & ˆZ9 ; T10 & ˆZ10; T11 & ˆZ11 ; T12 & ˆZ12 ; T13 & ˆZ13 ; T14 & ˆZ14 ; T15 & ˆZ15 ;

= 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; 0 ; (σ′′, σ′) ; (σ′′, σ′) ; 0 ; 0 ; 0 ;

= (σ′′, σ′);

Fig. 8. Metodo takelock2(D[0][a : O17, b : O18]) eseguito dal secondo thread

62

Page 63: A Framework for Deadlock Detection in Java

Adesso che abbiamo sia la LAM del main che quelle dei metodi del programma andiamo a sosti-tuire nella LAM del main le invocazioni di metodo con le corrispondenti LAM facendo attenzionea rimpiazzare opportunamente i parametri formali con quelli attuali.

< init > (D2[a : ⊥, b : ⊥]) ; < init > (T15[d : ⊥], D2[a : O3, b : O4]) ; run(T15[d : D2[a : O3, b :O4]]) ; run(T15[d : D2[a : O3, b : O4]]) & < init > (T26[d : ⊥], D2[a : O3, b : O4]) ; run(T15[d : D2[a :

O3, b : O4]]) & run(T26[d : D2[a : O3, b : O4]]) ;

= 0; 0; takelock(DT15.d2 [a : O3, b : O4]); takelock(DT15.d

2 [a : O3, b : O4]) & 0;

takelock(DT15.d2 [a : O3, b : O4]) & takelock2(DT26.d

2 [a : O3, b : O4]) ;

= (O(D2.a)3 , O

(D2.b)4 ) ;

(O(D2.a)3 , O

(D2.b)4 ) & (O

(D2.b)4 , O

(D2.a)3 ) ;

= (O(D2.a)3 , O

(D2.b)4 ) & (O

(D2.b)4 , O

(D2.a)3 ) ;

Quindi si ha una circolarita:

(O(D2.a)3 , O

(D2.a)3 ) ;

che indica la presenza di deadlock.

6 Conclusioni

A seguito di una lunga fase progettuale circa la semantica operazionale ed i tipi comportamentali(seppur momentaneamente non considerando alcune primitive quali la wait e notify) si e potutigiungere all’implementazione di un primo prototipo funzionanate per la costruzione delle LAMsa partire da un semplice programma in Java. Il progetto, dunque, seppur soggetto ad alcunelimitazioni, costituisce un primo tentativo per la stesura di un framework generale per l’analisidi deadlock in Java.

References

[1] Elena Giachino, Carlo A Grazia, Cosimo Laneve, Michael Lienhardt, and Peter YH Wong.Deadlock analysis of concurrent objects: Theory and practice. In Integrated Formal Methods,pages 394–411. Springer, 2013.

[2] Elena Giachino, Cosimo Laneve, and Michael Lienhardt. A framework for deadlock detectionin abs. Software and System Modeling (to appear, 2014), 2014.

63