150 likes | 163 Views
CSE 503 – Software Engineering Lecture 5: An introduction to the Spin model checker Rob DeLine 12 Apr 2004. Exploring state. Using Alloy to explore state Model system state using sets and relations Define state changing operations declaratively as functions
E N D
CSE 503 – Software Engineering • Lecture 5: An introduction to the Spin model checker • Rob DeLine • 12 Apr 2004
Exploring state • Using Alloy to explore state • Model system state using sets and relations • Define state changing operations declaratively as functions • Use asserts to test properties of particular operation sequences • Alloy tries to find states that break asserts • Using Promela (language)/Spin (tool) to explore state • Model system using processes with local variables and channels • Define state changing operations imperatively as algorithms • Use temporal logic formulae/asserts to specify states that we want/don’t want the system to reach • Spin tries to find operation sequences that break formulae/asserts • Today: Promela syntax and semantics, use of Spin • Wed: Case studies
Promela data types • Basic types (integers of various widths) • bit, bool 1-bit, unsigned • byte 8-bit, unsigned • short 16-bit, signed • int 32-bit, signed • Arrays (index starts at zero) • bit[8] • Records • typedef Header { bit flag0, flag1; byte dest; } • Enumerated types (underlying type is byte) • mtype = { ack, nack }
Variable declarations and assignments • Variable declarations • int x; // basic types initialize to zero by default • byte b = 123; • byte[3] array; • byte[3] initArray = 1; // all elements initialized to 1 • Header h; // apparently, no initializer allowed • byte msgtype = ack; // mtypes are just bytes • Assignment has C’s syntax • x = 3; • array[2] = y;
Expressions • Promela has many expressions from C • Arithmetic: a+b, a-b, a*b, a/b, a%b • Comparisons: a==b, a!=b, a<b, a<=b, a>b, a>=b • Logicals: a&&b, a||b,! a • Bit-level: a&b, a|b, a^b, ~a, a<<b, a>>b • Side-effecting: a++, a-- (postfix only) • Plus other Promela-specific expressions (more later)
Process declarations • Promela program consists of one or more processes • Program begins with distinguished process “init” (no parameters) • Start a process with “run” command, which returns a process id • A process is defined with “proctype” • proctype Hello () { printf(“hi\n”); } • init { run Hello(); } • Process != procedure • No return value, no call stack • if A “runs” B, then A and B execute concurrently • However, process cannot end until all processes that it runs end
Control statements • Conditionals (execute any branch whose condition is true) • if • :: condition0 -> statements0 • :: conditionn -> statementsn • fi • Loops • do • :: condition0 -> statements0 • :: conditionn -> statementsn • od • Unconditional jumps: break (leave nearest do); goto label • assert(cond) means crash if cond isn’t true
Executability • Expressions as statements • Like C, an expression can be used as a statement • Unlike C, an expression statement is blocked until it is true • This is useful for making a process wait for a condition • Conditionals and loops revisted • General forms • if :: statements0 :: ... :: statementsn fi • do :: statements0 :: ... :: statementsn od • S -> T is equivalent to S; T • if/do nondeterministically choose any executable statement • Timeout • Special statement “timeout” is executable iff every process is blocked at a non-executable statement
What does this print? • int i = 0; • proctype A () { • do • :: i == 10 -> break; • :: i % 2 == 0 -> printf(“%d\n”, i); i++; • :: i % 2 == 1 -> i++; • od • } • init { run A(); } • Two answers • 0, 2, 4, 6, 8 • all even naturals
Concurrency • Processes run concurrently • Execution is interleaved on the statement level • You can force multiple statements to be interleaved as one • atomic { statements } • Two forms of interaction between processes • Global variables • Shared communication channels
Producer/consumer using globals • int buffer[10]; • int i = 0; • proctype Consumer () { • int x; • do :: i > 0 -> i--; x = buffer[i]; od • } • proctype Producer () { • int item; • do :: i < 10 -> buffer[i] = item; item++; i++; od • } • init { run Consumer(); run Producer(); } • Can any items get lost?
Oops! Race condition! • initialProducer: buffer[i] = item;Producer: i++;Producer: buffer[i] = item;Producer: i++;Consumer: i--;Consumer: x = buffer[i];Producer: buffer[i] = item;Consumer: i--;Consumer: x = buffer[i];Producer: i++;Producer: buffer[i] = item; 0 0 0 1 0 1 0 1 0 1 0 2 0 0 0 2 0 3
Repaired producer/consumer • int buffer[10]; • int i = 0; • proctype Consumer () { • int x; • do :: i > 0 -> atomic { i--; x = buffer[i]; Use(x); } od • } • proctype Producer () { • int item; • do :: i < 10 -> atomic { buffer[i] = item; item++; i++; } od • } • init { run Consumer(); run Producer(); }
Interaction using channels • A channel is a fixed-size buffer for communication • Channels are named and contain typed data • chan name = [size] of { type0, ..., typen } • Process can read channel data, which blocks when channel empty • name?var0,...,varn • Process can write channel data, which blocks when channel full • name!expr0,...,exprn • Channels can be global or local • Channels can be passed as process parameters
Producer/consumer with channels • chan buffer = [10] of {int} • proctype Consumer () { • int x; • do :: buffer?x -> Use(x); od • } • proctype Producer () { • int item; • do :: buffer!item -> item++; od • } • init { run Consumer(); run Producer(); } • Let’s see Spin in action!