Proving Dekker with SPIN and PROMELA

Joshua Wise

Greg Hartman

Show of hands

Concurrency bugs suck

What's a race condition?

Multiple threads

The saddest locks

The saddest state diagram

See?

Introducing SPIN

The saddest locks, revisited

What about the actual checking?

Verifying mutual exclusion

Run it again

What went wrong?

Slightly happier mutexes

New PROMELA code

byte locked = 0;

inline mutex_lock()
{
        do
        :: 1 ->
             atomic {
               if
               :: locked == 0 -> locked = 1; break;
               :: else -> skip;
               fi
             }
        od
}

New PROMELA code 2

inline mutex_unlock()
{
        assert (locked == 1);
        locked = 0;
}

Any better?

Unbounded waiting

New monitor process

proctype fairness() {
        do
        :: 1 ->
                t0_incrit -> skip;
                t1_incrit -> skip;
progress:       skip
        od
}

[...]
        run fairness();
[...]

Is it fair?

$ spin -a happier-progress.promela
$ gcc -o pan pan.c -DNP
$ ./pan -l
pan: non-progress cycle (at depth 20)
pan: wrote happier-progress.promela.trail
[...]
State-vector 36 byte, depth reached 35, errors: 1
[...]

What went wrong? 2

$ ./pan -l -C
[...]
<<<<<START OF CYCLE>>>>>
22:                               B(3):[((locked==0))]
24:                               B(3):[break]
26:                               B(3):[t1_incrit = 1]
28:                               B(3):[t1_incrit = 0]
30:                               B(3):[assert((locked==1))]
32:                               B(3):[locked = 0]
34:                               B(3):[(1)]
36:                               B(3):[(1)]

On to Dekker

Mutual Exclusion

proctype A()
{
  f0 = 1;
  do
  :: f1 ->
    if
    :: turn != 0 ->
      f0 = 0;
      turn == 0 -> skip;
      f0 = 1;
    :: else -> skip;
    fi
  :: else -> break;
  od;

  t0_incrit = 1;
  t0_incrit = 0;

  turn = 1;
  f0 = 0;
}
proctype B()
{
  f1 = 1;
  do
  :: f0 ->
    if
    :: turn != 1 ->
      f1 = 0;
      turn == 1 -> skip;
      f1 = 1;
    :: else -> skip;
    fi
  :: else -> break;
  od;

  t1_incrit = 1;
  t1_incrit = 0;

  turn = 0;
  f1 = 0;
}

And, as we expect...

$ spin -a dekker.promela
$ gcc -o pan pan.c
$ ./pan
[...]
State-vector 32 byte, depth reached 29, errors: 0
[...]

Bounded waiting

As we expect 2

$ spin -a dekker-waiting.promela
$ gcc -o pan pan.c
$ ./pan
[...]
State-vector 40 byte, depth reached 106, errors: 0
[...]

Limitations

Summary