Title: Goldilocks: A Transaction and RaceAware Runtime for Java
1Goldilocks A Transaction and Race-Aware Runtime
for Java
- Serdar Tasiran
- Koç University Istanbul, Turkey
-
Shaz Qadeer Microsoft Research
Redmond, WA
Tayfun Elmas Koç UniversityIstanbul, Turkey
2More cores ? more concurrency
- Programmers will be forced to make more intensive
use of concurrency - More potential for concurrency-related errors
- Transactions will not solve all
concurrency-related problems - "offline concurrency" - concurrency that spans
transactions will always be needed Martin
Fowler, Patterns for Enterprise Application
Architecture - Other concurrent programming mechanisms will
co-exist with software and hardware transactions - Concurrency errors
- Non-deterministic, difficult to reproduce,
diagnose - BUT More computational power available for
runtime checks! - Static pre-elimination of concurrency errors
expensive, sometimes not possible - Deployed code will contain concurrency bugs
3Runtime Exceptions for Concurrency Errors
- Research direction Runtimes that
- detect concurrency-related errors
- race conditions, atomicity violations, refinement
violations - bring errors to the attention of programmer
- ConcurrencyException (a special kind of
RuntimeException) - Programmer explicitly specifies what to do when
concurrency error is detected. - Not as straightforward to define and implement as
NullPointerException or ArrayIndexOutOfBoundsExcep
tion
4Our recent focus
- Race conditions Often symptomatic of
concurrency-related errors - We built a runtime that provides a precise
DataRaceException - like NullPointerException, ArrayIndexOutOfBoundExc
eption - thrown when a data race is about to happen
5APACHE FTP SERVER CONNECTION HANDLING
public void run()
public void close()
INITIALIZE THE CONNECTION
CLOSE CONNECTION
2 // check whether already closed //or not 3
synchronized(this) 4 if(m_isConnectionClosed)
5 return 6 m_isConnectionClosed true 7
8 ...
2 ... 3 dereference m_request, m_writer,
m_reader 4 and m_controlSocket to initialize the
connection 5 ...
while(connection is alive) READ NEXT REQUEST
PERFORM REQUESTED ACTION (USINGREQUEST
HANDLERS FIELDS)
CLEAR FIELDS (SET FIELDS TO NULL)
6 while(!m_isConnectionClosed) 7 String
commandLine m_reader.readLine() 8
if(commandLine null) 9 break 10
11 commandLine commandLine.trim() 12
if(commandLine.equals("")) 13
continue 14 15 m_request.parse(commandL
ine) 16 if(!hasPermission()) 17
m_writer.send(530, "permission", null) 18
continue 19 20 // execute command 21
service(m_request, m_writer) 22
9 m_request null 10 m_writer null 11
m_reader null 12 m_controlSocket null ...
These fields are shared
Shared Fields
6BUG MANIFESTATION
Connection thread
Close Thread
public void run()
public void close()
2 ... 3 dereference m_request, m_writer,
m_reader 4 and m_controlSocket to initialize the
connection 5 ...
2 // check whether already closed //or not 3
synchronized(this) 4 if(m_isConnectionClosed)
5 return 6 m_isConnectionClosed true 7
8 ...
Detects thatconnection is alive
6 while(!m_isConnectionClosed) 7 String
commandLine m_reader.readLine() 8
if(commandLine null) 9 break 10
11 commandLine commandLine.trim() 12
if(commandLine.equals("")) 13
continue 14 15 m_request.parse(commandL
ine) 16 if(!hasPermission()) 17
m_writer.send(530, "permission", null) 18
continue 19 20 // execute command 21
service(m_request, m_writer) 22
9 m_request null 10 m_writer null 11
m_reader null 12 m_controlSocket null ...
Null Pointer Exception
7DataRaceException for detecting bug symptoms
8Defining races in the presence of transactions
9Races and transactions
10Why we check for races at runtime?
- Precise static detection undecidable
- Conservative checks require manual effort to rule
out false alarms - Not possible for open programs.
- The Java Memory Model Manson et.al, POPL05
- Correctly synchronized programs Race-free
programs - Race-freedom ? Program runs with
sequentially-consistent semantics - Semantics for race-y programs Complicated,
causality-based definition - Only for compiler and virtual machine designers
- DataRaceException Warning to programmer about
poor synchronization
11Existing dynamic approaches
- Vector-clock algorithms Mattern, 1989
- Vector clock For each thread and variable, a
vector of logical clocks - Vector has size T threads
- Vector updated at each synchronization operation
- Precise but inefficient in some cases
- O(T) computation at each synchronization
operation - Other algorithms use cheaper checks for
well-protected variables - Thread-local variables, variables protected by
single locks - Lockset algorithms Eraser, ...
Savage et.al., 1997 - Lockset A set of locks protecting access to
variable d - Lockset update rules specific to a
synchronization discipline - Efficient, intuitive, but imprecise
- False alarms Synchronization discipline violated
but no race occurred - Additional mechanisms to reduce false alarms
- State machines for object initialization, escape,
thread-locality
12A Precise, Efficient Race-Detection Algorithm
- To implement DataRaceException
- Need precise race detection algorithm.
- False alarms not acceptable in this context.
- Goldilocks Efficiently Computingthe
Happens-Before Relation Using LocksetsElmas,
Qadeer, Tasiran, FATES/RV 06 - Goldilocks A Race and Transaction-Aware Runtime
for JavaElmas, Qadeer, Tasiran, PLDI 07
13Example
T1 T2 T3
a IntBox()
class IntBox int x
L1
b IntBox()
acquire(L1)
L2
a.x
Global Variablesa, b IntBoxo1.x, o2.x int
release(L1)
acquire(L1)
acquire(L2)
tmp a
a b
b tmp
release(L1)
L1
release(L2)
acquire(L2)
L2
b.x
release(L2)
14Eraser
a IntBox()
LS(o1.x) all locks
b IntBox()
acquire(L1)
T1
a.x
release(L1)
acquire(L1)
acquire(L2)
tmp a
T2
a b
b tmp
release(L1)
release(L2)
acquire(L2)
b.x
T3
release(L2)
15The happens-before relation
- Happens-before in JMM ?hb
- Transitive closure of
- Program orders of threads ?p
- Synchronizes-with ?sw
- release(l) ?sw acquire(l)
- vol-write(v) ?sw vol-read(v)
- fork(t) ?hb (action of t)
- (action of t) ?hb join(t)
T1
a.x
T2
b.x
T3
16The Goldilocks algorithm FATES/RV 06
- Novel lockset-based characterication of the
happens-before relation - As efficient as other lockset algorithms
- As precise as vector-clocks
- Uniformly captures all synchronization
disciplines - Our locksets contain locks, volatile variables,
thread ids - Theorem When thread t accesses variable d,
there is no race - iff
- Lockset of d at that point contains t
- Sound Detects all apparent races that occur in
execution - Precise Race reported ? Two accesses not ordered
by happens-before - No false alarms, no alarms about potential races
17Goldilocks intuition
- LS (Variables) ? ?(Threads ?? Locks ? Volatiles)
- Update rules maintain invariants
- Thread t ? LS(d) ? ? t is owner of d
- Accesses to d by t are race-free
- Lock l ? LS(d) ? acquire l to become
owner of d - Volatile v ? LS(d) ? read v to become owner of
d - When t accesses d Race-free iff (t ? LS(d))
- After t accesses d LS(d) t
- t is the only owner of d
- Other threads Must synchronize with t
- In order to become an owner of d
18Lockset update rules
- Ownership transfer between threads
- LS(d) grows through synchronization actions
- release(l) by t
- For each variable d if (t ? LS(d)) ? (add l to
LS(d)) - acquire(l) by t
- For each variable d if (l ? LS(d)) ? (add t to
LS(d)) - volatile-write(v) by t
- For each variable d if (t ? LS(d)) ? (add v to
LS(d)) - volatile-read(v) by t
- For each variable d if (v ? LS(d)) ? (add t to
LS(d)) - fork(s) by t
- For each variable d if (t ? LS(d)) ? (add s to
LS(d)) - join(s) by t
- For each variable d if (s ? LS(d)) ? (add t to
LS(d))
19Goldilocks
a IntBox()
LS(o1.x) ?
b IntBox()
acquire(L1)
T1
a.x
release(L1)
acquire(L1)
acquire(L2)
tmp a
T2
a b
b tmp
release(L1)
release(L2)
acquire(L2)
b.x
T3
release(L2)
20Uniform handling of many scenarios
- Dynamically changing locksets
- Permanent/temporary thread-locality
- Container-protected objects
- Lockset of contained variable changesalthough
variable is not touched - Synchronization using wait/notify(All)
- No additional lockset update rules
- Synchronization using volatile variables
- Conditional branches on volatile variables
- Classes in java.util.concurrent package
- Semaphores, barriers, ...
21Defining races in the presence of transactions
22Extending the happens-before relation to
transactions
- Happens-before in JMM ?hb Transitive closure
of - Program orders of threads ?p
- Synchronizes-with ?sw
- release(l) ?sw acquire(l)
- vol-write(v) ?sw vol-read(v)
- fork(t) ? hb (action of t)
- (action of t) ? hb join(t)
- Transactions
- Two accesses a1 and a2 are race-free if they are
both within transactions - Transaction t1 happens before transaction t2 iff
t1 and t2 access a common variable - Transaction implementation provides list of
accessed variables at commit point to
race-checker/Java runtime
23Extending the happens-before relation to
transactions
- Happens-before in JMM ?hb
- Transitive closure of
- Program orders of threads ?p
- Synchronizes-with ?sw
- release(l) ?sw acquire(l)
- vol-write(v) ?sw vol-read(v)
- fork(t) ? hb (action of t)
- (action of t) ? hb join(t)
- Extended happens-before ? ehb
- Transitive closure of
- JMMs hb ?hb
- Transaction t1 ? ehb t2 iff
- t1 and t2 access at least one common variable
- Extended locksetsLS (Variables) ? ?(Threads
?? Locks ? Volatiles ?
Data Variables ? TL)
24t1 new Foo()
LS(o.data) ?
First access
t1.data 42
LS(o.data) T1
begin_tr
T1
t1.nxt head
head t1
(T1 ? LS) ? (add o.nxt, head to LS)
end_tr
LS(o.data) T1, o.nxt, head
begin_tr
iter head
iter ! null
T2
iter.data 0
iter iter.nxt
LS(o.data) T1, o.nxt, head, T2
(head,o.data,o.nxt ? LS ? ?) ? (add T2 to LS)
iter null
LS(o.data) TL, T2
(TL,T2 ? LS ? ?) ? (No race)
end_tr
LS(o.data) TL, T2, head, o.data, o.nxt
(T2 ? LS) ? (add head,o.data,o.nxt to LS)
begin_tr
t3 head
T3
head t3.nxt
LS(o.data) TL, T2, head, o.data, o.nxt,T3
(head, o.nxt ? LS ? ?) ? (add T3 to LS)
end_tr
LS(o.data) TL, T2, head, o.data, o.nxt,T3
(T3 ? LS) ? (add head, o.nxt to LS)
(T3 ? LS) ? (No race)
t3.data
LS(o.data) T3
25Implementation
- Naive implementation too inefficient
- acquire(l) by thread t
- For each variable d if (l ? LS(d)) ? (add t to
LS(d)) - Implementation features
- Short-circuit checks before lockset computation
- Handle thread-locality, unique protecting
lock,... - Lazy evaluation of locksets
- Apply update rules at only variable access
- Keep synchronization actions in a global event
list - Order of events consistent with ?p and ?sw
- Implicit, shared representation of locksets
- Use temporary locksets only at access
26Implementation in Kaffe
- In the Kaffe Virtual Machine
http//www.kaffe.org - Clean room implementation of JVM in C
- Full Java platform functionality
- Instrumented byte-code interpreter
- Functions executing instructions for
synchronization, heap access - Per thread checking
- Each thread checks its own actions
- Communication via global event list
- Applicable to multiprocessors
- Handle-Action (Thread t, Action ?)
- IF ? is a synchronization action
- Add ? to the global event list
- ELSE IF ? is an access to variable d
- IF all short-circuit checks fail
- Apply-Lockset-Rules(t, d)
27Short-circuit checks
- Sufficient, constant time checks for H-B
- If any of them succeed No race
- ? No need for lockset computation
- Track owner thread
- For each variable d, keep the last accessor
thread - owner-thread(d) Current accessor thread
- Succeeds when d remains thread-local
- Track same lock last time
- For each variable d, guess a protecting lock
- single-lock(d) Random lock held by current
accessor thread - Succeeds as long as d is accessed while holding
same lock - Direct ownership transfer from one thread to
another - Synchronization events by other threads in the
middle are irrelevant
28New Implementation Features
- Static analysis to rule out definitely
race-free accessesto avoid runtime checks - Using
- a variant of Chord Naik et. al., PLDI 06
- RccJava Abadi, et. al. ACM TOPLAS 06
- Technicalities
- Parse outputs of static tools
- Write results of static analysis into Java class
file - Goldilocks implementation in Kaffe skips checks
for marked fields, methods, classes - Different static tools can capture different
synchronization idioms - Static tools not completely sound
- Example May need to turn on race checking in
constructors only
29Experimental Evaluation
- Goldilocks compared with vs. other Java dynamic
race detectors - Racetrack Yu et. al., SOSP 05
- TRaDe Christiaens et. al., ICCSS 01
- IBM race detection tool Choi et. al., PLDI 02
- Benchmarks
- Microbenchmarks Interesting, artificial programs
- Larger programs for performance comparison
- Raja, SciMark, Grande
30Experiments
- Goldilocks performance competitive in all
examples - Significantly better in some
- With careful implementation, precision and
handling of transactions can be implemented
efficiently