k. rustan m. leino peter müller ifip wg 2.3 meeting 49 10 june 2009 boston, ma
TRANSCRIPT
Locks, channels, deadlock freedom, progress
K. Rustan M. LeinoPeter Müller IFIP WG 2.3 meeting
4910 June 2009Boston, MA
Chalice object life cycle (abridged)
Locks are objects, objects are locks
thread local
shared,availabl
e
shared,locked
new
share
acquire
release
Locking order in ChaliceEvery lock has an associated locking levelLocks have to be acquired in ascending order, which avoids deadlocks
Locking order detailsLocking order is a dense semi-lattice(Mu, <<, , ) << is the strict version of <<The locking level of an object o is stored in a mutable ghost field o.muAccessing o.mu requires appropriate permissions
Examplemethod M(o: C)
requires rd(o.mu) maxlock << o.mu
…{
acquire o…release o
}
(lHeld l.mu)
Semantics (defined by pseudo code)o := new C ≡ … o.mu := …share o between L and H ≡
assert CanWrite(o,mu) o.mu = ;assert L << H;havoc μ; assume L << μ << H;o.mu := μ;Exhale MonitorInv(o);
acquire o ≡ assert CanRead(o,mu);assert maxlock << o.mu;Held := Held {o};Inhale MonitorInv(o);
release o ≡ assert o Held;Exhale MonitorInv(o);Held := Held – {o};
thread local
shared,availabl
e
shared,locked
new
share
acquire
release
Lock reorderingreorder o between L and H ≡
assert CanWrite(o,mu) o.mu ≠ ;assert L << H;assert o Held; havoc μ; assume L << μ << H;o.mu := μ; method M(o: C)
requires rd(o.mu) maxlock << o.mu
…{
acquire o…release o
}
(lHeld l.mu)
Threadsfork tk := o.M()join tk
Join deadlockThread 0:
fork tk := o.M()acquire pjoin tkrelease p
Thread 1:
method M()…
{acquire p…release p
}
Avoiding join deadlocksTokens record the initial maxlock of the new threadfork tk := o.M() ≡
tk.forkMaxlock := maxlock;…
join tk ≡assert maxlock <<
tk.forkMaxlock;…
Example correctedThread 0:
fork tk := o.M()acquire pjoin tkrelease p
Thread 1:
method M()requires
rd(p.mu) maxlock <<
p.mu{
acquire p…release p
}
Channelschannel Name(signature) where predicate
Example:channel Ch(t: T) where acc(t.x) 0 ≤ t.x < 100
Channels have unbounded slackthat is: sends are non-blocking
ch := new Chsend ch(E) ≡ Exhale Where(ch);receive x := ch ≡ Inhale Where(ch);
Progress problemsThread 0:
receive x := ch
acquire oreceive x := ch
Thread 1:
/* No send. Ever. */
acquire osend ch(E)
or:
CreditsChannels have associated credits
cf. memory locations have associated permissions
receive requires a creditsend produces a creditSpecification syntax: credit(ch, n)where n is an integer, denotes n credits for channel ch
If omitted, n defaults to 1Negative credits are debits
Encoding of creditsIntroduce a per-activation-record credits counter C : channel int
cf. per-activation-record permissions mask P in Peter’s talk
Inhale credit(ch,n) ≡ C[ch] := C[ch] + nExhale credit(ch,n) ≡ C[ch] := C[ch] – n
Credit accountingch := new Ch ≡
… C[ch] := 0; …send ch(E) ≡
Inhale credit(ch,1); Exhale Where(ch);receive x := E ≡
assert C[ch] > 0;Inhale Where(ch); Exhale
credit(ch,1);
sell where clause,
obtain 1 credit
pay 1 credit,receive where
clause
Ensuring progressAssociate a locking level also with every channel ch, recorded in a field ch.much := new Ch between L and H ≡ …receive x := ch ≡
assert CanRead(ch,mu) maxlock << ch.mu;… // as before
send ch(E) ≡assert CanRead(ch,mu); ?… // as before
reorder – not yet worked out
Going into debtmaxlock ≡
(lHeld l.mu) (ch | C[ch] < 0 ch.mu)
Inhale credit(ch,n) ≡ Exhale credit(ch,-n)Exhale credit(ch,n) ≡
assert C[ch] – n < 0 ≤ C[ch] maxlock << ch.mu;C[ch] := C[ch] – n;
Credit-leak checkingAt the end of every activation record:
assert (ch 0 ≤ C[ch]);
Producer / Consumer exampleclass Cell { var val: int; … }
channel Ch(x: Cell) wherex ≠ null
acc(x.val) 0 ≤ x.val credit(this)class Program {
method Main() …method Producer(ch: Ch) …method Consumer(ch: Ch) …
}
P/C: Mainmethod Main() { var ch := new Ch fork tk0 := Producer(ch) fork tk1 := Consumer(ch) join tk0 join tk1}
P/C: Producermethod Producer(ch: Ch)
requires rd(ch.mu)ensures credit(ch, 1)
{while (…)
invariant rd(ch.mu){
var x := …send ch(x)
}send ch(null)
}
requires rd(ch.mu)requires credit(ch,
-1)ensures true
or:
P/C: Consumermethod Consumer(ch: Ch)
requires rd(ch.mu) maxlock << ch.murequires credit(ch)ensures rd(ch.mu)
{receive x := chwhile (x ≠ null)
invariant x ≠ null credit(ch){
…receive x := ch
} }