CS195Y Lecture 24

04/05/2015


Model Checking (1)

What are some shared resources that we use?

Now, let's think about this in the context of memory sharing and resource allocation. What might we want if two people or processes are contending for the same space.

  1. We would want mutual exclusion: if there are two people who want to access something, only one can do so at any one time. This is abbreviated to mutex. Otherwise, if there are two processes reading the same resource at the same time, we don't know what could happen --> undefined. (Safety)
  2. We would want progress, or some sense of non-starvation. E.g. if you are in class and you raise your hand, you should eventually be called on. So, if you are a process and you request access to a resource, you should be guaranteed to always eventually be able to access the resource. In the same vein, no process should be able to hog a process indefinitely. (Liveness)

What are some ways these might fail? If two processes access the same resource at the same time, the safety property fails. If three processes, A B C want a resource, there is a possibility that A and B continually exchange the process, and C never reaches the resource. Thus, an infinite livelock violates the liveness property.

So, let's try to model this hand-raising property in Spin!

We define two arrays of booleans.

bool in_crit[2]
bool flags[2]

We outline our first process:

proctype a_process():
    restart:
        code goes here
    goto restart;
}

This is essentially a while loop. Goto is the syntax in the Spin documentation, which is why it's the easiest to use here.

flags[1 - _pid] == 0;

This process would verify that the other process has its flag lowered, aka set to 0, and when it is, we can go ahead and execute the rest of the code.

flags[_pid] = 1;
in_crit[_pid] = 1;
//DO STUFF HERE
in_crit[_pid] = 0;
flags[_pid] = 0;

What is _pid? It is implicitly defined by Spin as the current process.
This is not an if statement, so how does this work? This is actually blocking the loop each time the restart loop begins. The rest of the code won't execute until that statement is true

Here we say:

  1. I want to enter the critical section by raising my flag.
  2. I enter the critical period.
  3. I do something in the critical section
  4. I leave the critical section.
  5. I say that I no longer want to enter the critical section by lowering my flag.

What do we get when we run this?
Spin instantiates process 1 and process 0. Nothing else happens. This is fine.

But, we haven't checked any properties! Let's do that.
We want to be sure that whenever a process is in the critical section, the other process is not. So, we can add this check when the process is in the critical section.

assert(!in_crit[1-_pid]);

Why might this assertion fail and result in a violation of mutual exclusion?
At the beginning, both processes start at 0. They enter the loop, and both check that their opponent's process is 0. This is true if they both enter at the same time. Then, they progress on to the next step, and they both enter the critical section at the same time.

In spin, using the -p flag when you run your program prints out the run of the program.

If it doesn't terminate, how can we be sure that our program is right?
We compile the Spin program into a C program that does an exhaustive search, and then we run that executable. This found a counterexample without having to rely on randomness.

To look at the trailfile, we can run our C program with -t to get the trace, and -p to print the trace.

What can we do? What is the problem here? Think about what the core problem here is...