Promela

Last updated

PROMELA (Process or Protocol Meta Language) is a verification modeling language introduced by Gerard J. Holzmann. The language allows for the dynamic creation of concurrent processes to model, for example, distributed systems. In PROMELA models, communication via message channels can be defined to be synchronous (i.e., rendezvous), or asynchronous (i.e., buffered). PROMELA models can be analyzed with the SPIN model checker, to verify that the modeled system produces the desired behavior. An implementation verified with Isabelle/HOL is also available, as part of the Computer Aided Verification of Automata (CAVA) project. [1] [2] Files written in Promela traditionally have a .pml file extension.

Contents

Introduction

PROMELA is a process-modeling language whose intended use is to verify the logic of parallel systems. Given a program in PROMELA, Spin can verify the model for correctness by performing random or iterative simulations of the modeled system's execution, or it can generate a C program that performs a fast exhaustive verification of the system state space. During simulations and verifications, SPIN checks for the absence of deadlocks, unspecified receptions, and unexecutable code. The verifier can also be used to prove the correctness of system invariants and it can find non-progress execution cycles. Finally, it supports the verification of linear time temporal constraints; either with Promela never-claims or by directly formulating the constraints in temporal logic. Each model can be verified with SPIN under different types of assumptions about the environment. Once the correctness of a model has been established with SPIN, that fact can be used in the construction and verification of all subsequent models.

PROMELA programs consist of processes,message channels, and variables. Processes are global objects that represent the concurrent entities of the distributed system. Message channels and variables can be declared either globally or locally within a process. Processes specify behavior, channels and global variables define the environment in which the processes run.

Language reference

Data types

The basic data types used in PROMELA are presented in the table below. The sizes in bits are given for a PC i386/Linux machine.

NameSize (bits)UsageRange
bit1unsigned0..1
bool1unsigned0..1
byte8unsigned0..255
mtype8unsigned0..255
short16signed−215..215 − 1
int32signed−231..231 − 1

The names bit and bool are synonyms for a single bit of information. A byte is an unsigned quantity that can store a value between 0 and 255. shorts and ints are signed quantities that differ only in the range of values they can hold.

Variables can also be declared as arrays. For example, the declaration:

intx[10];

declares an array of 10 integers that can be accessed in array subscript expressions like:

x[0] = x[1] + x[2];

But the arrays can not be enumerated on creation, so they must be initialised as follows:

<nowiki/>intx[3];x[0]=1;x[1]=2;x[2]=3;

The index to an array can be any expression that determines a unique integer value. The effect of an index outside the range is undefined. Multi-dimensional arrays can be defined indirectly with the help of the typedef construct (see below).

Processes

The state of a variable or of a message channel can only be changed or inspected by processes. The behavior of a process is defined by a proctype declaration. For example, the following declares a process type A with one variable state:

<nowiki/>  proctype A()  {      byte state;      state = 3;  }

The proctype definition only declares process behavior, it does not execute it. Initially, in the PROMELA model, just one process will be executed: a process of type init, that must be declared explicitly in every PROMELA specification.

New processes can be spawned using the run statement, which takes an argument consisting of the name of a proctype, from which a process is then instantiated. The run operator can be used in the body of the proctype definitions, not only in the initial process. This allows for dynamic creation of processes in PROMELA.

An executing process disappears when it terminates—that is, when it reaches the end of the body in the proctype definition, and all child processes that it started have terminated.

A proctype may also be active (below).

Atomic construct

By prefixing a sequence of statements enclosed in curly braces with the keyword atomic, the user can indicate that the sequence is to be executed as one indivisible unit, non-interleaved with any other processes.

<nowiki/>  atomic  {      statements;  }

Atomic sequences can be an important tool in reducing the complexity of verification models. Note that atomic sequences restrict the amount of interleaving that is allowed in a distributed system. Intractable models can be made tractable by labeling all manipulations of local variables with atomic sequences.

Message passing

Message channels are used to model the transfer of data from one process to another. They are declared either locally or globally, for instance as follows:

chan qname = [16] of {short}

This declares a buffered channel that can store up to 16 messages of type short (capacity is 16 here).

The statement:

qname ! expr;

sends the value of the expression expr to the channel with name qname, that is, it appends the value to the tail of the channel.

The statement:

qname ? msg;

receives the message, retrieves it from the head of the channel, and stores it in the variable msg. The channels pass messages in first-in-first-out order.

A rendezvous port can be declared as a message channel with the store length zero. For example, the following:

chan port = [0] of {byte}

defines a rendezvous port that can pass messages of type byte. Message interactions via such rendezvous ports are by definition synchronous, i.e. sender or receiver (the one that arrives first at the channel) will block for the contender that arrives second (receiver or sender).

When a buffered channel has been filled to its capacity (sending is "capacity" number of outputs ahead of receiving inputs), the default behavior of the channel is to become synchronous, and the sender will block on the next sending. Observe that there is no common message buffer shared between channels. Increasing complexity, as compared to using a channel as unidirectional and point to point, it is possible to share channels between multiple receivers or multiple senders, and to merge independent data-streams into a single shared channel. From this follows that a single channel may also be used for bidirectional communication.

Control flow constructs

There are three control flow constructs in PROMELA. They are the case selection, the repetition and the unconditional jump.

Case selection

The simplest construct is the selection structure. Using the relative values of two variables a and b, for example, one can write:

<nowiki/>  if  :: (a != b) -> option1  :: (a == b) -> option2  fi

The selection structure contains two execution sequences, each preceded by a double colon. One sequence from the list will be executed. A sequence can be selected only if its first statement is executable. The first statement of a control sequence is called a guard.

In the example above, the guards are mutually exclusive, but they need not be. If more than one guard is executable, one of the corresponding sequences is selected non-deterministically. If all guards are unexecutable, the process will block until one of them can be selected. (Opposite, the occam programming language would stop or not be able to proceed on no executable guards.)

<nowiki/>  if  :: (A == true) -> option1;  :: (B == true) -> option2; /* May arrive here also if A==true */  :: else -> fallthrough_option;  fi

The consequence of the non-deterministic choice is that, in the example above, if A is true, both choices may be taken. In "traditional" programming, one would understand an if – if – else structure sequentially. Here, the if – double colon – double colon must be understood as "any one being ready" and if none is ready, only then would the else be taken.

<nowiki/>  if  :: value = 3;  :: value = 4;  fi

In the example above, value is non-deterministically given the value 3 or 4.

There are two pseudo-statements that can be used as guards: the timeout statement and the else statement. The timeout statement models a special condition that allows a process to abort the waiting for a condition that may never become true. The else statement can be used as the initial statement of the last option sequence in a selection or iteration statement. The else is only executable if all other options in the same selection are not executable. Also, the else may not be used together with channels.

Repetition (loop)

A logical extension of the selection structure is the repetition structure. For example:

<nowiki/>  do  :: count = count + 1  :: a = b + 2  :: (count == 0) -> break  od

describes a repetition structure in PROMELA. Only one option can be selected at a time. After the option completes, the execution of the structure is repeated. The normal way to terminate the repetition structure is with a break statement. It transfers the control to the instruction that immediately follows the repetition structure.

Unconditional jumps

Another way to break a loop is the goto statement. For example, one can modify the example above as follows:

<nowiki/>  do  :: count = count + 1  :: a = b + 2  :: (count == 0) -> goto done  od  done:  skip;

The goto in this example jumps to a label named done. A label can only appear before a statement. To jump at the end of the program, for example, a dummy statement skip is useful: it is a place-holder that is always executable and has no effect.

Assertions

An important language construct in PROMELA that needs a little explanation is the assert statement. Statements of the form:

assert(any_boolean_condition)

are always executable. If a boolean condition specified holds, the statement has no effect. If, however, the condition does not necessarily hold, the statement will produce an error during verifications with SPIN.

Complex data structures

A PROMELA typedef definition can be used to introduce a new name for a list of data objects of predefined or earlier defined types. The new type name can be used to declare and instantiate new data objects, which can be used in any context in an obvious way:

<nowiki/>typedefMyStruct{shortField1;byteField2;};

The access to the fields declared in a typedef construction is done in the same manner as in C programming language. For example:

MyStruct x; x.Field1 = 1;

is a valid PROMELA sequence that assigns to the field Field1 of the variable x the value 1.

Active proctypes

The active keyword can be prefixed to any proctype definition. If the keyword is present, an instance of that proctype will be active in the initial system state. Multiple instantiations of that proctype can be specified with an optional array suffix of the keyword. Example:

<nowiki/>  active proctype A() { ... }  active [4] proctype B() { ... }

Executability

The semantics of executability provides the basic means in Promela for modeling process synchronizations.

<nowiki/>  mtype = {M_UP, M_DW};  chan Chan_data_down = [0] of {mtype};  chan Chan_data_up   = [0] of {mtype};  proctype P1 (chan Chan_data_in, Chan_data_out)  {      do      ::  Chan_data_in  ? M_UP -> skip;      ::  Chan_data_out ! M_DW -> skip;      od;  };  proctype P2 (chan Chan_data_in, Chan_data_out)  {      do      ::  Chan_data_in  ? M_DW -> skip;      ::  Chan_data_out ! M_UP -> skip;      od;  };  init  {      atomic      {          run P1 (Chan_data_up, Chan_data_down);          run P2 (Chan_data_down, Chan_data_up);      }  }

In the example, the two processes P1 and P2 have non-deterministic choices of (1) input from the other or (2) output to the other. Two rendezvous handshakes are possible, or executable, and one of them is chosen. This repeats forever. Therefore, this model will not deadlock.

When Spin analyzes a model like the above, it will verify the choices with a non-deterministic algorithm, where all executable choices will be explored. However, when Spin's simulator visualizes possible non-verified communication patterns, it may use a random generator to resolve the "non-deterministic" choice. Therefore, the simulator may fail to show a bad execution (in the example, there is no bad trail). This illustrates a difference between verification and simulation. In addition, it is also possible to generate executable code from Promela models using Refinement. [3]

Keywords

The following identifiers are reserved for use as keywords.

  • active
  • assert
  • atomic
  • bit
  • bool
  • break
  • byte
  • chan
  • d_step
  • D_proctype
  • do
  • else
  • empty
  • enabled
  • fi
  • full
  • goto
  • hidden
  • if
  • inline
  • init
  • int
  • len
  • mtype
  • empty
  • never
  • nfull
  • od
  • of
  • pc_value
  • printf
  • priority
  • prototype
  • provided
  • run
  • short
  • skip
  • timeout
  • typedef
  • unless
  • unsigned
  • xr
  • xs

Related Research Articles

C is a general-purpose computer programming language. It was created in the 1970s by Dennis Ritchie, and remains very widely used and influential. By design, C's features cleanly reflect the capabilities of the targeted CPUs. It has found lasting use in operating systems, device drivers, and protocol stacks, but its use in application software has been decreasing. C is commonly used on computer architectures that range from the largest supercomputers to the smallest microcontrollers and embedded systems.

Verilog, standardized as IEEE 1364, is a hardware description language (HDL) used to model electronic systems. It is most commonly used in the design and verification of digital circuits at the register-transfer level of abstraction. It is also used in the verification of analog circuits and mixed-signal circuits, as well as in the design of genetic circuits. In 2009, the Verilog standard was merged into the SystemVerilog standard, creating IEEE Standard 1800-2009. Since then, Verilog is officially part of the SystemVerilog language. The current version is IEEE standard 1800-2017.

Abstract Syntax Notation One (ASN.1) is a standard interface description language (IDL) for defining data structures that can be serialized and deserialized in a cross-platform way. It is broadly used in telecommunications and computer networking, and especially in cryptography.

In computer science, self-modifying code is code that alters its own instructions while it is executing – usually to reduce the instruction path length and improve performance or simply to reduce otherwise repetitively similar code, thus simplifying maintenance. The term is usually only applied to code where the self-modification is intentional, not in situations where code accidentally modifies itself due to an error such as a buffer overflow.

<span class="mw-page-title-main">C syntax</span> Set of rules defining correctly structured programs

The syntax of the C programming language is the set of rules governing writing of software in C. It is designed to allow for programs that are extremely terse, have a close relationship with the resulting object code, and yet provide relatively high-level data abstraction. C was the first widely successful high-level language for portable operating-system development.

<span class="mw-page-title-main">Pointer (computer programming)</span> Object which stores memory addresses in a computer program

In computer science, a pointer is an object in many programming languages that stores a memory address. This can be that of another value located in computer memory, or in some cases, that of memory-mapped computer hardware. A pointer references a location in memory, and obtaining the value stored at that location is known as dereferencing the pointer. As an analogy, a page number in a book's index could be considered a pointer to the corresponding page; dereferencing such a pointer would be done by flipping to the page with the given page number and reading the text found on that page. The actual format and content of a pointer variable is dependent on the underlying computer architecture.

<span class="mw-page-title-main">Conditional (computer programming)</span> Control flow statement that executes code according to some condition(s)

In computer science, conditionals are programming language commands for handling decisions. Specifically, conditionals perform different computations or actions depending on whether a programmer-defined Boolean condition evaluates to true or false. In terms of control flow, the decision is always achieved by selectively altering the control flow based on some condition . Although dynamic dispatch is not usually classified as a conditional construct, it is another way to select between alternatives at runtime. Conditional statements are the checkpoints in the programe that determines behaviour according to situation.

The Guarded Command Language (GCL) is a programming language defined by Edsger Dijkstra for predicate transformer semantics in EWD472. It combines programming concepts in a compact way. It makes it easier to develop a program and its proof hand-in-hand, with the proof ideas leading the way; moreover, parts of a program can actually be calculated.

Loop unrolling, also known as loop unwinding, is a loop transformation technique that attempts to optimize a program's execution speed at the expense of its binary size, which is an approach known as space–time tradeoff. The transformation can be undertaken manually by the programmer or by an optimizing compiler. On modern processors, loop unrolling is often counterproductive, as the increased code size can cause more cache misses; cf. Duff's device.

The computer programming languages C and Pascal have similar times of origin, influences, and purposes. Both were used to design their own compilers early in their lifetimes. The original Pascal definition appeared in 1969 and a first compiler in 1970. The first version of C appeared in 1972.

<span class="mw-page-title-main">SystemVerilog</span> Hardware description and hardware verification language

SystemVerilog, standardized as IEEE 1800, is a hardware description and hardware verification language used to model, design, simulate, test and implement electronic systems. SystemVerilog is based on Verilog and some extensions, and since 2008, Verilog is now part of the same IEEE standard. It is commonly used in the semiconductor and electronic design industry as an evolution of Verilog.

This is an overview of Fortran 95 language features. Included are the additional features of TR-15581:Enhanced Data Type Facilities, which have been universally implemented. Old features that have been superseded by new ones are not described – few of those historic features are used in modern programs although most have been retained in the language to maintain backward compatibility. The current standard is Fortran 2023; many of its new features are still being implemented in compilers. The additional features of Fortran 2003, Fortran 2008, Fortran 2018 and Fortran 2023 are described by Metcalf, Reid, Cohen and Bader.

In computer programming, a branch table or jump table is a method of transferring program control (branching) to another part of a program using a table of branch or jump instructions. It is a form of multiway branch. The branch table construction is commonly used when programming in assembly language but may also be generated by compilers, especially when implementing optimized switch statements whose values are densely packed together.

The syntax and semantics of PHP, a programming language, form a set of rules that define how a PHP program can be written and interpreted.

<span class="mw-page-title-main">Control table</span> Data structures that control the execution order of computer commands

Control tables are tables that control the control flow or play a major part in program control. There are no rigid rules about the structure or content of a control table—its qualifying attribute is its ability to direct control flow in some way through "execution" by a processor or interpreter. The design of such tables is sometimes referred to as table-driven design. In some cases, control tables can be specific implementations of finite-state-machine-based automata-based programming. If there are several hierarchical levels of control table they may behave in a manner equivalent to UML state machines

<span class="mw-page-title-main">Speakeasy (computational environment)</span> Computer software environment with own programming language

Speakeasy was a numerical computing interactive environment also featuring an interpreted programming language. It was initially developed for internal use at the Physics Division of Argonne National Laboratory by the theoretical physicist Stanley Cohen. He eventually founded Speakeasy Computing Corporation to make the program available commercially.

SuperPascal is an imperative, concurrent computing programming language developed by Per Brinch Hansen. It was designed as a publication language: a thinking tool to enable the clear and concise expression of concepts in parallel programming. This is in contrast with implementation languages which are often complicated with machine details and historical conventions. It was created to address the need at the time for a parallel publication language. Arguably, few languages today are expressive and concise enough to be used as thinking tools.

<span class="mw-page-title-main">XQuery API for Java</span> Application programming interface

XQuery API for Java (XQJ) refers to the common Java API for the W3C XQuery 1.0 specification.

PL/SQL is Oracle Corporation's procedural extension for SQL and the Oracle relational database. PL/SQL is available in Oracle Database, Times Ten in-memory database, and IBM Db2. Oracle Corporation usually extends PL/SQL functionality with each successive release of the Oracle Database.

Join-patterns provides a way to write concurrent, parallel and distributed computer programs by message passing. Compared to the use of threads and locks, this is a high level programming model using communication constructs model to abstract the complexity of concurrent environment and to allow scalability. Its focus is on the execution of a chord between messages atomically consumed from a group of channels.

References

  1. Neumann, René (17–18 July 2014). "Using Promela in a Fully Verified Executable LTL Model Checker" (PDF). VSTTE: Working Conference on Verified Software: Theories, Tools, and Experiments. LNCS. Vol. 8471. Vienna: Springer. pp. 105–114. Archived from the original (PDF) on 7 October 2015.
  2. CAVA project website
  3. Sharma, Asankhaya. "A Refinement Calculus for Promela." Engineering of Complex Computer Systems (ICECCS), 2013 18th International Conference on. IEEE, 2013.