.HTML "Using SPIN.\" runoff as:.\" eqn file | tbl | troff -ms.\".ds P \\s-1PROMELA\\s0.ds V \\s-1SPIN\\s0.ds C pcc.\" .tr -\(hy.EQdelim $#.EN.TLUsing \*V.AUGerard J. Holzmanngerard@plan9.bell-labs.com.AB\*V can be used for proving or disproving logical propertiesof concurrent systems.To render the proofs, a concurrent system is firstmodeled in a formal specification language called \*P.The language allows one to specify the behaviorsof asynchronously executingprocesses that may interact through synchronousor asynchronous message passing, or through directaccess to shared variables..LPSystem models specified in this way can be verifiedfor both safety and liveness properties. The specificationof general properties in linear time temporal logic isalso supported..LPThe first part of this manualdiscusses the basic features of the specification language \*P.The second part describes the verifier \*V..AE.NH 1The Language \*P.LP\*P is short for Protocol Meta Language [Ho91].\*P is a \f2modeling\f1 language, not a programming language.A formal model differs in two essential ways from an implementation.First, a model is meant to be an abstraction of a designthat contains only those aspects of the design that aredirectly relevant to the properties one is interested in proving.Second, a formal model must contain things that are typically not partof an implementation, such as worst-case assumptions aboutthe behavior of the environment that may interact with thesystem being studied, and a formal statement of relevant correctnessproperties. It is possible to mechanically extract abstract modelsfrom implementation level code, as discussed, for instance in [HS99]..LPVerification with \*V is often performed in a series of steps,with the construction of increasingly detailed models.Each model can be verified under different types ofassumptions about the environment and for differenttypes of correctness properties.If a property is not valid for the given assumptions aboutsystem behavior, the verifier can produce a counter-examplethat demonstrates how the property may be violated.If a property is valid, it may be possible to simplify themodel based on that fact, and prove still other properties..LPSection 1.1 covers the basic building blocks of the language.Section 1.2 introduces the control flow structures.Section 1.3 explains how correctness properties are specified.Section 1.4 concludes the first part with a discussion ofspecial predefined variables and functions that can be used toexpress some correctness properties..LPUp to date manual pages for \*V can always be found online at:.CWhttp://cm.bell-labs.com/cm/cs/what/spin/Man/.R.NH 2Basics.LPA \*P model can contain three different types of objects:.IP.RS\(bu Processes (section 1.1.1),.br\(bu Variables (section 1.1.2),.br\(bu Message channels (section 1.1.3)..RE.LPAll processes are global objects.For obvious reasons, a \*P model must contain at least oneprocess to be meaningful.Since \*V is specifically meant to prove properties ofconcurrent systems, a model typically contains more thanone process..LPMessage channels and variables, the two basic types of data objects,can be declared with either a global scope or a local scope.A data object with global scope can be referred to by all processes.A data object with a local scope can be referred to by just asingle process: the process that declares and instantiates the object.As usual, all objects must be declared in the specificationbefore they are referenced..NH 3Processes.LPHere is a simple process that does nothing except printa line of text:.P1init { printf("it works\en")}.P2There are a few things to note..CW Initis a predefined keyword from the language.It can be used to declare and instantiatea single initial process in the model.(It is comparable to the.CW mainprocedure of a C program.)The.CW initprocess does not take arguments, but it canstart up (instantiate) other processes that do..CW Printfis one of a few built-in procedures in the language.It behaves the same as the C version.Note, finally, that no semicolon follows the single.CW printfstatement in the above example.In \*P, semicolons are used as statement separators,not statement terminators. (The \*V parser, however, islenient on this issue.).LPAny process can start new processes by using anotherbuilt-in procedure called.CW run .For example,.P1proctype you_run(byte x){ printf("my x is: %d\en", x)}.P2.P1init { run you_run(1); run you_run(2)}.P2The word.CW proctypeis again a keyword that introduces the declarationof a new type of process.In this case, we have named that type.CW you_runand declared that all instantiations of processesof this type will take one argument: a data objectof type.CW byte ,that can be referred to within this process by the name.CW x .Instances of a.CW proctypecan be created with the predefined procedure.CW run ,as shown in the example.When the.CW runstatement completes, a copy of the processhas been started, and all its arguments have beeninitialized with the arguments provided.The process may, but need not, have performedany statement executions at this point.It is now part of the concurrent system,and its execution can be interleaved arbitrarily withthose of the other, already executing processes.(More about the semantics of execution follows shortly.).LPIn many cases, we are only interested in creating asingle instance of each process type that is declared,and the processes require no arguments.We can define this by prefixing the keyword.CW proctypefrom the process declaration with another keyword:.CW active .Instances of all active proctypes are created when thesystem itself is initialized.We could, for instance, have avoided the use of.CW initby declaring the corresponding process in the last exampleas follows:.P1active proctype main() { run you_run(1); run you_run(2)}.P2Note that there are no parameters to instantiate in thiscase. Had they been declared, they would default to azero value, just like all other data objectsthat are not explicitly instantiated..LPMultiple copies of a process type can also be created inthis way. For example:.P1active [4] proctype try_me() { printf("hi, i am process %d\en", _pid)}.P2creates four processes.A predefined variable.CW _pidis assigned to each running process, and holdsits unique process instantiation number.In some cases, this number is needed when a referencehas to be made to a specific process..LPSummarizing: process behavior is declared in.CW proctypedefinitions, and it is instantiated with either.CW runstatements or with the prefix.CW active .Within a proctype declaration, statements are separated(not terminated) by semicolons.As we shall see in examples that follow, instead of thesemicolon, one can also use the alternative separator.CW "->"(arrow), wherever that may help to clarify the structureof a \*P model..SHSemantics of Execution.LPIn \*P there is no difference between a condition orexpression and a statement.Fundamental to the semantics of the language is thenotion of the \f2executability\f1 of statements.Statements are either executable or blocked.Executability is the basic means of enforcingsynchronization between the processes in a distributed system.A process can wait for an event to happen by waitingfor a statement to become executable.For instance, instead of writing a busy wait loop:.P1while (a != b) /* not valid Promela syntax */ skip; /* wait for a==b */\&....P2we achieve the same effect in \*P with the statement.P1(a == b);\&....P2Often we indicate that the continuation of an executionis conditional on the truth of some expression by usingthe alternate statement separator:.P1(a == b) -> \&....P2Assignments and.CW printfstatements are always executable in \*P.A condition, however, can only be executed (passed) when it holds.If the condition does not hold, execution blocks until it does.There are similar rules for determining the executabilityof all other primitive and compound statements in thelanguage.The semantics of each statement is defined in terms ofrules for executability and effect.The rules for executability set a precondition on the stateof the system in which a statement can be executed.The effect defines how a statement will alter asystem state when executed..LP\*P assumes that all individual statements are executedatomically: that is, they model the smallest meaningful entitiesof execution in the system being studied.This means that \*P defines the standard asynchronous interleavingmodel of execution, where a supposed scheduler is free ateach point in the execution to select any one of the processesto proceed by executing a single primitive statement.Synchronization constraints can be used to influence theinterleaving patterns. It is the purpose of a concurrent system'sdesign to constrain those patterns in such a way that nocorrectness requirements can be violated, and all servicerequirements are met. It is the purpose of the verifiereither to find counter-examples to a designer's claim that thisgoal has been met, or to demonstrate that the claim is indeed valid..NH 3Variables.LPThe table summarizes the five basic data types used in \*P..CW Bitand.CW boolare synonyms for a single bit of information.The first three types can store only unsigned quantities.The last two can hold either positive or negative values.The precise value ranges of variables of types.CW shortand.CW intis implementation dependent, and correspondsto those of the same types in C programsthat are compiled for the same hardware.The values given in the table are most common..KS.TScenter;l llw(10) lw(12).=\f3Type Range\f1_bit 0..1bool 0..1byte 0..255short $-2 sup 15# .. $2 sup 15 -1#int $-2 sup 31# .. $2 sup 31 -1#_.TE.KE.LPThe following example program declares a array oftwo elements of type.CW booland a scalar variable.CW turnof the same type.Note that the example relies on the fact that.CW _pidis either 0 or 1 here..MT _sec5critical.P1/* * Peterson's algorithm for enforcing * mutual exclusion between two processes * competing for access to a critical section */bool turn, want[2]; active [2] proctype user(){again: want[_pid] = 1; turn = _pid; /* wait until this condition holds: */ (want[1 - _pid] == 0 || turn == 1 - _pid); /* enter */critical: skip; /* leave */ want[_pid] = 0; goto again}.P2In the above case, all variables are initialized to zero.The general syntax for declaring and instantiating avariable, respectively for scalar and array variables, is:.P1type name = expression;type name[constant] = expression.P2In the latter case, all elements of the array are initializedto the value of the expression.A missing initializer fields defaults to the value zero.As usual, multiple variables of the same type can be groupedbehind a single type name, as in:.P1byte a, b[3], c = 4.P2In this example, the variable.CW cis initialized to the value 4; variable.CW aand the elements of array.CW bare all initialized to zero..LPVariables can also be declared as structures.For example:.P1typedef Field { short f = 3; byte g}; typedef Msg { byte a[3]; int fld1; Field fld2; chan p[3]; bit b}; Msg foo;.P2introduces two user-defined data types, the first named.CW Fieldand the second named.CW Msg .A single variable named.CW fooof type.CW Msgis declared.All fields of.CW foothat are not explicitly initialized (in the example, all fields except.CW foo.fld2.f )are initialized to zero.References to the elements of a structure are written as:.P1foo.a[2] = foo.fld2.f + 12.P2A variable of a user-defined type can be passed as a singleargument to a new process in.CW runstatements.For instance,.P1proctype me(Msg z) { z.a[2] = 12}init { Msg foo; run me(foo)}.P2.LPNote that even though \*P supports only one-dimensional arrays,a two-dimensional array can be created indirectly with user-definedstructures, for instance as follows:.P1typedef Array { byte el[4]}; Array a[4];.P2This creates a data structure of 16 elements that can bereferenced, for instance, as.CW a[i].el[j] ..LPAs in C, the indices of an array of.CW Nelements range from 0 to.CW N-1 ..SHExpressions.LPExpressions must be side-effect free in \*P.Specifically, this means that an expression cannotcontain assignments, or send and receive operations (see section 1.1.3)..P1c = c + 1; c = c - 1.P2and.P1c++; c--.P2are assignments in \*P, with the same effects.But, unlike in C,.P1b = c++.P2is not a valid assignment, because the right-hand sideoperand is not a valid expression in \*P (it is not side-effect free)..LPIt is also possible to write a side-effect free conditionalexpression, with the following syntax:.P1(expr1 -> expr2 : expr3).P2The parentheses around the conditional expression are required toavoid misinterpretation of the arrow.The example expression has the value of \f(CWexpr2\f1 when \f(CWexpr1\f1evaluates to a non-zero value, and the value of \f(CWexpr3\f1 otherwise..LPIn assignments like.P1variable = expression.P2the values of all operands used inside the expression are first cast tosigned integers before the operands are applied.After the evaluation of the expression completes, the value producedis cast to the type of the target variable before the assignment takes place..NH 3Message Channels.LPMessage channels are used to model the transfer of databetween processes.They are declared either locally or globally,for instance as follows:.P1chan qname = [16] of { short, byte }.P2The keyword.CW chanLines 1–500 of 2519. Load more
.HTML "Using SPIN .\" runoff as: .\" eqn file | tbl | troff -ms .\" .ds P \\s-1PROMELA\\s0 .ds V \\s-1SPIN\\s0 .ds C pcc .\" .tr -\(hy .EQ delim $# .EN .TL Using \*V .AU Gerard J. Holzmann gerard@plan9.bell-labs.com .AB \*V can be used for proving or disproving logical properties of concurrent systems. To render the proofs, a concurrent system is first modeled in a formal specification language called \*P. The language allows one to specify the behaviors of asynchronously executing processes that may interact through synchronous or asynchronous message passing, or through direct access to shared variables. .LP System models specified in this way can be verified for both safety and liveness properties. The specification of general properties in linear time temporal logic is also supported. .LP The first part of this manual discusses the basic features of the specification language \*P. The second part describes the verifier \*V. .AE .NH 1 The Language \*P .LP \*P is short for Protocol Meta Language [Ho91]. \*P is a \f2modeling\f1 language, not a programming language. A formal model differs in two essential ways from an implementation. First, a model is meant to be an abstraction of a design that contains only those aspects of the design that are directly relevant to the properties one is interested in proving. Second, a formal model must contain things that are typically not part of an implementation, such as worst-case assumptions about the behavior of the environment that may interact with the system being studied, and a formal statement of relevant correctness properties. It is possible to mechanically extract abstract models from implementation level code, as discussed, for instance in [HS99]. .LP Verification with \*V is often performed in a series of steps, with the construction of increasingly detailed models. Each model can be verified under different types of assumptions about the environment and for different types of correctness properties. If a property is not valid for the given assumptions about system behavior, the verifier can produce a counter-example that demonstrates how the property may be violated. If a property is valid, it may be possible to simplify the model based on that fact, and prove still other properties. .LP Section 1.1 covers the basic building blocks of the language. Section 1.2 introduces the control flow structures. Section 1.3 explains how correctness properties are specified. Section 1.4 concludes the first part with a discussion of special predefined variables and functions that can be used to express some correctness properties. .LP Up to date manual pages for \*V can always be found online at: .CW http://cm.bell-labs.com/cm/cs/what/spin/Man/ .R .NH 2 Basics .LP A \*P model can contain three different types of objects: .IP .RS \(bu Processes (section 1.1.1), .br \(bu Variables (section 1.1.2), .br \(bu Message channels (section 1.1.3). .RE .LP All processes are global objects. For obvious reasons, a \*P model must contain at least one process to be meaningful. Since \*V is specifically meant to prove properties of concurrent systems, a model typically contains more than one process. .LP Message channels and variables, the two basic types of data objects, can be declared with either a global scope or a local scope. A data object with global scope can be referred to by all processes. A data object with a local scope can be referred to by just a single process: the process that declares and instantiates the object. As usual, all objects must be declared in the specification before they are referenced. .NH 3 Processes .LP Here is a simple process that does nothing except print a line of text: .P1 init { printf("it works\en") } .P2 There are a few things to note. .CW Init is a predefined keyword from the language. It can be used to declare and instantiate a single initial process in the model. (It is comparable to the .CW main procedure of a C program.) The .CW init process does not take arguments, but it can start up (instantiate) other processes that do. .CW Printf is one of a few built-in procedures in the language. It behaves the same as the C version. Note, finally, that no semicolon follows the single .CW printf statement in the above example. In \*P, semicolons are used as statement separators, not statement terminators. (The \*V parser, however, is lenient on this issue.) .LP Any process can start new processes by using another built-in procedure called .CW run . For example, .P1 proctype you_run(byte x) { printf("my x is: %d\en", x) } .P2 .P1 init { run you_run(1); run you_run(2) } .P2 The word .CW proctype is again a keyword that introduces the declaration of a new type of process. In this case, we have named that type .CW you_run and declared that all instantiations of processes of this type will take one argument: a data object of type .CW byte , that can be referred to within this process by the name .CW x . Instances of a .CW proctype can be created with the predefined procedure .CW run , as shown in the example. When the .CW run statement completes, a copy of the process has been started, and all its arguments have been initialized with the arguments provided. The process may, but need not, have performed any statement executions at this point. It is now part of the concurrent system, and its execution can be interleaved arbitrarily with those of the other, already executing processes. (More about the semantics of execution follows shortly.) .LP In many cases, we are only interested in creating a single instance of each process type that is declared, and the processes require no arguments. We can define this by prefixing the keyword .CW proctype from the process declaration with another keyword: .CW active . Instances of all active proctypes are created when the system itself is initialized. We could, for instance, have avoided the use of .CW init by declaring the corresponding process in the last example as follows: .P1 active proctype main() { run you_run(1); run you_run(2) } .P2 Note that there are no parameters to instantiate in this case. Had they been declared, they would default to a zero value, just like all other data objects that are not explicitly instantiated. .LP Multiple copies of a process type can also be created in this way. For example: .P1 active [4] proctype try_me() { printf("hi, i am process %d\en", _pid) } .P2 creates four processes. A predefined variable .CW _pid is assigned to each running process, and holds its unique process instantiation number. In some cases, this number is needed when a reference has to be made to a specific process. .LP Summarizing: process behavior is declared in .CW proctype definitions, and it is instantiated with either .CW run statements or with the prefix .CW active . Within a proctype declaration, statements are separated (not terminated) by semicolons. As we shall see in examples that follow, instead of the semicolon, one can also use the alternative separator .CW "->" (arrow), wherever that may help to clarify the structure of a \*P model. .SH Semantics of Execution .LP In \*P there is no difference between a condition or expression and a statement. Fundamental to the semantics of the language is the notion of the \f2executability\f1 of statements. Statements are either executable or blocked. Executability is the basic means of enforcing synchronization between the processes in a distributed system. A process can wait for an event to happen by waiting for a statement to become executable. For instance, instead of writing a busy wait loop: .P1 while (a != b) /* not valid Promela syntax */ skip; /* wait for a==b */ \&... .P2 we achieve the same effect in \*P with the statement .P1 (a == b); \&... .P2 Often we indicate that the continuation of an execution is conditional on the truth of some expression by using the alternate statement separator: .P1 (a == b) -> \&... .P2 Assignments and .CW printf statements are always executable in \*P. A condition, however, can only be executed (passed) when it holds. If the condition does not hold, execution blocks until it does. There are similar rules for determining the executability of all other primitive and compound statements in the language. The semantics of each statement is defined in terms of rules for executability and effect. The rules for executability set a precondition on the state of the system in which a statement can be executed. The effect defines how a statement will alter a system state when executed. .LP \*P assumes that all individual statements are executed atomically: that is, they model the smallest meaningful entities of execution in the system being studied. This means that \*P defines the standard asynchronous interleaving model of execution, where a supposed scheduler is free at each point in the execution to select any one of the processes to proceed by executing a single primitive statement. Synchronization constraints can be used to influence the interleaving patterns. It is the purpose of a concurrent system's design to constrain those patterns in such a way that no correctness requirements can be violated, and all service requirements are met. It is the purpose of the verifier either to find counter-examples to a designer's claim that this goal has been met, or to demonstrate that the claim is indeed valid. .NH 3 Variables .LP The table summarizes the five basic data types used in \*P. .CW Bit and .CW bool are synonyms for a single bit of information. The first three types can store only unsigned quantities. The last two can hold either positive or negative values. The precise value ranges of variables of types .CW short and .CW int is implementation dependent, and corresponds to those of the same types in C programs that are compiled for the same hardware. The values given in the table are most common. .KS .TS center; l l lw(10) lw(12). = \f3Type Range\f1 _ bit 0..1 bool 0..1 byte 0..255 short $-2 sup 15# .. $2 sup 15 -1# int $-2 sup 31# .. $2 sup 31 -1# _ .TE .KE .LP The following example program declares a array of two elements of type .CW bool and a scalar variable .CW turn of the same type. Note that the example relies on the fact that .CW _pid is either 0 or 1 here. .MT _sec5critical .P1 /* * Peterson's algorithm for enforcing * mutual exclusion between two processes * competing for access to a critical section */ bool turn, want[2]; active [2] proctype user() { again: want[_pid] = 1; turn = _pid; /* wait until this condition holds: */ (want[1 - _pid] == 0 || turn == 1 - _pid); /* enter */ critical: skip; /* leave */ want[_pid] = 0; goto again } .P2 In the above case, all variables are initialized to zero. The general syntax for declaring and instantiating a variable, respectively for scalar and array variables, is: .P1 type name = expression; type name[constant] = expression .P2 In the latter case, all elements of the array are initialized to the value of the expression. A missing initializer fields defaults to the value zero. As usual, multiple variables of the same type can be grouped behind a single type name, as in: .P1 byte a, b[3], c = 4 .P2 In this example, the variable .CW c is initialized to the value 4; variable .CW a and the elements of array .CW b are all initialized to zero. .LP Variables can also be declared as structures. For example: .P1 typedef Field { short f = 3; byte g }; typedef Msg { byte a[3]; int fld1; Field fld2; chan p[3]; bit b }; Msg foo; .P2 introduces two user-defined data types, the first named .CW Field and the second named .CW Msg . A single variable named .CW foo of type .CW Msg is declared. All fields of .CW foo that are not explicitly initialized (in the example, all fields except .CW foo.fld2.f ) are initialized to zero. References to the elements of a structure are written as: .P1 foo.a[2] = foo.fld2.f + 12 .P2 A variable of a user-defined type can be passed as a single argument to a new process in .CW run statements. For instance, .P1 proctype me(Msg z) { z.a[2] = 12 } init { Msg foo; run me(foo) } .P2 .LP Note that even though \*P supports only one-dimensional arrays, a two-dimensional array can be created indirectly with user-defined structures, for instance as follows: .P1 typedef Array { byte el[4] }; Array a[4]; .P2 This creates a data structure of 16 elements that can be referenced, for instance, as .CW a[i].el[j] . .LP As in C, the indices of an array of .CW N elements range from 0 to .CW N-1 . .SH Expressions .LP Expressions must be side-effect free in \*P. Specifically, this means that an expression cannot contain assignments, or send and receive operations (see section 1.1.3). .P1 c = c + 1; c = c - 1 .P2 and .P1 c++; c-- .P2 are assignments in \*P, with the same effects. But, unlike in C, .P1 b = c++ .P2 is not a valid assignment, because the right-hand side operand is not a valid expression in \*P (it is not side-effect free). .LP It is also possible to write a side-effect free conditional expression, with the following syntax: .P1 (expr1 -> expr2 : expr3) .P2 The parentheses around the conditional expression are required to avoid misinterpretation of the arrow. The example expression has the value of \f(CWexpr2\f1 when \f(CWexpr1\f1 evaluates to a non-zero value, and the value of \f(CWexpr3\f1 otherwise. .LP In assignments like .P1 variable = expression .P2 the values of all operands used inside the expression are first cast to signed integers before the operands are applied. After the evaluation of the expression completes, the value produced is cast to the type of the target variable before the assignment takes place. .NH 3 Message Channels .LP Message channels are used to model the transfer of data between processes. They are declared either locally or globally, for instance as follows: .P1 chan qname = [16] of { short, byte } .P2 The keyword .CW chan