|
|
1.1 ! root 1: .so ../ADM/mac ! 2: .XX spin 429 "Spin \(em A Protocol Analyzer" ! 3: .nr dP 2 ! 4: .nr dV 3p ! 5: .EQ ! 6: delim @@ ! 7: .EN ! 8: .de IH \" makes a bold italic sub heading ! 9: .NH 2 ! 10: \\$1 ! 11: .. ! 12: .ds P \\s-2PROMELA\\s0 ! 13: .ds S \fISpin\fP ! 14: .ds s \fIspin\fP ! 15: .TL ! 16: Spin \(em A Protocol Analyzer ! 17: .AU "MH 2C-521" 6335 ! 18: Gerard J. Holzmann ! 19: .AI ! 20: .MH ! 21: .AB ! 22: \*S is a tool for analyzing the logical consistency of ! 23: concurrent systems, specifically of data communication protocols. ! 24: The system is described in a modeling language called \*P. ! 25: The language allows for the dynamic creation of concurrent processes. ! 26: Communication via message channels can be defined to be synchronous ! 27: (i.e., rendez-vous), or asynchronous (i.e., buffered). ! 28: .PP ! 29: Given a model system specified in \*P, \*s ! 30: can either perform random simulations of the system's execution ! 31: or it can generate a C program that performs a fast exhaustive ! 32: validation of the system state space. ! 33: During simulations and validations \*s checks for the absence of deadlocks, ! 34: unspecified receptions, and unexecutable code. ! 35: The validator can also be used to verify the correctness of ! 36: system invariants, and it can find non-progress execution cycles. ! 37: .PP ! 38: The validator is setup to be extremely fast and to use ! 39: only a minimal amount of memory. ! 40: The exhaustive validations performed by \*s are conclusive, ! 41: They establish with certainty whether or not a given behavior ! 42: is error-free. ! 43: Very large validation runs, that can ordinarily not be ! 44: performed with automated techniques, can be ! 45: done in \*s with a novel ``bit state space'' technique. ! 46: With this method the state space is collapsed to a single ! 47: bit per system state stored, with minimal side-effects. ! 48: .PP ! 49: The first part of this memo gives an introduction to \*P, ! 50: the second part discusses the usage of \*s, and ! 51: the third part contains a brief reference manual for \*P. ! 52: In the appendix an example is used to illustrate the construction ! 53: of a basic \*P model for \*s validations. ! 54: .AE ! 55: .2C ! 56: .NH ! 57: Introduction to \*P ! 58: .PP ! 59: \*P is a validation modeling language. ! 60: It provides a vehicle for making abstractions of protocols ! 61: (or distributed systems in general) that suppress details ! 62: that are unrelated to process interaction. ! 63: The intended use of \*s is to validate fractions of process ! 64: behavior, that for one reason or another is considered suspect. ! 65: The relevant behavior is modeled in \*P and validated. ! 66: A complete validation is therefore typically performed in a series of steps, ! 67: with the construction of increasingly detailed \*P models. ! 68: Each model can be validated with \*s under different types of ! 69: assumptions about the environment (e.g., message loss, message ! 70: duplications etc). ! 71: Once the correctness of a model has been established with \*s, that ! 72: fact can be used in the construction and validation of all ! 73: subsequent models. ! 74: .PP ! 75: \*P programs consist of \f2processes\f1, ! 76: message \f2channels\f1, and \f2variables\f1. ! 77: Processes are global objects. ! 78: Message channels and variables can be declared either globally ! 79: or locally within a process. ! 80: Processes specify behavior; channels and global variables ! 81: define the environment in which the processes run. ! 82: .IH Executability ! 83: .PP ! 84: In \*P there is no difference between conditions and ! 85: statements, even isolated boolean conditions can be used as statements. ! 86: The execution of every statement is conditional on its ! 87: .I executability . ! 88: Statements are either executable or blocked. ! 89: The executability is the basic means of synchronization. ! 90: A process can wait for an event to happen by waiting ! 91: for a statement to become executable. ! 92: For instance, instead of writing a busy wait loop: ! 93: .P1 0 ! 94: while (a != b) ! 95: skip /* wait for a==b */ ! 96: .P2 ! 97: one can achieve the same effect in \*P with the statement ! 98: .P1 0 ! 99: (a == b) ! 100: .P2 ! 101: A condition can only be executed (passed) when it holds. ! 102: If the condition does not hold, execution blocks until it does. ! 103: .PP ! 104: Variables are used to store either global information about the ! 105: system as a whole, or information local to one specific process, ! 106: depending on where the declaration for the variable is placed. ! 107: The declarations ! 108: .P1 0 ! 109: bool flag; ! 110: int state; ! 111: byte msg; ! 112: .P2 ! 113: define variables that can store integer values in ! 114: three different ranges. ! 115: The scope of a variable is global if it is declared outside all ! 116: process declarations, and local if it is declared within a process ! 117: declaration. ! 118: .IH "Data Types" ! 119: .PP ! 120: Table 1 summarizes the basic data types, sizes, ! 121: and the corresponding value ranges (on a DEC VAX computer). ! 122: .KS ! 123: .SP .5 ! 124: .ps -1 ! 125: .vs -2 ! 126: .TS ! 127: center; ! 128: l l l l ! 129: lFCW n r c. ! 130: = ! 131: Name Size (bits) Usage Range ! 132: _ ! 133: bit 1 unsigned 0..1 ! 134: bool 1 unsigned 0..1 ! 135: byte 8 unsigned 0..255 ! 136: short 16 signed @-2 sup 15@..@{2 sup 15} - 1@ ! 137: int 32 signed @-2 sup 31@..@{2 sup 31} - 1@ ! 138: _ ! 139: .TE ! 140: .ps +1 ! 141: .vs +2 ! 142: .SP .5 ! 143: .ce ! 144: \fBTable 1.\fP Data Types ! 145: .SP ! 146: .KE ! 147: The names ! 148: .CW bit ! 149: and ! 150: .CW bool ! 151: are synonyms for a single bit of information. ! 152: A ! 153: .CW byte ! 154: is an unsigned quantity that can store a value between ! 155: .CW 0 ! 156: and ! 157: .CW 255 . ! 158: .CW short s ! 159: and ! 160: .CW int s ! 161: are signed quantities that ! 162: differ only in the range of values they can hold. ! 163: .IH "Array Variables" ! 164: .PP ! 165: Variables can be declared as arrays. ! 166: For instance, ! 167: .P1 0 ! 168: byte state[N] ! 169: .P2 ! 170: declares an array of ! 171: .CW N ! 172: bytes that can be accessed in statements such as ! 173: .P1 0 ! 174: state[0] = state[3] + 5 * state[3*2/n] ! 175: .P2 ! 176: where ! 177: .CW n ! 178: is a constant or a variable declared elsewhere. ! 179: The index to an array can be any expression that ! 180: determines a unique integer value. ! 181: The effect of an index value outside the range ! 182: .CW "0 .. N-1" ! 183: is undefined; most likely it will cause a runtime error. ! 184: .PP ! 185: So far we have seen examples of variable declarations ! 186: and of two types of statements: boolean conditions and ! 187: assignments. ! 188: Declarations and assignments are always \f2executable\f1. ! 189: Conditions are only executable when they hold. ! 190: .IH "Process Types" ! 191: .PP ! 192: The state of a variable or of a message channel ! 193: can only be changed or inspected by processes. ! 194: The behavior of a process is defined in a ! 195: .CW proctype ! 196: declaration. ! 197: The following, for instance, declares a process with one local variable ! 198: .CW state . ! 199: .P1 0 ! 200: proctype A() ! 201: { byte state; ! 202: ! 203: state = 3 ! 204: } ! 205: .P2 ! 206: The process type is named ! 207: .CW A . ! 208: The body of the declaration is enclosed in curly braces. ! 209: The declaration body consists of a list of zero or more ! 210: declarations of local variables and/or statements. ! 211: The declaration above contains one local variable declaration ! 212: and a single statement: an assignment of the ! 213: value 3 to variable ! 214: .CW state . ! 215: .PP ! 216: The semicolon is a statement \f2separator\f1 (not a statement terminator, ! 217: hence there is no semicolon after the last statement). ! 218: \*P accepts two different statement separators: ! 219: .CW `->' ! 220: (arrow) and ! 221: .CW `;' . ! 222: The two statement separators are equivalent. ! 223: The arrow is sometimes used as an informal way to indicate a causal ! 224: relation between two statements. ! 225: Consider the following example. ! 226: .P1 0 ! 227: byte state = 2; ! 228: ! 229: proctype A() ! 230: { (state == 1) -> state = 3 ! 231: } ! 232: .P3 ! 233: proctype B() ! 234: { state = state \- 1 ! 235: } ! 236: .P2 ! 237: In this example we declared two types of processes, ! 238: .CW A ! 239: and ! 240: .CW B . ! 241: Variable ! 242: .CW state ! 243: is now a global, initialized to the value two. ! 244: Process type ! 245: .CW A ! 246: contains two statements, separated by an arrow. ! 247: In the example, process declaration ! 248: .CW B ! 249: contains a single statement that decrements ! 250: the value of the state variable by one. ! 251: Since the assignment is always executable, ! 252: processes of type ! 253: .CW B ! 254: can always complete without delay. ! 255: Processes of type ! 256: .CW A , ! 257: however, are delayed at the condition until ! 258: the variable ! 259: .CW state ! 260: contains the proper value. ! 261: ...... ! 262: .IH "Process Instantiation" ! 263: .PP ! 264: A ! 265: .CW proctype ! 266: definition only declares process behavior, it ! 267: does not execute it. ! 268: Initially, in the \*P model, just one process will be executed: ! 269: a process of type ! 270: .CW init , ! 271: that must be declared explicitly in every \*P specification. ! 272: The smallest possible \*P specification, therefore, is: ! 273: .P1 0 ! 274: init { skip } ! 275: .P2 ! 276: where ! 277: .CW skip ! 278: is a dummy, null statement. ! 279: More interestingly, however, ! 280: the initial process can initialize global variables, ! 281: and instantiate processes. ! 282: An ! 283: .CW init ! 284: declaration for the above system, for instance, could look as follows. ! 285: .P1 0 ! 286: init ! 287: { run A(); run B() ! 288: } ! 289: .P2 ! 290: .PP ! 291: .CW run ! 292: is used as a unary operator that takes the name of a process type (e.g. ! 293: .CW A ). ! 294: It is executable only if a process of ! 295: the type specified can be instantiated. ! 296: It is unexecutable if this cannot be done, ! 297: for instance if too many processes are already running. ! 298: .PP ! 299: The ! 300: .CW run ! 301: statement can pass parameter values of all basic ! 302: data types to the new process. ! 303: The declarations are then written, for instance, as follows: ! 304: .P1 0 ! 305: proctype A(byte state; short foo) ! 306: { ! 307: (state == 1) -> state = foo ! 308: } ! 309: .P3 ! 310: init ! 311: { ! 312: run A(1, 3) ! 313: } ! 314: .P2 ! 315: Data arrays or process types can not be passed as parameters. ! 316: As we will see below, there is just one other data type that ! 317: can be used as a parameter: a message channel. ! 318: .PP ! 319: .CW Run ! 320: statements can be used in any process to spawn new processes, ! 321: not just in the initial process. ! 322: Processes are created with the ! 323: .CW run ! 324: statements. ! 325: An executing process disappears again when it terminates ! 326: (i.e., reaches the end of the body of its ! 327: process type declaration), but not before all processes ! 328: that it started have terminated. ! 329: .PP ! 330: With the ! 331: .CW run ! 332: statement we can create any number of copies of the process types ! 333: .CW A ! 334: and ! 335: .CW B . ! 336: If, however, more than one concurrent process is allowed to both read and ! 337: write the value of a global variable a well-known set of problems ! 338: can result; for example see |reference(dijkstra concurrent). ! 339: Consider, for instance, the following system of ! 340: two processes, sharing access to the global variable ! 341: .CW state . ! 342: .P1 0 ! 343: byte state = 1; ! 344: ! 345: proctype A() ! 346: { (state==1) -> state = state+1 ! 347: } ! 348: .P3 ! 349: proctype B() ! 350: { (state==1) -> state = state\-1 ! 351: } ! 352: .P3 ! 353: init ! 354: { run A(); run B() ! 355: } ! 356: .P2 ! 357: If one of the two processes completes before its competitor has ! 358: started, the other process will block forever on the initial condition. ! 359: If both pass the condition simultaneously, both will complete, but ! 360: the resulting value of ! 361: .CW state ! 362: is unpredictable. ! 363: It can be any of the values ! 364: .CW 0 , ! 365: .CW 1 , ! 366: or ! 367: .CW 2 . ! 368: .PP ! 369: Many solutions to this problem have been considered, ranging from ! 370: an abolishment of global variables to the provision of special ! 371: machine instructions that can guarantee an indivisible test and ! 372: set sequence on a shared variable. ! 373: The example below was one of the first solutions published. ! 374: It is due to the Dutch mathematician Dekker. ! 375: It grants two processes mutually exclusion access to an arbitrary ! 376: .I ! 377: critical section ! 378: .R ! 379: in their code, by manipulation three additional global variables. ! 380: The first four lines in the \*P specification ! 381: below are C-style macro definitions. ! 382: The first two macros define ! 383: .CW true ! 384: to be a constant value equal to ! 385: .CW 1 ! 386: and ! 387: .CW false ! 388: to be a constant ! 389: .CW 0 . ! 390: Similarly, ! 391: .CW Aturn ! 392: and ! 393: .CW Bturn ! 394: are defined as constants. ! 395: .P1 0 ! 396: #define true 1 ! 397: #define false 0 ! 398: #define Aturn false ! 399: #define Bturn true ! 400: ! 401: bool x, y, t; ! 402: .P3 ! 403: ! 404: proctype A() ! 405: { x = true; ! 406: t = Bturn; ! 407: (y == false || t == Aturn); ! 408: /* critical section */ ! 409: x = false ! 410: } ! 411: .P3 ! 412: proctype B() ! 413: { y = true; ! 414: t = Aturn; ! 415: (x == false || t == Bturn); ! 416: /* critical section */ ! 417: y = false ! 418: } ! 419: .P3 ! 420: init ! 421: { run A(); run B() ! 422: } ! 423: .P2 ! 424: The algorithm can be executed repeatedly and is independent of ! 425: the relative speeds of the two processes. ! 426: .IH "Atomic Sequences" ! 427: .PP ! 428: In \*P there is also another way to avoid the \f2test and set\f1 ! 429: problem: ! 430: .CW atomic ! 431: sequences. ! 432: By prefixing a sequence of statements enclosed in curly ! 433: braces with the keyword ! 434: .CW atomic ! 435: the user can indicate that the sequence is to be executed ! 436: as one indivisible unit, non-interleaved with any other ! 437: processes. ! 438: It causes a run-time error if any statement, other than ! 439: the first statement, blocks in an atomic sequence. ! 440: This is how we can use atomic sequences to protect the ! 441: concurrent access to the global variable ! 442: .CW state ! 443: in the earlier example. ! 444: .P1 0 ! 445: byte state = 1; ! 446: ! 447: proctype A() ! 448: { atomic { ! 449: (state==1) -> state = state+1 ! 450: } ! 451: } ! 452: .P3 ! 453: proctype B() ! 454: { atomic { ! 455: (state==1) -> state = state\-1 ! 456: } ! 457: } ! 458: .P3 ! 459: init ! 460: { run A(); run B() ! 461: } ! 462: .P2 ! 463: In this case the final value of ! 464: .CW state ! 465: is guaranteed to be zero, though during the execution of ! 466: .CW A ! 467: and ! 468: .CW B ! 469: the intermediate value can be either ! 470: .CW 0 ! 471: or ! 472: .CW 2 . ! 473: .PP ! 474: Atomic sequences can be an important tool in reducing ! 475: the complexity of validation models. ! 476: Note that atomic sequence restricts the amount of ! 477: interleaving that is allowed in a distributed system. ! 478: Otherwise untractable models can be made tractable ! 479: by, for instance, labeling all manipulations of local variables ! 480: with atomic sequences. ! 481: The reduction in complexity can be dramatic. ! 482: .IH "Message Passing" ! 483: .PP ! 484: Message channels are used to model the transfer of data ! 485: from one process to another. ! 486: They are declared either locally or globally, ! 487: for instance as follows: ! 488: .P1 0 ! 489: chan qname[16] of { short } ! 490: .P2 ! 491: This declares a channel that can store up ! 492: to 16 messages of type ! 493: .CW short . ! 494: Channel names can be passed from one process to another via ! 495: channels or as parameters in process instantiations. ! 496: If the messages to be passed by the channel have more than ! 497: one field, the declaration may look as follows: ! 498: .P1 0 ! 499: chan qname[16] of { byte, int, chan, byte } ! 500: .P2 ! 501: This time each message in the channel stores up to ! 502: sixteen messages, each consisting of two 8-bit values, ! 503: one 32-bit value, and a channel name. ! 504: .PP ! 505: .Tm ! S ! 506: .Tm ? S ! 507: The statement ! 508: .P1 0 ! 509: qname!expr ! 510: .P2 ! 511: sends the value of expression ! 512: .CW expr ! 513: to the channel that we just created, that is: ! 514: it appends the value to the tail of the channel. ! 515: .P1 0 ! 516: qname?msg ! 517: .P2 ! 518: receives the message, it retrieves it from the head of the channel, ! 519: and stores it in a variable ! 520: .CW msg . ! 521: The channels pass messages in first-in-first-out order. ! 522: In the above cases only a single value ! 523: is passed through the channel. ! 524: If more than one value is to be transferred per message, ! 525: they are specified in a comma separated list ! 526: .P1 0 ! 527: qname!expr1,expr2,expr3 ! 528: qname?var1,var2,var3 ! 529: .P2 ! 530: If more parameters are sent per message then the message channel ! 531: can store, the redundant parameters are lost without warning. ! 532: If fewer parameters are sent then the message channel can store, ! 533: the value of the remaining parameters is undefined. ! 534: Similarly, if the receive operation tries to retrieve more ! 535: parameters than available, the value of the extra parameters is ! 536: undefined; if it receives fewer than the number of parameters ! 537: that was sent, the extra information is lost. ! 538: .PP ! 539: By convention, the first message field is often ! 540: used to specify the message type (i.e. a constant). ! 541: An alternative, and equivalent, notation for the ! 542: send and receive operations is therefore to specify the ! 543: message type, followed by a list of message fields ! 544: enclosed in braces. ! 545: In general: ! 546: .P1 0 ! 547: qname!expr1(expr2,expr3) ! 548: qname?var1(var2,var3) ! 549: .P2 ! 550: .PP ! 551: The send operation is executable only when the channel addressed is not full. ! 552: The receive operation, similarly, is only executable ! 553: when the channel is non empty. ! 554: Optionally, some of the arguments of the receive operation ! 555: can be constants: ! 556: .P1 0 ! 557: qname?cons1,var2,cons2 ! 558: .P2 ! 559: in this case, a further condition on the executability of the ! 560: receive operation is that the value of all message fields that are ! 561: specified as constants match the value of the corresponding fields ! 562: in the message that is at the head of the channel. ! 563: Again, nothing bad will happen if a statement happens to be non-executable. ! 564: The process trying to execute it will be delayed until the ! 565: statement, or, more likely, an alternative statement, becomes executable. ! 566: .PP ! 567: Here is an example that uses some of the mechanisms introduced ! 568: so far. ! 569: .P1 0 ! 570: proctype A(chan q1) ! 571: { chan q2; ! 572: q1?q2; ! 573: q2!123 ! 574: } ! 575: .P3 ! 576: proctype B(chan qforb) ! 577: { int x; ! 578: qforb?x; ! 579: printf("x = %d\n", x) ! 580: } ! 581: .P3 ! 582: init { ! 583: chan qname[1] of { chan }; ! 584: chan qforb[1] of { int }; ! 585: run A(qname); ! 586: run B(qforb); ! 587: qname!qforb ! 588: } ! 589: .P2 ! 590: The value printed will be ! 591: .CW 123 . ! 592: .PP ! 593: A predefined function ! 594: .CW len(qname) ! 595: returns the number of messages currently ! 596: stored in channel ! 597: .CW qname . ! 598: Note that if ! 599: .CW len ! 600: is used as a statement, rather than on ! 601: the right hand side of an assignment, it will be unexecutable if ! 602: the channel is empty: it returns a zero result, which by definition ! 603: means that the statement is temporarily unexecutable. ! 604: Composite conditions such as ! 605: .P1 0 ! 606: (qname?var == 0) ! 607: .P2 ! 608: or ! 609: .P1 0 ! 610: (a > b && qname!123) ! 611: .P2 ! 612: are invalid in \*P (note that these conditions can not be evaluated ! 613: without side-effects). ! 614: For a receive statement there is an alternative, using square ! 615: brackets around the clause behind the question mark. ! 616: .P1 0 ! 617: qname?[ack,var] ! 618: .P2 ! 619: is evaluated as a condition. ! 620: It returns ! 621: .CW 1 ! 622: if the corresponding receive statement ! 623: .P1 0 ! 624: qname?ack,var ! 625: .P2 ! 626: is executable, i.e., if there is indeed a message ! 627: .CW ack ! 628: at the head of the channel. ! 629: It returns ! 630: .CW 0 ! 631: otherwise. ! 632: In neither case has the evaluation of a statement such as ! 633: .P1 0 ! 634: qname?[ack,var] ! 635: .P2 ! 636: any side-effects: the receive is evaluated, not executed. ! 637: .PP ! 638: Note carefully that in non-atomic sequences of two statements such as ! 639: .P1 0 ! 640: (len(qname) < MAX) -> qname!msgtype ! 641: .P2 ! 642: or ! 643: .P1 0 ! 644: qname?[msgtype] -> qname?msgtype ! 645: .P2 ! 646: the second statement is not \f2necessarily\f1 executable ! 647: after the first one has been executed. ! 648: There may be race conditions if access to the channels ! 649: is shared between several processes. ! 650: In the first case ! 651: another process can send a message to channel ! 652: .CW qname ! 653: just after this process determined that the channel was not full. ! 654: In the second case, the other process can steal away the ! 655: message just after our process determined its presence. ! 656: .IH "Rendez-Vous Communication" ! 657: .PP ! 658: So far we have talked about asynchronous communication between processes ! 659: via message channels, declared in statements such as ! 660: .P1 0 ! 661: chan qname [N] of { byte } ! 662: .P2 ! 663: where ! 664: .CW N ! 665: is a positive constant that defines the buffer size. ! 666: A logical extension is to allow for the declaration ! 667: .P1 0 ! 668: chan port [0] of { byte } ! 669: .P2 ! 670: to define a rendez-vous port that can pass single byte messages. ! 671: The channel size is zero, that is, the channel ! 672: .CW port ! 673: can pass, but can not store messages. ! 674: Message interactions via such rendez-vous ports are ! 675: by definition synchronous. ! 676: Consider the following example. ! 677: .P1 0 ! 678: #define msgtype 33 ! 679: ! 680: chan name [0] of { byte, byte }; ! 681: ! 682: proctype A() ! 683: { name!msgtype(124); ! 684: name!msgtype(121) ! 685: } ! 686: .P3 ! 687: proctype B() ! 688: { byte state; ! 689: name?msgtype(state) ! 690: } ! 691: .P3 ! 692: init ! 693: { atomic { run A(); run B() } ! 694: } ! 695: .P2 ! 696: Channel ! 697: .CW name ! 698: is a global rendez-vous port. ! 699: The two processes will synchronously execute their first statement: ! 700: a handshake on message ! 701: .CW msgtype ! 702: and a transfer of the value 124 to local variable ! 703: .CW state . ! 704: The second statement in process ! 705: .CW A ! 706: will be unexecutable, ! 707: because there is no matching receive operation in process ! 708: .CW B . ! 709: .PP ! 710: If the channel ! 711: .CW name ! 712: is defined with a non-zero buffer capacity, ! 713: the behavior is different. ! 714: If the buffer size is at least 2, the process of type ! 715: .CW A ! 716: can complete its execution, before its peer even starts. ! 717: If the buffer size is 1, the sequence of events is as follows. ! 718: The process of type ! 719: .CW A ! 720: can complete its first send action, but it blocks on the ! 721: second, because the channel is now filled to capacity. ! 722: The process of type ! 723: .CW B ! 724: can then retrieve the first message and complete. ! 725: At this point ! 726: .CW A ! 727: becomes executable again and completes, ! 728: leaving its last message as a residual in the channel. ! 729: .PP ! 730: Rendez-vous communication is binary: only two processes, ! 731: a sender and a receiver, can be synchronized in a ! 732: rendez-vous handshake. ! 733: We will see an example of a way to exploit this to ! 734: build a semaphore below. ! 735: But first, let us introduce a few more control flow structures ! 736: that may be useful. ! 737: .NH 2 ! 738: Control Flow ! 739: .PP ! 740: Between the lines, we have already introduced three ways of ! 741: defining control flow: concatenation of statements ! 742: within a process, parallel execution of processes, and ! 743: atomic sequences. ! 744: There are three other control flow constructs in \*P to be discussed. ! 745: They are case selection, ! 746: repetition, and ! 747: unconditional jumps. ! 748: .NH 3 ! 749: Case Selection ! 750: .PP ! 751: The simplest construct is the selection structure. ! 752: Using the relative values of two variables ! 753: .CW a ! 754: and ! 755: .CW b ! 756: to choose between two options, for instance, we can write: ! 757: .P1 0 ! 758: if ! 759: :: (a != b) -> option1 ! 760: :: (a == b) -> option2 ! 761: fi ! 762: .P2 ! 763: The selection structure contains two execution sequences, ! 764: each preceded by a double colon. ! 765: Only one sequence from the list will be executed. ! 766: A sequence can be selected only if its first statement is executable. ! 767: The first statement is therefore called a \f2guard\f1. ! 768: .PP ! 769: In the above example the guards are mutually exclusive, but they ! 770: need not be. ! 771: If more than one guard is executable, one of the corresponding sequences ! 772: is selected nondeterministically. ! 773: If all guards are unexecutable the process will block until at least ! 774: one of them can be selected. ! 775: There is no restriction on the type of statements that can be used ! 776: as a guard. ! 777: The following example, for instance, uses input statements. ! 778: .P1 0 ! 779: #define a 1 ! 780: #define b 2 ! 781: ! 782: chan ch[1] of { byte }; ! 783: ! 784: proctype A() ! 785: { ch!a ! 786: } ! 787: .P3 ! 788: proctype B() ! 789: { ch!b ! 790: } ! 791: .P3 ! 792: proctype C() ! 793: { if ! 794: :: ch?a ! 795: :: ch?b ! 796: fi ! 797: } ! 798: .P3 ! 799: init ! 800: { atomic { run A(); run B(); run C() } ! 801: } ! 802: .P2 ! 803: The example defines three processes and one channel. ! 804: The first option in the selection structure of the process ! 805: of type ! 806: .CW C ! 807: is executable if the channel contains ! 808: a message ! 809: .CW a , ! 810: where ! 811: .CW a ! 812: is a constant with value ! 813: .CW 1 , ! 814: defined in a macro definition at the start of the program. ! 815: The second option is executable if it contains a message ! 816: .CW b , ! 817: where, similarly, ! 818: .CW b ! 819: is a constant. ! 820: Which message will be available depends on the unknown ! 821: relative speeds of the processes. ! 822: .PP ! 823: A process of the following type will either increment ! 824: or decrement the value of variable ! 825: .CW count ! 826: once. ! 827: .P1 0 ! 828: byte count; ! 829: ! 830: proctype counter() ! 831: { ! 832: if ! 833: :: count = count + 1 ! 834: :: count = count \- 1 ! 835: fi ! 836: } ! 837: .P2 ! 838: .NH 3 ! 839: Repetition ! 840: .PP ! 841: A logical extension of the selection structure is ! 842: the repetition structure. ! 843: We can modify the above program as follows, to obtain ! 844: a cyclic program that randomly changes the value of ! 845: the variable up or down. ! 846: .P1 0 ! 847: byte count; ! 848: ! 849: proctype counter() ! 850: { ! 851: do ! 852: :: count = count + 1 ! 853: :: count = count \- 1 ! 854: :: (count == 0) -> break ! 855: od ! 856: } ! 857: .P2 ! 858: .PP ! 859: Only one option can be selected for execution at a time. ! 860: After the option completes, the execution of the structure ! 861: is repeated. ! 862: The normal way to terminate the repetition structure is ! 863: with a ! 864: .CW break ! 865: statement. ! 866: In the example, the loop can be ! 867: broken when the count reaches zero. ! 868: Note, however, that it need ! 869: not terminate since the other two options always remain executable. ! 870: To force termination we could modify the program as follows. ! 871: .P1 0 ! 872: proctype counter() ! 873: { ! 874: do ! 875: :: (count != 0) -> ! 876: if ! 877: :: count = count + 1 ! 878: :: count = count \- 1 ! 879: fi ! 880: :: (count == 0) -> break ! 881: od ! 882: } ! 883: .P2 ! 884: .NH 3 ! 885: Unconditional Jumps ! 886: .PP ! 887: Another way to break the loop is with an unconditional jump: ! 888: the infamous ! 889: .CW goto ! 890: statement. ! 891: This is illustrated in the following implementation of Euclid's algorithm for ! 892: finding the greatest common divisor of two non-zero, positive numbers: ! 893: .P1 0 ! 894: proctype Euclid(int x, y) ! 895: { ! 896: do ! 897: :: (x > y) -> x = x \- y ! 898: :: (x < y) -> y = y \- x ! 899: :: (x == y) -> goto done ! 900: od; ! 901: done: ! 902: skip ! 903: } ! 904: .P2 ! 905: The ! 906: .CW goto ! 907: in this example jumps to a label named ! 908: .CW done . ! 909: A label can only appear before a statement. ! 910: Above we want to jump to the end of the program. ! 911: In this case a dummy statement ! 912: .CW skip ! 913: is useful: it is a place holder that ! 914: is always executable and has no effect. ! 915: The ! 916: .CW goto ! 917: is also always executable. ! 918: .PP ! 919: The following example specifies a filter that receives ! 920: messages from a channel ! 921: .CW in ! 922: and divides them over two channels ! 923: .CW large ! 924: and ! 925: .CW small ! 926: depending on the values attached. ! 927: The constant ! 928: .CW N ! 929: is defined to be ! 930: .CW 128 ! 931: and ! 932: .CW size ! 933: is defined to be ! 934: .CW 16 ! 935: in the two macro definitions. ! 936: .P1 0 ! 937: #define N 128 ! 938: #define size 16 ! 939: .P3 ! 940: ! 941: chan in [size] of { short }; ! 942: chan large [size] of { short }; ! 943: chan small [size] of { short }; ! 944: .P3 ! 945: ! 946: proctype split() ! 947: { short cargo; ! 948: ! 949: do ! 950: :: in?cargo -> ! 951: if ! 952: :: (cargo >= N) -> ! 953: large!cargo ! 954: :: (cargo < N) -> ! 955: small!cargo ! 956: fi ! 957: od ! 958: } ! 959: .P3 ! 960: init ! 961: { run split() ! 962: } ! 963: .P2 ! 964: A process type that merges the two streams back into one, most ! 965: likely in a different order, and writes it back ! 966: into the channel ! 967: .CW in ! 968: could be specified as follows. ! 969: .P1 0 ! 970: proctype merge() ! 971: { short cargo; ! 972: ! 973: do ! 974: :: if ! 975: :: large?cargo ! 976: :: small?cargo ! 977: fi; ! 978: in!cargo ! 979: od ! 980: } ! 981: .P2 ! 982: If we now modify the ! 983: .CW init ! 984: process as follows, the ! 985: split and merge processes could busily perform their ! 986: duties forever on. ! 987: .P1 0 ! 988: init ! 989: { in!345; in!12; in!6777; ! 990: in!32; in!0; ! 991: run split(); ! 992: run merge() ! 993: } ! 994: .P2 ! 995: .PP ! 996: As a final example, consider the following implementation of ! 997: a Dijkstra semaphore, using binary rendez-vous communication. ! 998: .P1 0 ! 999: #define p 0 ! 1000: #define v 1 ! 1001: ! 1002: chan sema[0] of { bit }; ! 1003: .P3 ! 1004: proctype dijkstra() ! 1005: { byte count = 1; ! 1006: ! 1007: do ! 1008: :: (count == 1) \-> ! 1009: sema!p; count = 0 ! 1010: :: (count == 0) \-> ! 1011: sema?v; count = 1 ! 1012: od ! 1013: } ! 1014: .P3 ! 1015: proctype user() ! 1016: { do ! 1017: :: sema?p; ! 1018: /* critical section */ ! 1019: sema!v; ! 1020: /* non-critical section */ ! 1021: od ! 1022: } ! 1023: .P3 ! 1024: init ! 1025: { run dijkstra(); ! 1026: run user(); ! 1027: run user(); ! 1028: run user() ! 1029: } ! 1030: .P2 ! 1031: The semaphore guarantees that only one of the user processes ! 1032: can enter its critical section at a time. ! 1033: It does not necessarily prevent the monopolization of ! 1034: the access to the critical section by one of the processes. ! 1035: .IH "Modeling Procedures and Recursion" ! 1036: .PP ! 1037: Procedures can be modeled as processes, even recursive ones. ! 1038: The return value can be passed back to the calling process ! 1039: via a global variable, or via a message. ! 1040: The following program illustrates this. ! 1041: .P1 0 ! 1042: proctype fact(int n; chan p) ! 1043: { chan child[1] of { int }; ! 1044: int result; ! 1045: ! 1046: if ! 1047: :: (n <= 1) -> p!1 ! 1048: :: (n >= 2) -> ! 1049: run fact(n-1, child); ! 1050: child?result; ! 1051: p!n*result ! 1052: fi ! 1053: } ! 1054: init ! 1055: { chan child [1] of { int }; ! 1056: int result; ! 1057: ! 1058: run fact(7, child); ! 1059: child?result; ! 1060: printf("result: %d\n", result) ! 1061: } ! 1062: .P2 ! 1063: The process ! 1064: .I "fact(n, p)" ! 1065: recursively calculates the factorial of ! 1066: .I n , ! 1067: communicating the result via a message to its parent process ! 1068: .I p . ! 1069: .IH "Timeouts" ! 1070: .PP ! 1071: We have already discussed two types of statement ! 1072: with a predefined meaning in \*P: ! 1073: .CW skip , ! 1074: and ! 1075: .CW break . ! 1076: Another predefined statement is ! 1077: .CW timeout . ! 1078: The ! 1079: .CW timeout ! 1080: models a special condition that allows a process to ! 1081: abort the waiting for a condition that may never become true, e.g. ! 1082: an input from an empty channel. ! 1083: The timeout keyword is a modeling feature in \*P that provides an ! 1084: escape from a hang state. ! 1085: The timeout condition becomes true only when no other ! 1086: statements within the distributed system is executable. ! 1087: Note that we deliberately abstract from absolute timing ! 1088: considerations, which is crucial in validation work, ! 1089: and we do not specify how the timeout should be implemented. ! 1090: A simple example is the following process that will send ! 1091: a reset message to a channel named \f2guard\f1 whenever the ! 1092: system comes to a standstill. ! 1093: .P1 0 ! 1094: proctype watchdog() ! 1095: { ! 1096: do ! 1097: :: timeout -> guard!reset ! 1098: od ! 1099: } ! 1100: .P2 ! 1101: .IH "Assertions" ! 1102: .PP ! 1103: Another important language construct in \*P that ! 1104: needs little explanation is the ! 1105: .CW assert ! 1106: statement. ! 1107: Statements of the form ! 1108: .P1 0 ! 1109: assert(any_boolean_condition) ! 1110: .P2 ! 1111: are always executable. ! 1112: If the boolean condition specified holds, the statement has no effect. ! 1113: If, however, the condition does not necessarily hold, ! 1114: the statement will produce an error report during validations with \*s. ! 1115: .NH 2 ! 1116: More Advanced Usage ! 1117: .PP ! 1118: The modeling language has a few features that specifically address ! 1119: the validation aspects. ! 1120: It shows up in the way labels are used, in the ! 1121: semantics of the \*P ! 1122: .CW timeout ! 1123: statement, and in the usage of a few ! 1124: special types of statements, such as ! 1125: \f(CWassert\f1, \f(CWblock\f1, ! 1126: and \f(CWhang\f1, that we discuss next. ! 1127: .NH 3 ! 1128: End-State Labels ! 1129: .PP ! 1130: When \*P is used as a validation language the user must ! 1131: be able to make very specific assertions about the behavior ! 1132: that is being modeled. ! 1133: In particular, if a \*P is checked for the presence of ! 1134: deadlocks, the validator must be able to distinguish a normal \f2end state\f1 ! 1135: from an abnormal one. ! 1136: .PP ! 1137: A normal end state could be a state in which every \*P process ! 1138: that was instantiated has properly reached the end of the ! 1139: defining program body, and all message channels are empty. ! 1140: But, not all \*P process are, of course, meant to reach the ! 1141: end of their program body. ! 1142: Some may very well linger in an \f(CWIDLE\f1 ! 1143: state, or they may sit patiently in a loop ! 1144: ready to spring into action when new input arrives. ! 1145: .PP ! 1146: To make it clear to the validator that these alternate end states ! 1147: are legal, and do not constitute a deadlock, a \*P model can use ! 1148: end state labels. ! 1149: For instance, if by adding a label to the process type ! 1150: \f(CWdijkstra()\f1, from section 1.9: ! 1151: .P1 ! 1152: proctype dijkstra() ! 1153: { byte count = 1; ! 1154: ! 1155: end: do ! 1156: :: (count == 1) \-> ! 1157: sema!p; count = 0 ! 1158: :: (count == 0) \-> ! 1159: sema?v; count = 1 ! 1160: od ! 1161: } ! 1162: .P2 ! 1163: we indicate that it is not an error if, at the end of an ! 1164: execution sequence, a process of type \f(CWdijkstra()\f1 ! 1165: has not reached its closing curly brace, but waits in the loop. ! 1166: Of course, such a state could still be part of a deadlock state, but ! 1167: if so, it is not caused by this particular process. ! 1168: (It will still be reported if any one of the other processes ! 1169: in not in a valid end-state). ! 1170: .PP ! 1171: There may be more than one end state label per validation model. ! 1172: If so, all labels that occur within the same process body must ! 1173: be unique. ! 1174: The rule is that every label name that \f2starts\f1 with the three ! 1175: character sequence \f(CW"end"\f1 ! 1176: is an endstate label. ! 1177: So it is perfectly valid to use variations such as ! 1178: \f(CWenddne\f1, \f(CWend0\f1, \f(CWend_appel\f1, etc. ! 1179: .NH 3 ! 1180: Progress-State Labels ! 1181: .PP ! 1182: In the same spirit as the end state labels, the user can also ! 1183: define \f2progress state\f1 labels. ! 1184: In this case, a progress state labels will mark a state that ! 1185: \f2must\f1 be executed for the protocol to make progress. ! 1186: Any infinite cycle in the protocol execution that does not ! 1187: pass through at least one of these progress states, is a ! 1188: potential starvation loop. ! 1189: In the ! 1190: .CW dijkstra ! 1191: example, for instance, we can label the ! 1192: successful passing of a semaphore test as ``progress'' and ! 1193: ask a validator to make sure that there is no cycle in the ! 1194: protocol execution where at least one process succeeds in ! 1195: passing the semaphore guard. ! 1196: If more than one state carries a progress label, ! 1197: variations with a common prefix are again valid: ! 1198: \f(CWprogress0\f1, \f(CWprogress_foo\f1, etc. ! 1199: .KF ! 1200: .P1 ! 1201: proctype dijkstra() ! 1202: { byte count = 1; ! 1203: ! 1204: end: do ! 1205: :: (count == 1) -> ! 1206: progress: sema!p; count = 0 ! 1207: :: (count == 0) -> ! 1208: sema?v; count = 1 ! 1209: od ! 1210: } ! 1211: .P2 ! 1212: .KE ! 1213: .PP ! 1214: .CW "spin -a" ! 1215: generates analyzers that support (after compilation) a ! 1216: .CW -l ! 1217: option, which makes the analyzer use a fast search for non-progress loops, ! 1218: instead of the default search for deadlocks. ! 1219: The ! 1220: .CW -l ! 1221: search completely avoids the expense of a ! 1222: full construction of all strongly ! 1223: connected components in the reachability graph ! 1224: (the conventional method for doing loop analysis). ! 1225: The expense is therefore never more than about ! 1226: twice the time and memory requirements of ! 1227: a default search for deadlocks. ! 1228: .IH "Message Type Definitions" ! 1229: .PP ! 1230: We have seen how variables are declared and how constants ! 1231: can be defined using C-style macros. ! 1232: As a mild form of syntactic sugar, \*P also allows for ! 1233: message type definitions that look as follows: ! 1234: .P1 0 ! 1235: mtype = { ! 1236: ack, nak, err, ! 1237: next, accept ! 1238: } ! 1239: .P2 ! 1240: This is a preferred way of specifying the message types since ! 1241: it abstracts from the specific values to be used, and it makes ! 1242: the names of the constants available to an implementation, ! 1243: which can improve error reporting. ! 1244: .IH "Pseudo Statements" ! 1245: .PP ! 1246: We have now discussed all the basic types of statements defined in \*P: ! 1247: assignments, conditions, send and receive, ! 1248: .CW assert , ! 1249: .CW timeout , ! 1250: .CW goto , ! 1251: .CW break ! 1252: and ! 1253: .CW skip . ! 1254: Note that ! 1255: .CW chan , ! 1256: .CW len ! 1257: and ! 1258: .CW run ! 1259: are not really statements but unary operators that can be used in ! 1260: conditions and assignments. ! 1261: .PP ! 1262: The ! 1263: .CW skip ! 1264: statement was mentioned in passing as a statement that can be ! 1265: a useful filler to satisfy syntax requirements, but that really ! 1266: has no effect. ! 1267: It is formally not part of the language but a \f2pseudo-statement\f1, ! 1268: merely a synonym of another statement with the same effect: a ! 1269: simple condition of a constant value ! 1270: .CW (1) . ! 1271: In the same spirit two other pseudo-statements are predefined. ! 1272: They are called ! 1273: .CW block ! 1274: and ! 1275: .CW halt . ! 1276: The first is a stop statement that is never executable: the ! 1277: opposite of ! 1278: .CW skip . ! 1279: It is modeled as another condition ! 1280: .CW (0) . ! 1281: The ! 1282: .CW halt ! 1283: statement aborts the execution of the system of processes ! 1284: whenever it is executed. ! 1285: It is equivalent to an assertion that will always fail: ! 1286: .CW assert(0) . ! 1287: .IH Example ! 1288: .PP ! 1289: Here is a simple example of a (flawed) protocol, modeled in \*P. ! 1290: .P1 0 ! 1291: mtype = { ! 1292: ack, nak, err, next, accept ! 1293: } ! 1294: ! 1295: .P3 ! 1296: proctype transfer(chan in,out,chin,chout) ! 1297: { byte o, i; ! 1298: ! 1299: in?next(o); ! 1300: .P3 ! 1301: do ! 1302: :: chin?nak(i) -> ! 1303: out!accept(i); ! 1304: chout!ack(o) ! 1305: .P3 ! 1306: :: chin?ack(i) -> ! 1307: out!accept(i); ! 1308: in?next(o); ! 1309: chout!ack(o) ! 1310: .P3 ! 1311: :: chin?err(i) -> ! 1312: chout!nak(o) ! 1313: od ! 1314: } ! 1315: ! 1316: .P3 ! 1317: init ! 1318: { chan AtoB[1] of { byte, byte }; ! 1319: chan BtoA[1] of { byte, byte }; ! 1320: .P3 ! 1321: chan Ain [2] of { byte }; ! 1322: chan Bin [2] of { byte }; ! 1323: .P3 ! 1324: chan Aout[2] of { byte }; ! 1325: chan Bout[2] of { byte }; ! 1326: .P3 ! 1327: atomic { ! 1328: run transfer(Ain,Aout, AtoB,BtoA); ! 1329: run transfer(Bin,Bout, BtoA,AtoB) ! 1330: }; ! 1331: .P3 ! 1332: AtoB!err(0) ! 1333: } ! 1334: .P2 ! 1335: The channels ! 1336: .CW Ain ! 1337: and ! 1338: .CW Bin ! 1339: are to be filled with ! 1340: token messages of type ! 1341: .CW next ! 1342: and arbitrary values (e.g. ! 1343: ASCII character values) by unspecified background processes: ! 1344: the users of the transfer service. ! 1345: Similarly, these user processes ! 1346: can read received data from the channels ! 1347: .CW Aout ! 1348: and ! 1349: .CW Bout . ! 1350: The channels and processes are initialized in a single ! 1351: atomic statement, and started with the dummy ! 1352: .CW err ! 1353: message. ! 1354: .NH ! 1355: Introduction to Spin ! 1356: .PP ! 1357: Given a model system specified in \*P, \*s ! 1358: can either perform random simulations of the system's execution ! 1359: or it can generate a C program that performs a fast exhaustive ! 1360: validation of the system state space. ! 1361: The validator can check, for instance, if user specified system ! 1362: invariants may be violated during a protocol's execution. ! 1363: .PP ! 1364: If \*s is invoked without any options it performs a random simulation. ! 1365: With option ! 1366: .CW -n\fIN ! 1367: the seed for the simulation is set explicitly to the integer value ! 1368: .I N . ! 1369: .PP ! 1370: The options ! 1371: .CW pglrs ! 1372: controls the amount of information output from the simulation run. ! 1373: Every line of output normally contains a reference to the source ! 1374: line in the specification that caused it. ! 1375: .IP \f(CW-p\f1 ! 1376: Shows the state changes of the \*P ! 1377: processes at every time step. ! 1378: .IP \f(CW-g\f1 ! 1379: Shows the current value of global variables at every time step. ! 1380: .IP \f(CW-l\f1 ! 1381: Shows the current value of local variables, after the ! 1382: process that owns them has changed state. ! 1383: It is best used in combination with option ! 1384: .CW -p . ! 1385: .IP \f(CW-r\f1 ! 1386: Shows all message receive events. ! 1387: It shows the process performing the receive, its name and number, ! 1388: the source line number, the message parameter number (there is ! 1389: one line for each parameter), the message type and the message ! 1390: channel number and name. ! 1391: .IP \f(CW-s\f1 ! 1392: Shows all message send events. ! 1393: .LP ! 1394: \*S understands four other options: ! 1395: .IP \f(CW-a\f1 ! 1396: Generates a protocol specific analyzer. ! 1397: The output is written into a set of C files, named ! 1398: .CW pan.[cbhmt] , ! 1399: that can be compiled to produce the analyzer ! 1400: (which is then executed to perform the analysis). ! 1401: To guarantee an exhaustive exploration of the state space, the ! 1402: program can be compiled simply as ! 1403: .RS ! 1404: .IP ! 1405: .P1 ! 1406: $ cc -o run pan.c ! 1407: .P2 ! 1408: .RE ! 1409: .IP ! 1410: For larger systems this may, however, exhaust the available memory ! 1411: on the machine used. ! 1412: Large to very large systems can still be analyzed by using a ! 1413: memory efficient bit state space method by ! 1414: .RS ! 1415: .IP ! 1416: .P1 ! 1417: $ cc -DBITSTATE -o run pan.c ! 1418: .P2 ! 1419: .RE ! 1420: .IP ! 1421: An indication of the coverage of such a search can be derived from the ! 1422: .I "hash factor" ! 1423: (see below). ! 1424: The generated executable analyzer, named ! 1425: .CW run ! 1426: above, has its own set of options that can be seen by typing ! 1427: .CW "run -?" ! 1428: (see also below in ``The Analyzer''). ! 1429: .IP \f(CW-m\f1 ! 1430: can be used to change the default semantics of send actions. ! 1431: Normally, a send operation is only executable if the target channel ! 1432: is non-full. ! 1433: This imposes an implicit synchronization that can not always ! 1434: be justified. ! 1435: Option \f(CW-m\f1 causes send actions to be always executable. ! 1436: Messages sent to a channel that is full are then dropped. ! 1437: If this option is combined with \f(CW-a\f1 the semantics of send ! 1438: in the analyzers generated is similarly altered, and the validations ! 1439: will take the effects of this type of message loss into consideration. ! 1440: .IP \f(CW-q\f1 ! 1441: causes \*s to peruse the model for obviously atomicable ! 1442: sequences, and to label them appropriately, in an effort to ! 1443: reduce the complexity of large validation runs. ! 1444: Typically, the user can do better by hand (by being more ! 1445: daring than \*s can be in this case). ! 1446: .IP \f(CW-t\f1 ! 1447: is a trail-hunting option. ! 1448: If the analyzer finds a violation of an assertion, a deadlock or ! 1449: an unspecified reception, it writes an error trail into a file ! 1450: named ! 1451: .CW pan.trail . ! 1452: The trail can be inspected in detail by invoking \*s with the ! 1453: .CW -t ! 1454: option. ! 1455: In combination with the options ! 1456: .CW pglrs ! 1457: different views of the error sequence are then easily obtained. ! 1458: .PP ! 1459: For brevity, other features of \*s are not discussed here. ! 1460: For details see|reference(holzmann spinbook), for a hint of ! 1461: what else is available, see ``Digging Deeper'' at the end of this manual. ! 1462: .IH "The Simulator" ! 1463: .PP ! 1464: Consider the following example protocol, that we will store in a ! 1465: file named ! 1466: .CW lynch . ! 1467: .P1 0 ! 1468: 1 #define MIN 9 ! 1469: 2 #define MAX 12 ! 1470: 3 #define FILL 99 ! 1471: 4 ! 1472: 5 mtype = { ack, nak, err } ! 1473: 6 ! 1474: .P3 ! 1475: 7 proctype transfer(chan chin, chout) ! 1476: 8 { byte o, i, last_i=MIN; ! 1477: 9 ! 1478: 10 o = MIN+1; ! 1479: .P3 ! 1480: 11 do ! 1481: 12 :: chin?nak(i) -> ! 1482: 13 assert(i == last_i+1); ! 1483: 14 chout!ack(o) ! 1484: .P3 ! 1485: 15 :: chin?ack(i) -> ! 1486: 16 if ! 1487: 17 :: (o < MAX) -> o = o+1 ! 1488: 18 :: (o >= MAX) -> o = FILL ! 1489: 19 fi; ! 1490: 20 chout!ack(o) ! 1491: .P3 ! 1492: 21 :: chin?err(i) -> ! 1493: 22 chout!nak(o) ! 1494: 23 od ! 1495: 24 } ! 1496: 25 ! 1497: .P3 ! 1498: 26 proctype channel(chan in, out) ! 1499: 27 { byte md, mt; ! 1500: 28 do ! 1501: 29 :: in?mt,md -> ! 1502: 30 if ! 1503: 31 :: out!mt,md ! 1504: 32 :: out!err,0 ! 1505: 33 fi ! 1506: 34 od ! 1507: 35 } ! 1508: 36 ! 1509: .P3 ! 1510: 37 init ! 1511: 38 { chan AtoB[1] of { byte, byte }; ! 1512: 39 chan BtoC[1] of { byte, byte }; ! 1513: 40 chan CtoA[1] of { byte, byte }; ! 1514: 41 atomic { ! 1515: 42 run transfer(AtoB, BtoC); ! 1516: 43 run channel(BtoC, CtoA); ! 1517: 44 run transfer(CtoA, AtoB) ! 1518: 45 }; ! 1519: 46 AtoB!err,0; /* start */ ! 1520: 47 hang ! 1521: 48 } ! 1522: .P2 ! 1523: The protocol uses three message types: \f2ack\f1, \f2nak\f1, and ! 1524: a special type \f2err\f1 that is used to model message distortions ! 1525: on the communication channel between the two transfer processes. ! 1526: The behavior of the channel is modeled explicitly with a channel ! 1527: process. ! 1528: There is also an ! 1529: .CW assert ! 1530: statement that claims a (faulty) invariant ! 1531: relation between two local variables in the transfer processes. ! 1532: .PP ! 1533: Running \*s without options gives us a random simulation that ! 1534: will only provide output when execution terminates, or if ! 1535: a \f2printf\f1 statement is encountered. ! 1536: In this case: ! 1537: .P1 0 ! 1538: $ spin lynch ! 1539: spin: "lynch" line 13: assertion violated ! 1540: #processes: 4 ! 1541: proc 3 (transfer) line 11 (state 15) ! 1542: proc 2 (channel) line 28 (state 6) ! 1543: proc 1 (transfer) line 13 (state 3) ! 1544: proc 0 (:init:) line 48 (state 6) ! 1545: 4 processes created ! 1546: $ ! 1547: .P2 ! 1548: There are no \f2printf\f1's in the specification, but execution ! 1549: halts on an assertion violation. ! 1550: Curious to find out more, we can repeat the run with more verbose ! 1551: output, e.g. printing all receive events. ! 1552: The result of that run is shown in Figure 1. ! 1553: Most output will be self-explanatory. ! 1554: .PP ! 1555: The above simulation run ends in the same assertion violation. ! 1556: Since the simulation resolves nondeterministic choices in a ! 1557: random manner, this need not always be the case. ! 1558: To force a reproducible run, the option ! 1559: .CW -n\fIN ! 1560: can be used. ! 1561: For instance: ! 1562: .P1 0 ! 1563: $ spin -r -n100 lynch ! 1564: .P2 ! 1565: will seed the random number generator with the integer value 100 ! 1566: and is guaranteed to produce the same output each time it is executed. ! 1567: .PP ! 1568: The other options can add still more output to the simulation run, ! 1569: but the amount of text can quickly become overwhelming. ! 1570: An easy solution is to filter the output through \f2grep\f1. ! 1571: For instance, if we are only interested in the behavior of the ! 1572: channel process in the above example, we say: ! 1573: .P1 0 ! 1574: $ spin -n100 -r lynch | grep "proc 2" ! 1575: .P2 ! 1576: The results are shown in Figure 1. ! 1577: .1C ! 1578: .KF ! 1579: .nf ! 1580: .ps -2 ! 1581: .vs -3p ! 1582: .ft CW ! 1583: .TS ! 1584: box expand; ! 1585: l ! 1586: l. ! 1587: $ spin -r lynch ! 1588: proc 1 (transfer) line 21, Recv err,0 <- queue 1 (chin) ! 1589: proc 2 (channel) line 29, Recv nak,10 <- queue 2 (in) ! 1590: proc 3 (transfer) line 12, Recv nak,10 <- queue 3 (chin) ! 1591: proc 1 (transfer) line 15, Recv ack,10 <- queue 1 (chin) ! 1592: \&... ! 1593: proc 1 (transfer) line 15, Recv ack,12 <- queue 1 (chin) ! 1594: proc 2 (channel) line 29, Recv ack,99 <- queue 2 (in) ! 1595: proc 3 (transfer) line 15, Recv ack,99 <- queue 3 (chin) ! 1596: proc 1 (transfer) line 15, Recv ack,99 <- queue 1 (chin) ! 1597: proc 2 (channel) line 29, Recv ack,99 <- queue 2 (in) ! 1598: proc 3 (transfer) line 21, Recv err,0 <- queue 3 (chin) ! 1599: proc 1 (transfer) line 12, Recv nak,99 <- queue 1 (chin) ! 1600: spin: "lynch" line 13: assertion violated ! 1601: #processes: 4 ! 1602: proc 3 (transfer) line 11 (state 15) ! 1603: proc 2 (channel) line 28 (state 6) ! 1604: proc 1 (transfer) line 13 (state 3) ! 1605: proc 0 (:init:) line 48 (state 6) ! 1606: 4 processes created ! 1607: $ spin -n100 -r lynch | grep "proc 2" ! 1608: proc 2 (channel) line 29, Recv nak,10 <- queue 2 (in) ! 1609: proc 2 (channel) line 29, Recv ack,11 <- queue 2 (in) ! 1610: proc 2 (channel) line 29, Recv ack,12 <- queue 2 (in) ! 1611: proc 2 (channel) line 28 (state 6) ! 1612: .TE ! 1613: .fi ! 1614: .ps +2 ! 1615: .vs +3p ! 1616: .SP .5 ! 1617: .ce ! 1618: \fBFigure 1.\fR Simulation Run Output ! 1619: .SP .5 ! 1620: .KE ! 1621: .2C ! 1622: ...... ! 1623: .IH "The Analyzer" ! 1624: .PP ! 1625: The simulation runs can be useful in quick debugging of ! 1626: new designs, but by simulation alone we can not prove ! 1627: that the system is really error free. ! 1628: A validation of even very large models can be performed with the ! 1629: .CW -a ! 1630: and ! 1631: .CW -t ! 1632: options of \*s. ! 1633: .PP ! 1634: An exhaustive state space searching program for a protocol ! 1635: model is generated as follows, producing five files, named \f2pan.[bchmt]\f1. ! 1636: .P1 0 ! 1637: $ spin -a lynch ! 1638: .P3 ! 1639: $ wc pan.[bchmt] ! 1640: .P3 ! 1641: 92 326 2041 pan.b ! 1642: .P3 ! 1643: 854 2502 17524 pan.c ! 1644: .P3 ! 1645: 147 576 3475 pan.h ! 1646: .P3 ! 1647: 307 1230 7493 pan.m ! 1648: .P3 ! 1649: 177 548 3997 pan.t ! 1650: .P3 ! 1651: 1577 5182 34530 total ! 1652: .P2 ! 1653: The details are none too interesting: \f2pan.c\f1 contains ! 1654: most of the C code for the analysis of the protocol. ! 1655: File \f2pan.t\f1 contains a transition matrix that encodes ! 1656: the protocol control flow; \f2pan.b\f1 and \f2pan.m\f1 contain ! 1657: C code for forward and backward transitions and ! 1658: \f2pan.h\f1 is a general header file. ! 1659: The program can be compiled in two different ways: with a full ! 1660: state space or with a bit state space. ! 1661: .IH "Exhaustive Search" ! 1662: .PP ! 1663: The best method, that works up to system state spaces of ! 1664: roughly 100,000 states, is to use the ! 1665: default compilation of the program: ! 1666: .P1 0 ! 1667: $ cc -o run pan.c ! 1668: .P2 ! 1669: The executable program \f2run\f1 can now be executed to perform ! 1670: the validation. ! 1671: The validation is truly exhaustive: it tests all possible ! 1672: event sequences in all possible orders. ! 1673: It should, of course, find the same assertion violation. ! 1674: .P1 0 ! 1675: $ run ! 1676: assertion violated (i == last_i + 1)) ! 1677: pan: aborted ! 1678: pan: wrote pan.trail ! 1679: search interrupted ! 1680: vector 64 byte, depth reached 56 ! 1681: 61 states, stored ! 1682: 5 states, linked ! 1683: 1 states, matched ! 1684: hash conflicts: 0 (resolved) ! 1685: (size 2^18 states, stack frames: 0/5) ! 1686: .P2 ! 1687: The first line of the output announces the assertion violation ! 1688: and attempts to give a first indication of the invariant that ! 1689: was violated. ! 1690: The violation was found after 61 states had been generated. ! 1691: Hash "conflicts" gives the number ! 1692: of hash collisions that happened during access to the state space. ! 1693: As indicated, ! 1694: all collisions are resolved in full search mode, since all states are ! 1695: placed in a linked list. ! 1696: The most relevant piece of output in this case, however, is on the ! 1697: third line which tells us that a trail file was created that can ! 1698: be used in combination with the simulator to recreate the error ! 1699: sequence. ! 1700: We can now say, for instance ! 1701: .P1 0 ! 1702: $ spin -t -r lynch | grep "proc 2" ! 1703: .P2 ! 1704: to determine the cause of the error. ! 1705: Note carefully that the validator is guaranteed to find the ! 1706: assertion violation if it is feasible. ! 1707: If an exhaustive search does not report such a violation, it is ! 1708: certain that \f2no\f1 execution execution sequence exists that can ! 1709: violate the assertion. ! 1710: .IH Options ! 1711: .PP ! 1712: The executable analyzer that is generated comes with a modest ! 1713: number of options that can be checked as follows ! 1714: .P1 0 ! 1715: $ run -? ! 1716: -cN stop at Nth error (default=1) ! 1717: -l find non-progress loops ! 1718: -mN max depth N (default=10k) ! 1719: -wN hash table of 2^N entries (default=18) ! 1720: .P2 ! 1721: Using a zero as an argument to the first option ! 1722: forces the state space search to continue, ! 1723: even if errors are found. ! 1724: An overview of unexecutable (unreachable) code is given with every ! 1725: complete run: either the default run if it did not find any ! 1726: errors, or the run with option ! 1727: .CW -c0 . ! 1728: In this case the output is: ! 1729: .P1 0 ! 1730: $ run -c0 ! 1731: assertion violated (i == (last_i + 1)) ! 1732: assertion violated (i == (last_i + 1)) ! 1733: assertion violated (i == (last_i + 1)) ! 1734: assertion violated (i == (last_i + 1)) ! 1735: assertion violated (i == (last_i + 1)) ! 1736: .P3 ! 1737: vector 64 byte, depth reached 60, errors: 5 ! 1738: 165 states, stored ! 1739: 5 states, linked ! 1740: 26 states, matched ! 1741: hash conflicts: 1 (resolved) ! 1742: (size 2^18 states, stack frames: 0/6) ! 1743: ! 1744: unreached code :init: (proc 0): ! 1745: reached all 9 states ! 1746: unreached code channel (proc 1): ! 1747: line 35 (state 9), ! 1748: reached: 8 of 9 states ! 1749: unreached code transfer (proc 2): ! 1750: line 24 (state 18), ! 1751: reached: 17 of 18 states ! 1752: .P2 ! 1753: There were five assertion violations, and some 165 unique ! 1754: system states were generated. ! 1755: Each state description (the \f2vector size\f1) took up 64 bytes ! 1756: of memory; the longest non-cyclic execution sequence was 60. ! 1757: There is one unreachable state both in the channel process and in ! 1758: the transfer process. ! 1759: In both cases the unreachable state is the control flow point ! 1760: just after the do-loop in each process. ! 1761: Note that both loops are indeed meant to be non-terminating. ! 1762: .PP ! 1763: The \f(CW-l\f1 option will cause the analyzer to search for ! 1764: non-progress loops rather than deadlocks or assertion violations. ! 1765: The option is explained in the section on ``More Advanced Usage.'' ! 1766: .PP ! 1767: The executable analyzer has two other options. ! 1768: By default the search depth is restricted to a rather ! 1769: arbitrary 10,000 steps. ! 1770: If the depth limit is reached, the search is truncated, making ! 1771: the validation less than exhaustive. ! 1772: To make certain that the search is exhaustive, make sure that the ! 1773: "depth reached" notice is within the maximum search depth, and ! 1774: if not, repeat the analysis with an explicit ! 1775: .CW -m ! 1776: argument. ! 1777: .PP ! 1778: The ! 1779: .CW -m ! 1780: option can of course also be used to truncate ! 1781: the search explicitly, in an effort to find the shortest possible ! 1782: execution sequence that violates a given assertion. ! 1783: Such a truncated search, however, is not guaranteed to find every ! 1784: possible violation, even within the search depth. ! 1785: .PP ! 1786: The last option ! 1787: .CW -w\fIN ! 1788: can only affect the run time, not ! 1789: the scope, of an analysis with a full state space. ! 1790: This "hash table width" should normally be set equal to, ! 1791: or preferably higher than, ! 1792: the logarithm of the expected number of unique system states generated ! 1793: by the analyzer. ! 1794: (If it is set too low, the number of hash collisions will increase ! 1795: and slow down the search.) ! 1796: The default ! 1797: .I N ! 1798: of 18 handles up to 262,144 system states, which should ! 1799: suffice for almost all applications of a full state space analysis. ! 1800: .IH "Bit State Space Analysis" ! 1801: .PP ! 1802: It can easily be calculated what the memory requirements of an analysis ! 1803: with a full state space are|reference(holzmann atttj). ! 1804: If, as in the example we have used, the protocol requires 64 bytes ! 1805: of memory to encode one system state, and we have a total of 2MB ! 1806: of memory available for the search, we can store up to 32,768 states. ! 1807: The analysis fails if there are more reachable states in the ! 1808: system state space. ! 1809: So far, \*s is the \f2only\f1 validation system that can avoid this trap. ! 1810: All other existing automated validation system (irrespective on ! 1811: which formalism they are based) simply run out of memory and ! 1812: abort their analysis without returning a useful answer to the user. ! 1813: .PP ! 1814: The coverage of a conventional analysis goes down rapidly when ! 1815: the memory limit is hit, i.e. if there are ! 1816: twice as many states in the full state space than we can store, ! 1817: the effective coverage of the search is only 50% and so on. ! 1818: \*S does substantially better in those cases by using the bit state ! 1819: space storage method|reference(holzmann atttj). ! 1820: The bit state space can be included by compiling the analyzer as follows: ! 1821: .P1 0 ! 1822: $ cc -DBITSTATE -o run pan.c ! 1823: .P2 ! 1824: The analyzer compiled in this way ! 1825: should of course find the same assertion violation again: ! 1826: .P1 0 ! 1827: $ run ! 1828: assertion violated (i == ((last_i + 1)) ! 1829: pan: aborted ! 1830: pan: wrote pan.trail ! 1831: search interrupted ! 1832: vector 64 byte, depth reached 56 ! 1833: 61 states, stored ! 1834: 5 states, linked ! 1835: 1 states, matched ! 1836: hash factor: 67650.064516 ! 1837: (size 2^22 states, stack frames: 0/5) ! 1838: $ ! 1839: .P2 ! 1840: In fact, for small to medium size problems there is very little ! 1841: difference between the full state space method and the bit state ! 1842: space method (with the exception that the latter is somewhat ! 1843: faster and uses substantially less memory). ! 1844: The big difference comes for larger problems. ! 1845: The last two lines in the output are useful in estimating ! 1846: the \f2coverage\f1 of a large run. ! 1847: The maximum number of states that the bit state space can ! 1848: accommodate is written on the last line (here @2 sup 22@ bytes or about 32 million ! 1849: bits = states). ! 1850: The line above it gives the \f2hash factor\f1: roughly ! 1851: equal to the maximum number of states divided by the actual ! 1852: number of states. ! 1853: A large hash factor (larger than 100) means, with high reliability, ! 1854: a coverage of 99% or 100%. ! 1855: As the hash factor approaches 1 the coverage approaches 0%. ! 1856: .PP ! 1857: Note carefully that the analyzer realizes a partial coverage \f2only\f1 ! 1858: in cases where traditional validators are either unable to perform a ! 1859: search, or realize a far smaller coverage. ! 1860: In \f2no\f1 case will \*s produce an answer that is less reliable than ! 1861: that produced by other automated validation systems (quite on the contrary). ! 1862: .PP ! 1863: The object of a bit state validation is to achieve a hash factor ! 1864: larger than 100 by allocating the maximum amount of memory ! 1865: for the bit state space. ! 1866: For the best result obtainable: use the ! 1867: .CW -w\fIN ! 1868: option to size the state space to precisely the amount ! 1869: of real (not virtual) memory available on your machine. ! 1870: By default, ! 1871: .I N ! 1872: is 22, corresponding to a state space of 4MB. ! 1873: For example, if your machine has 128MB of real memory, you can use ! 1874: .CW -w27 ! 1875: to analyze systems with up to a billion reachable states. ! 1876: .SP 2 ! 1877: .NH ! 1878: \*P Reference Manual ! 1879: .PP ! 1880: This section describes the language \*P proper. ! 1881: As much as possible, the presentation follows the example ! 1882: from the ! 1883: .CW C ! 1884: reference manuals|reference(cbook). ! 1885: It does not cover possible restrictions or extensions of ! 1886: specific implementations. ! 1887: The current implementation of \*s, for instance, ! 1888: has an extra keyword ! 1889: .CW printf , ! 1890: to access the corresponding ! 1891: .UX ! 1892: library function. ! 1893: .IH "Lexical Conventions" ! 1894: .PP ! 1895: There are five classes of tokens: identifiers, keywords, constants, ! 1896: operators and statement separators. ! 1897: Blanks, tabs, newlines, and comments serve only to separate tokens. ! 1898: If more than one interpretation is possible, a token is ! 1899: taken to be the longest string of characters that can ! 1900: constitute a token. ! 1901: .ix lexical conventions ! 1902: .ix tokens ! 1903: .IH Comments ! 1904: .PP ! 1905: Any string started with ! 1906: .CW /* ! 1907: and terminated with ! 1908: .CW */ ! 1909: is a comment. ! 1910: Comments may not be nested. ! 1911: .ix comments ! 1912: .IH Identifiers ! 1913: .PP ! 1914: An identifier is a single letter, period, or underscore ! 1915: followed by zero or more letters, digits, periods, or underscores. ! 1916: .ix identifiers ! 1917: .IH Keywords ! 1918: .PP ! 1919: The following identifiers are reserved for use as keywords: ! 1920: .ix keywords ! 1921: .KS ! 1922: .ft CW ! 1923: .ps -1 ! 1924: .vs -1 ! 1925: .TS ! 1926: center; ! 1927: l l l. ! 1928: assert bit block ! 1929: bool break byte ! 1930: chan do fi ! 1931: goto halt if ! 1932: init int len ! 1933: mtype od of ! 1934: proctype run short ! 1935: skip timeout ! 1936: .ps +1 ! 1937: .vs +1 ! 1938: .TE ! 1939: .KE ! 1940: .IH Constants ! 1941: .PP ! 1942: A constant is a sequence of digits representing a decimal integer. ! 1943: There are no floating point numbers in \*P. ! 1944: .ix constants ! 1945: Symbolic names for constants can be defined in two ways. ! 1946: The first method is to use a C-style macro definition ! 1947: .P1 0 ! 1948: #define NAME value ! 1949: .P2 ! 1950: The second method is to use the keyword ! 1951: .CW mtype ! 1952: (see ``declarations'' below). ! 1953: .IH Expressions ! 1954: .PP ! 1955: The following operators can be used to build expressions. ! 1956: .ix expressions ! 1957: .ix operators ! 1958: .KS ! 1959: .TS ! 1960: center; ! 1961: lFCW. ! 1962: + \- * \/ % ! 1963: > >= < <= == != ! ! 1964: && || ! 1965: & | ~ >> << ! 1966: .TE ! 1967: .KE ! 1968: .PP ! 1969: Most operators are binary. ! 1970: The logical negation \f2!\f1 and the minus \f2\-\f1 ! 1971: operator can be both unary and binary, depending on context. ! 1972: Expressions are used, for instance, in assignments of the type ! 1973: .CW "a = expression" , ! 1974: with ! 1975: .CW a ! 1976: a variable. ! 1977: .ix assignment ! 1978: There is also one unary operator that applies to message channels: ! 1979: .P1 0 ! 1980: len ! 1981: .P2 ! 1982: It measures the number of messages an existing channel holds. ! 1983: There is one unary operator that is used for process instantiations: ! 1984: .P1 0 ! 1985: run ! 1986: .P2 ! 1987: And, finally, there are two binary operators ! 1988: .P1 0 ! 1989: ! ? ! 1990: .P2 ! 1991: which are used for sending and receiving messages (see below). ! 1992: .IH Declarations ! 1993: .PP ! 1994: .ix declarations ! 1995: Processes, channels, and variables must be declared before they can be used. ! 1996: Variables and channels can be declared either locally, ! 1997: within a process, or globally. ! 1998: A process can only be declared globally in a ! 1999: .CW proctype ! 2000: declaration. ! 2001: Local declarations may appear anywhere in a process body. ! 2002: .IH Variables ! 2003: .PP ! 2004: .ix variables ! 2005: .ix local variables ! 2006: .ix global variables ! 2007: .ix initializers ! 2008: A variable declaration is started by a keyword indicating the ! 2009: basic data type of the variable, ! 2010: .CW bit , ! 2011: .CW bool , ! 2012: .CW byte , ! 2013: .CW short , ! 2014: or ! 2015: .CW int , ! 2016: followed ! 2017: by one or more identifiers, optionally followed by ! 2018: an initializer. ! 2019: .P1 0 ! 2020: byte name1, name2 = 4, name3 ! 2021: .P2 ! 2022: By default all variables are initialized to zero. ! 2023: An initializer, if specified, must be a constant. ! 2024: The table below summarizes the width and attributes of each ! 2025: basic data type. ! 2026: .KS ! 2027: .ps -1 ! 2028: .vs -2 ! 2029: .TS ! 2030: center; ! 2031: l l l ! 2032: lFCW n r. ! 2033: = ! 2034: Name Size (bits) Usage ! 2035: _ ! 2036: bit 1 unsigned ! 2037: bool 1 unsigned ! 2038: byte 8 unsigned ! 2039: short 16 signed ! 2040: int 32 signed ! 2041: _ ! 2042: .TE ! 2043: .ps +1 ! 2044: .vs +2 ! 2045: .KE ! 2046: The names \f2bit\f1 and \f2bool\f1 ! 2047: are synonyms for a single bit of ! 2048: information. ! 2049: A \f2byte\f1 is an unsigned quantity that can store a value between ! 2050: 0 and 255. ! 2051: \f2Short\f1s and \f2int\f1s are signed quantities that ! 2052: differ only in the range of values they can hold. ! 2053: .PP ! 2054: An array of variables is declared as follows: ! 2055: .P1 0 ! 2056: int name1[N] ! 2057: .P2 ! 2058: where ! 2059: .CW N ! 2060: is a constant. ! 2061: An array can have a just a single constant as an initializer. ! 2062: If specified it is used to initialize all elements of the array. ! 2063: .PP ! 2064: Symbolic names for constants, e.g. message types, ! 2065: can, optionally, be defined in a declaration ! 2066: of the type ! 2067: .P1 0 ! 2068: mtype = { namelist } ! 2069: .P2 ! 2070: where ! 2071: .CW namelist ! 2072: is a comma separated list of symbolic names. ! 2073: .IH "Message Channels" ! 2074: .PP ! 2075: A message channel can be declared, for instance, as follows: ! 2076: .ix channels ! 2077: .P1 0 ! 2078: chan name[N] of { short, short } ! 2079: .P2 ! 2080: where ! 2081: .CW N ! 2082: is a constant that specifies the maximum number of messages ! 2083: that can be stored in the channel. ! 2084: A list of one or more data types (or the channel type ! 2085: .CW chan ) ! 2086: enclosed in curly braces defines the type of the messages that can ! 2087: be passed through the channel. ! 2088: All channels are initialized to be empty. ! 2089: .IH Processes ! 2090: .PP ! 2091: .ix process ! 2092: A process declaration starts with the keyword ! 2093: .CW proctype ! 2094: followed by a name, a list of formal parameters ! 2095: enclosed in round braces, and ! 2096: a sequence of statements and local ! 2097: variable declarations. ! 2098: The body of process declaration is enclosed in curly braces. ! 2099: .P1 0 ! 2100: proctype name( /* parameter decls */ ) ! 2101: { ! 2102: /* statements */ ! 2103: } ! 2104: .P2 ! 2105: .IH Statements ! 2106: .PP ! 2107: .ix statements ! 2108: .ix gotos ! 2109: .ix labels ! 2110: .ix skip ! 2111: There are twelve types of statements: ! 2112: .KS ! 2113: .TS ! 2114: center; ! 2115: a a a. ! 2116: .ft CW ! 2117: .ps -1 ! 2118: .vs -1 ! 2119: assertion assignment atomic ! 2120: break declaration expression ! 2121: goto receive selection ! 2122: repetition send timeout ! 2123: .ft ! 2124: .ps +1 ! 2125: .vs +1 ! 2126: .TE ! 2127: .KE ! 2128: Each statement may be preceded by a label: a name followed by a colon. ! 2129: A statement can only be passed if it is executable. ! 2130: To determine its executability the statement can be evaluated: ! 2131: if evaluation returns a zero value the statement is blocked. ! 2132: In all other cases the statement is executable and can be passed. ! 2133: The act of passing the statement after a successful evaluation is ! 2134: called the ``execution'' of the statement. ! 2135: There are also three so-called \fIpseudo\fR-statements, which are ! 2136: really syntactic equivalents of specific variants of some of the ! 2137: above statements ! 2138: They are ! 2139: .P1 ! 2140: skip block halt ! 2141: .P2 ! 2142: equivalent to two conditions and an assert statement, respectively: ! 2143: .P1 ! 2144: 1 0 assert(0). ! 2145: .P2 ! 2146: .CW skip , ! 2147: therefore, is a null statement; it is always executable. ! 2148: It has no effect when executed, but may be needed ! 2149: to satisfy syntax requirements. ! 2150: .CW block , ! 2151: is never executable. ! 2152: The evaluation of an assertion statement ! 2153: .CW assert(condition) ! 2154: has no effect if the condition holds, but aborts the ! 2155: running process if evaluation of the condition returns a ! 2156: zero result (the boolean value ``false''). ! 2157: .CW halt , ! 2158: therefore, effectively stops the execution of the system. ! 2159: .PP ! 2160: .CW goto ! 2161: statements can be used to transfer control to any labeled statement ! 2162: within the same process or procedure. ! 2163: They also are always executable. ! 2164: Assignments have been discussed above, they are ! 2165: always executable. ! 2166: A declaration is also always executable. ! 2167: Expressions are only executable if they return a non-zero value. ! 2168: That is, the expression \(CW0\fR (zero) is never executable, and ! 2169: similarly \(CW1\fR always is executable. ! 2170: Below we consider the remaining statements: selection, repetition, ! 2171: send, receive, break, timeout, and atomic statements. ! 2172: .IH Selection ! 2173: .PP ! 2174: .ix if statement ! 2175: .ix case selection ! 2176: .ix nondeterminism ! 2177: A selection statement is started with the keyword ! 2178: .CW if , ! 2179: followed by ! 2180: a list of one or more `options' and terminated with the keyword ! 2181: .CW fi . ! 2182: Every `option' is started with the flag \f(CW::\fR followed by any sequence ! 2183: of statements. ! 2184: One and only one option from a selection statement will ! 2185: be selected for execution. ! 2186: The first statement of an option determines ! 2187: whether the option can be selected or not. ! 2188: If more than one option is executable, one will be selected at random. ! 2189: Note that this randomness makes the language a nondeterministic one. ! 2190: .IH "Repetition and Break" ! 2191: .PP ! 2192: .ix do statement ! 2193: .ix repetition ! 2194: A repetition or ! 2195: .CW do ! 2196: statement is similar to a selection statement, but is executed ! 2197: repeatedly until either a ! 2198: .CW break ! 2199: statement is executed or a ! 2200: .CW goto ! 2201: jump will transfer control outside the cycle. ! 2202: The keywords of the repetition statement are ! 2203: .CW do ! 2204: and ! 2205: .CW od ! 2206: instead of the ! 2207: .CW if ! 2208: and ! 2209: .CW fi ! 2210: of selection. ! 2211: The ! 2212: .CW break ! 2213: statement will terminate the innermost repetition ! 2214: statement in which it is executed. ! 2215: The use of a \(CWbreak\fR statement outside a ! 2216: repetition statement is illegal. ! 2217: ...... ! 2218: .IH "Atomic Sequences" ! 2219: .PP ! 2220: The keyword ! 2221: .CW atomic ! 2222: introduces an atomic sequence of statements, that is ! 2223: to be executed as one indivisible step. ! 2224: The syntax is as follows ! 2225: .P1 0 ! 2226: atomic { sequence } ! 2227: .P2 ! 2228: Logically the sequence of statements is now equivalent ! 2229: to one single statement. ! 2230: It is a run-time error if any statement that is part of an ! 2231: atomic sequence is found to be unexecutable. ! 2232: The safest is therefore to include only assignments and ! 2233: local conditions in atomic sequences, but no sends or receives. ! 2234: Labeling local computations as atomic can bring an important ! 2235: reduction of the complexity of a validation model. ! 2236: For the lazy, \*s has an option (\f(CW-q\f1) that tries to find ! 2237: the most obvious ``atomicable'' sequences in the code, ! 2238: but the user can often do better by hand. ! 2239: .IH Send ! 2240: .PP ! 2241: .ix i/o statements ! 2242: .ix send ! 2243: The syntax of a send statement is: ! 2244: .P1 0 ! 2245: expr1!expr2 ! 2246: .P2 ! 2247: where ! 2248: .CW expr1 ! 2249: returns the identity of a channel, e.g. obtained from a ! 2250: .CW chan ! 2251: operation, and ! 2252: .CW expr2 ! 2253: returns a value to be appended to the channel. ! 2254: The send statement is not executable (blocks) if the addressed channel is full ! 2255: or does not exist. ! 2256: .ix value transfer ! 2257: If more than one value is to be passed from sender to receiver, the expressions ! 2258: are written in a comma separated list: ! 2259: .P1 0 ! 2260: expr1!expr2,expr3,expr4 ! 2261: .P2 ! 2262: Equivalently, this may be written ! 2263: .P1 0 ! 2264: expr1!expr2(expr3,expr4) . ! 2265: .P2 ! 2266: .IH Receive ! 2267: .PP ! 2268: .ix i/o statements ! 2269: .ix receive ! 2270: .ix value transfer ! 2271: The syntax of the receive statement is: ! 2272: .P1 0 ! 2273: expr1?name ! 2274: .P2 ! 2275: where ! 2276: .CW expr1 ! 2277: returns the name of a channel and ! 2278: .CW name ! 2279: is a variable or a constant. ! 2280: If a constant is specified the receive statement is only executable ! 2281: if the channel exists and ! 2282: the oldest message stored in the channel contains the same value. ! 2283: If a variable is specified, the receive statement is executable ! 2284: if the channel exists and contains any message at all. ! 2285: The variable in that case will receive the value of the message ! 2286: that is retrieved. ! 2287: If more than one value is sent per message, the receive statement ! 2288: also take a comma separated list of variables and constants ! 2289: .P1 0 ! 2290: expr1?name1,name2,... ! 2291: .P2 ! 2292: which again is syntactically equivalent to ! 2293: .P1 0 ! 2294: expr1?name1(name2,...) ! 2295: .P2 ! 2296: Each constant in this list puts an extra condition on the ! 2297: executability of the receive: it must be matched by the ! 2298: value of the corresponding message field of the ! 2299: message to be retrieved. ! 2300: The variable fields retrieve the values of the corresponding ! 2301: message fields on a receive. ! 2302: .PP ! 2303: Placing square brackets around the clause after the `?' ! 2304: in the receiver operation converts it into a condition, ! 2305: that is true only if the corresponding receive operation ! 2306: is executable. ! 2307: It can be used freely in any type of composite boolean condition, ! 2308: and it has no side-effects when evaluated. ! 2309: .PP ! 2310: A last type of operation allowed on channels is ! 2311: .P1 0 ! 2312: len(expr) ! 2313: .P2 ! 2314: where ! 2315: .CW expr ! 2316: returns the identity of an instantiated channel. ! 2317: The operation returns the number of messages in ! 2318: the channel specified, or zero if the channel does not exist. ! 2319: .IH Timeout ! 2320: .PP ! 2321: The timeout condition is a modeling feature that by definition becomes true ! 2322: only if no statement in any of the running processes is executable. ! 2323: It has no effect when executed. ! 2324: .IH "Macros and Include Files" ! 2325: .PP ! 2326: .ix macros ! 2327: .ix include files ! 2328: .ix preprocessor ! 2329: The source text of a specification is processed by the C|reference(cbook) ! 2330: preprocessor for macro-expansion and file inclusions. ! 2331: .NH ! 2332: Summary ! 2333: .PP ! 2334: In the first part of this memo ! 2335: we have introduced a notation for modeling concurrent ! 2336: systems, including but not limited to asynchronous ! 2337: data communication protocols, in a language named \*P. ! 2338: The language has several unusual features. ! 2339: All communication between processes takes ! 2340: place via either messages or shared variables. ! 2341: Both synchronous and asynchronous communication ! 2342: are modeled as two special cases of a general message ! 2343: passing mechanism. ! 2344: Every statement in \*P can potentially model delay: it is ! 2345: either executable or not, in most cases depending on the state ! 2346: of the environment of the running process. ! 2347: Process interaction and process coordination is thus at ! 2348: the very basis of the language. ! 2349: More about the design of \*P, of the validator \*s, and ! 2350: its application to protocol design, can be found in |reference(holzmann spinbook). ! 2351: .PP ! 2352: \*P is deliberately a validation modeling language, not a programming language. ! 2353: There are, for instance, no elaborate abstract data types, ! 2354: or more than a few basic types of variable. ! 2355: A validation model is an abstraction of a protocol implementation. ! 2356: The abstraction maintains the essentials of the process interactions, ! 2357: so that it can be studied in isolation. ! 2358: It suppresses implementation and programming detail. ! 2359: .PP ! 2360: The syntax of \*P expressions, declarations, and assignments ! 2361: is loosely based on the language ! 2362: .CW C |reference(cbook). ! 2363: The language was influenced significantly by the ``guarded command languages'' ! 2364: of E.W. Dijkstra |reference(dijkstra guarded) and C.A.R. Hoare ! 2365: |reference(hoare csp). ! 2366: There are, however, important differences. ! 2367: Dijkstra's language had no primitives for process interaction. ! 2368: Hoare's language was based exclusively on synchronous ! 2369: communication. ! 2370: Also in Hoare's language, the type ! 2371: of statements that could appear in the guards of an option was ! 2372: restricted. ! 2373: The semantics of the selection and cycling statements ! 2374: in \*P is also rather different from other guarded ! 2375: command languages: the statements are not aborted when all guards ! 2376: are false but they block: thus providing the required synchronization. ! 2377: .PP ! 2378: With minimal effort \*s allows the user to generate sophisticated ! 2379: analyzers from \*P validation models. ! 2380: Both the \*s software itself, and the analyzers it can generate, ! 2381: are written in ANSII C and are portable across ! 2382: .UX ! 2383: systems. ! 2384: They can be scaled to fully exploit the physical limitations ! 2385: of the host computer, and deliver within those ! 2386: limits the best possible analyses that can be realized ! 2387: with the current state of the art in protocol analysis. ! 2388: .NH ! 2389: References ! 2390: .LP ! 2391: |reference_placement ! 2392: .af H1 A ! 2393: .nr H1 1 ! 2394: .nr H2 0 ! 2395: .SH ! 2396: Appendix: Building A Validation Suite ! 2397: .PP ! 2398: The first order of business in using \*s for ! 2399: a validation is the construction of a ! 2400: faithful model in \*P of the problem at hand. ! 2401: The language is deliberately kept small. ! 2402: The purpose of the modeling is to extract those ! 2403: aspects of the system that are relevant to the ! 2404: coordination problem being studied. ! 2405: All other details are suppressed. ! 2406: Formally: the model is a reduction of the ! 2407: system that needs to be equivalent to the full system ! 2408: only with respect to the properties that are being validated. ! 2409: Once a model has been constructed, it becomes ! 2410: the basis for the construction of a series of, ! 2411: what we may call, ``validation suites'' that ! 2412: are used to verify its properties. ! 2413: To build a validation suite we can prime the ! 2414: model with assertions. ! 2415: The assertions can formalize invariant relations ! 2416: about the values of variables or about allowable ! 2417: sequences of events in the model. ! 2418: .NH 2 ! 2419: An Example ! 2420: .PP ! 2421: As a first example we take the following solution ! 2422: to the mutual exclusion problem, discussed earlier, ! 2423: published in 1966 by H. Hyman in the Communications of the ACM. ! 2424: It was listed, in pseudo Algol, as follows. ! 2425: .P1 0 ! 2426: 1 \f3Boolean array\f2 b(0;1) \f3integer\f2 k, i,\f(CW ! 2427: 2 \f3comment\f2 process i, with i either 0 or 1;\f(CW ! 2428: 3 \f2C0: b(i) := \f3false\f2;\f(CW ! 2429: 4 \f2C1: \f3if\f2 k != i \f3then begin\f2\f(CW ! 2430: 5 \f2C2: \f3if\f2 not (b(1-i) \f3then go to\f2 C2;\f(CW ! 2431: 6 \f3else\f2 k := i; \f3go to\f2 C1 \f3end\f2;\f(CW ! 2432: 7 \f3else\f2 critical section;\f(CW ! 2433: 8 \f2b(i) := \f3true\f2;\f(CW ! 2434: 9 \f2remainder of program;\f(CW ! 2435: 10 \f3go to\f2 C0;\f(CW ! 2436: 11 \f3end\f(CW ! 2437: .P2 ! 2438: The solution, as Dekker's earlier solution, is for two processes, ! 2439: numbered 0 and 1. ! 2440: Suppose we wanted to prove that Hyman's solution truly ! 2441: guaranteed mutually exclusive access to the critical section. ! 2442: Our first task is to build a model of the solution in \*P. ! 2443: While we're at it, we can pick some more useful names for ! 2444: the variables that are used. ! 2445: .P1 0 ! 2446: 1 bool want[2]; /* Bool array b */ ! 2447: 2 bool turn; /* integer k */ ! 2448: 3 ! 2449: .P3 ! 2450: 4 proctype P(bool i) ! 2451: 5 { ! 2452: 6 want[i] = 1; ! 2453: .P3 ! 2454: 7 do ! 2455: 8 :: (turn != i) -> ! 2456: 9 (!want[1-i]); ! 2457: 10 turn = i ! 2458: .P3 ! 2459: 11 :: (turn == i) -> ! 2460: 12 break ! 2461: 13 od; ! 2462: .P3 ! 2463: 14 skip; /* critical section */ ! 2464: 15 want[i] = 0 ! 2465: 16 } ! 2466: .P3 ! 2467: 17 ! 2468: .P3 ! 2469: 18 init { run P(0); run P(1) } ! 2470: .P2 ! 2471: We can generate, compile, and run a validator for this ! 2472: model, to see if there are any major problems, such as ! 2473: a global system deadlock. ! 2474: .P1 0 ! 2475: $ spin -a hyman0 ! 2476: $ cc pan.c ! 2477: $ a.out ! 2478: full statespace search for: ! 2479: assertion violations and invalid endstates ! 2480: vector 20 byte, depth reached 19, errors: 0 ! 2481: 79 states, stored ! 2482: 0 states, linked ! 2483: 38 states, matched total: 117 ! 2484: hash conflicts: 4 (resolved) ! 2485: (size 2^18 states, stack frames: 3/0) ! 2486: ! 2487: unreached code _init (proc 0): ! 2488: reached all 3 states ! 2489: unreached code P (proc 1): ! 2490: reached all 12 states ! 2491: .P2 ! 2492: The model passes this first test. ! 2493: What we are really interested in, however, is if ! 2494: the algorithm guarantees mutual exclusion. ! 2495: There are several ways to proceed. ! 2496: The simplest is to just add enough information ! 2497: to the model that we can express the correctness ! 2498: requirement in a \*P assertion. ! 2499: .P1 0 ! 2500: 1 bool want[2]; ! 2501: 2 bool turn; ! 2502: 3 byte cnt; ! 2503: 4 ! 2504: .P3 ! 2505: 5 proctype P(bool i) ! 2506: 6 { ! 2507: .P3 ! 2508: 7 want[i] = 1; ! 2509: .P3 ! 2510: 8 do ! 2511: 9 :: (turn != i) -> ! 2512: 10 (!want[1-i]); ! 2513: 11 turn = i ! 2514: .P3 ! 2515: 12 :: (turn == i) -> ! 2516: 13 break ! 2517: 14 od; ! 2518: 15 skip; /* critical section */ ! 2519: .P3 ! 2520: 16 cnt = cnt+1; ! 2521: 17 assert(cnt == 1); ! 2522: 18 cnt = cnt-1; ! 2523: 19 want[i] = 0 ! 2524: 20 } ! 2525: .P3 ! 2526: 21 ! 2527: .P3 ! 2528: 22 init { run P(0); run P(1) } ! 2529: .P2 ! 2530: We have added a global variable ! 2531: .CW cnt ! 2532: that is incremented upon each access to the ! 2533: critical section, and decremented upon each exit ! 2534: from it. ! 2535: The maximum value that this variable should ever ! 2536: have is 1, and it can only have this value when ! 2537: a process is inside the critical section. ! 2538: .P1 0 ! 2539: $ spin -a hyman1 ! 2540: $ cc pan.c ! 2541: $ a.out ! 2542: assertion violated (cnt==1) ! 2543: pan: aborted (at depth 15) ! 2544: pan: wrote pan.trail ! 2545: full statespace search for: ! 2546: assertion violations and invalid endstates ! 2547: search was not completed ! 2548: vector 20 byte, depth reached 25, errors: 1 ! 2549: 123 states, stored ! 2550: 0 states, linked ! 2551: 55 states, matched total: 178 ! 2552: hash conflicts: 42 (resolved) ! 2553: (size 2^18 states, stack frames: 3/0) ! 2554: .P2 ! 2555: The validator claims that the assertion can be violated. ! 2556: We can use the error trail to check it with \*s's \f(CW-t\f1 option: ! 2557: .P1 0 ! 2558: $ spin -t -p hyman1 ! 2559: proc 0 (_init) line 24 (state 2) ! 2560: proc 0 (_init) line 24 (state 3) ! 2561: .P3 ! 2562: proc 2 (P) line 8 (state 7) ! 2563: proc 2 (P) line 9 (state 2) ! 2564: .P3 ! 2565: proc 2 (P) line 10 (state 3) ! 2566: proc 2 (P) line 11 (state 4) ! 2567: .P3 ! 2568: proc 1 (P) line 8 (state 7) ! 2569: proc 1 (P) line 12 (state 5) ! 2570: .P3 ! 2571: proc 1 (P) line 15 (state 10) ! 2572: proc 2 (P) line 8 (state 7) ! 2573: .P3 ! 2574: proc 2 (P) line 12 (state 5) ! 2575: proc 2 (P) line 15 (state 10) ! 2576: .P3 ! 2577: proc 2 (P) line 16 (state 11) ! 2578: proc 2 (P) line 17 (state 12) ! 2579: .P3 ! 2580: proc 2 (P) line 18 (state 13) ! 2581: proc 1 (P) line 16 (state 11) ! 2582: .P3 ! 2583: proc 1 (P) line 17 (state 12) ! 2584: spin: "hyman1" line 17: assertion violated ! 2585: .P3 ! 2586: step 17, #processes: 3 ! 2587: want[0] = 1 ! 2588: _p[0] = 12 ! 2589: turn[0] = 1 ! 2590: cnt[0] = 2 ! 2591: .P3 ! 2592: proc 2 (P) line 18 (state 13) ! 2593: proc 1 (P) line 17 (state 12) ! 2594: proc 0 (_init) line 24 (state 3) ! 2595: 3 processes created ! 2596: .P2 ! 2597: Here is another way to catch the error. ! 2598: We again lace the model with the information that ! 2599: will allow us to count the number of processes ! 2600: in the critical section. ! 2601: .P1 0 ! 2602: 1 bool want[2]; ! 2603: 2 bool turn; ! 2604: 3 byte cnt; ! 2605: 4 ! 2606: .P3 ! 2607: 5 proctype P(bool i) ! 2608: 6 { ! 2609: 7 want[i] = 1; ! 2610: .P3 ! 2611: 8 do ! 2612: 9 :: (turn != i) -> ! 2613: 10 (!want[1-i]); ! 2614: 11 turn = i ! 2615: .P3 ! 2616: 12 :: (turn == i) -> ! 2617: 13 break ! 2618: 14 od; ! 2619: .P3 ! 2620: 15 cnt = cnt+1; ! 2621: 16 skip; /* critical section */ ! 2622: 17 cnt = cnt-1; ! 2623: 18 want[i] = 0 ! 2624: 19 } ! 2625: .P3 ! 2626: 20 ! 2627: .P3 ! 2628: 21 proctype monitor() ! 2629: 22 { ! 2630: 23 assert(cnt == 0 || cnt == 1) ! 2631: 24 } ! 2632: .P3 ! 2633: 25 ! 2634: .P3 ! 2635: 26 init { ! 2636: 27 run P(0); run P(1); run monitor() ! 2637: 28 } ! 2638: .P2 ! 2639: The invariant condition on the value of counter ! 2640: .CW cnt ! 2641: is now place in a separate process ! 2642: .CW monitor() ! 2643: (the name is immaterial). ! 2644: The extra process runs along with the two others. ! 2645: It will always terminate in one step, but it ! 2646: could execute that step at \f2any\f1 time. ! 2647: The systems modeled by \*P and validated by \*s ! 2648: are completely asynchronous. ! 2649: That means that the validation of \*s take into ! 2650: account \f2all\f1 possible relative timings of ! 2651: the three processes. ! 2652: In a full validation, the assertion therefore ! 2653: can be evaluated at any time during the lifetime ! 2654: of the other two processes. ! 2655: If the validator reports that it is not violated ! 2656: we can indeed conclude that there is no execution ! 2657: sequence at all (no way to select relative speeds for ! 2658: the three processes) in which the assertion can be ! 2659: violated. ! 2660: The setup with the monitor process is therefore an ! 2661: elegant way to check the validity of a system invariant. ! 2662: The validation produces: ! 2663: .P1 0 ! 2664: $ spin -a hyman2 ! 2665: $ cc pan.c ! 2666: $ a.out ! 2667: assertion violated ((cnt==0)||(cnt==1)) ! 2668: pan: aborted (at depth 15) ! 2669: pan: wrote pan.trail ! 2670: full statespace search for: ! 2671: assertion violations and invalid endstates ! 2672: search was not completed ! 2673: vector 24 byte, depth reached 26, errors: 1 ! 2674: 368 states, stored ! 2675: 0 states, linked ! 2676: 379 states, matched total: 747 ! 2677: hash conflicts: 180 (resolved) ! 2678: (size 2^18 states, stack frames: 4/0) ! 2679: .P2 ! 2680: Because of the extra interleaving of the two processes ! 2681: with a third monitor, the number of system states that ! 2682: had to be searched has increased, but the error is again ! 2683: correctly reported. ! 2684: .br ! 2685: .NE 8v ! 2686: .NH 2 ! 2687: Another Example ! 2688: .PP ! 2689: Not always can a correctness requirement be cast in ! 2690: terms of a global system invariant. ! 2691: Here is an example that illustrates this. ! 2692: It is a simple alternating bit protocol, modeling ! 2693: the possibility of message loss, and distortion, ! 2694: and extended with negative acknowledgements. ! 2695: .P1 0 ! 2696: 1 #define MAX 5 ! 2697: 2 ! 2698: 3 mtype = { mesg, ack, nak, err }; ! 2699: 4 ! 2700: .P3 ! 2701: 5 proctype sender(chan in, out) ! 2702: 6 { byte o, s, r; ! 2703: 7 ! 2704: 8 o=MAX-1; ! 2705: 9 do ! 2706: 10 :: o = (o+1)%MAX; /* next msg */ ! 2707: 11 again: if ! 2708: 12 :: out!mesg(o,s) /* send */ ! 2709: 13 :: out!err /* distort */ ! 2710: 14 :: skip /* or lose */ ! 2711: 15 fi; ! 2712: .P3 ! 2713: 16 if ! 2714: 17 :: timeout -> goto again ! 2715: 18 :: in?err -> goto again ! 2716: 19 :: in?nak(r) -> goto again ! 2717: 20 :: in?ack(r) -> ! 2718: 21 if ! 2719: 22 :: (r == s) -> goto progress ! 2720: 23 :: (r != s) -> goto again ! 2721: 24 fi ! 2722: 25 fi; ! 2723: 26 progress: s = 1-s /* toggle seqno */ ! 2724: 27 od ! 2725: 28 } ! 2726: 29 ! 2727: .P3 ! 2728: 30 proctype receiver(chan in, out) ! 2729: 31 { byte i; /* actual input */ ! 2730: 32 byte s; /* actual seqno */ ! 2731: 33 byte es; /* expected seqno */ ! 2732: 34 byte ei; /* expected input */ ! 2733: 35 ! 2734: 36 do ! 2735: 37 :: in?mesg(i, s) -> ! 2736: 38 if ! 2737: 39 :: (s == es) -> ! 2738: 40 assert(i == ei); ! 2739: 41 progress: es = 1 - es; ! 2740: 42 ei = (ei + 1)%MAX; ! 2741: 43 if ! 2742: 44 /* send, */ :: out!ack(s) ! 2743: 45 /* distort */ :: out!err ! 2744: 46 /* or lose */ :: skip ! 2745: 47 fi ! 2746: .P3 ! 2747: 48 :: (s != es) -> ! 2748: .P3 ! 2749: 49 if ! 2750: .P3 ! 2751: 50 /* send, */ :: out!nak(s) ! 2752: 51 /* distort */ :: out!err ! 2753: 52 /* or lose */ :: skip ! 2754: .P3 ! 2755: 53 fi ! 2756: .P3 ! 2757: 54 fi ! 2758: 55 :: in?err -> ! 2759: 56 out!nak(s) ! 2760: .P3 ! 2761: 57 od ! 2762: 58 } ! 2763: 59 ! 2764: .P3 ! 2765: 60 init { ! 2766: .P3 ! 2767: 61 chan s_r [1] of { byte,byte,byte }; ! 2768: 62 chan r_s [1] of { byte,byte,byte }; ! 2769: .P3 ! 2770: 63 atomic { ! 2771: .P3 ! 2772: 64 run sender(r_s, s_r); ! 2773: 65 run receiver(s_r, r_s) ! 2774: .P3 ! 2775: 66 } ! 2776: .P3 ! 2777: 67 } ! 2778: .P2 ! 2779: To test the proposition that this protocol will ! 2780: correctly transfer data, the model has already ! 2781: been primed for the first validation runs. ! 2782: First, the sender is setup to transfer an infinite ! 2783: series of integers as messages, where the value ! 2784: of the integers are incremented modulo ! 2785: .CW MAX . ! 2786: The value of ! 2787: .CW MAX ! 2788: is not really too interesting, as long as it is ! 2789: larger than the range of the sequence numbers in ! 2790: the protocol: in this case 2. ! 2791: We want to verify that data that is sent can only be ! 2792: delivered to the receiver without any deletions or reorderings, ! 2793: despite the possibility of arbitrary message loss. ! 2794: The assertion on line 40 verifies precisely that. ! 2795: Note that if it were ever possible for the protocol to ! 2796: fail to meet the above requirement, the assertion can be violated. ! 2797: .PP ! 2798: A first validation run reassures us that this is not possible. ! 2799: .P1 0 ! 2800: $ spin -a ABP0 ! 2801: $ cc pan.c ! 2802: $ a.out ! 2803: full statespace search for: ! 2804: assertion violations and invalid endstates ! 2805: vector 40 byte, depth reached 131, errors: 0 ! 2806: 346 states, stored ! 2807: 1 states, linked ! 2808: 125 states, matched total: 472 ! 2809: hash conflicts: 17 (resolved) ! 2810: (size 2^18 states, stack frames: 0/25) ! 2811: ! 2812: unreached code _init (proc 0): ! 2813: reached all 4 states ! 2814: unreached code receiver (proc 1): ! 2815: line 58 (state 24) ! 2816: reached: 23 of 24 states ! 2817: unreached code sender (proc 2): ! 2818: line 28 (state 27) ! 2819: reached: 26 of 27 states ! 2820: .P2 ! 2821: But, be careful. ! 2822: The result means that all data that is delivered, is ! 2823: delivered in the correct order without deletions etc. ! 2824: We did not check that the data \f2will\f1 necessarily be delivered. ! 2825: It may be possible for sender and receiver to cycle ! 2826: through a series of states, exchanges erroneous messages, ! 2827: without ever making effective progress. ! 2828: To check this, the state in the sender and in the receiver ! 2829: process that unmistakingly signify progress, were labeled ! 2830: as a ``progress states.'' ! 2831: (In fact, either one by itself would suffice.) ! 2832: .PP ! 2833: We should now be able to demonstrate the absence of ! 2834: infinite execution cycles that do not pass through any ! 2835: of these progress states. ! 2836: We can use the same executable from the last run, but ! 2837: this time we perform a loop-check. ! 2838: .P1 0 ! 2839: $ a.out -l ! 2840: pan: non-progress cycle (at depth 6) ! 2841: pan: wrote pan.trail ! 2842: full statespace search for: ! 2843: assertion violations and non-progress loops ! 2844: search was not completed ! 2845: vector 44 byte, depth reached 8, loops: 1 ! 2846: 12 states, stored ! 2847: 1 states, linked ! 2848: 0 states, matched total: 13 ! 2849: hash conflicts: 0 (resolved) ! 2850: (size 2^18 states, stack frames: 0/1) ! 2851: .P2 ! 2852: There are non-progress cycles. ! 2853: The first one encountered is dumped into the error trail ! 2854: by the validator, and we can inspect it. ! 2855: The results are shown in the first half of Figure 2. ! 2856: The channel can distort or lose the message infinitely often; ! 2857: true, but not too exciting as an error scenario. ! 2858: To see how many non-progress cycles there are, we can use the \f(CW-c\f1 flag. ! 2859: If we set its numeric argument to zero, only ! 2860: a total count of all errors will be printed. ! 2861: .P1 0 ! 2862: $ a.out -l -c0 ! 2863: full statespace search for: ! 2864: assertion violations and non-progress loops ! 2865: vector 44 byte, depth reached 137, loops: 92 ! 2866: 671 states, stored ! 2867: 2 states, linked ! 2868: 521 states, matched total: 1194 ! 2869: hash conflicts: 39 (resolved) ! 2870: (size 2^18 states, stack frames: 0/26) ! 2871: .P2 ! 2872: There are 92 cases to consider, and we could look at each ! 2873: one, using the \f(CW-c\f1 option (\f(CW-c1\f1, \f(CW-c2\f1, \f(CW-c3\f1, ...etc.) ! 2874: But, we can make the job a little easier by at least ! 2875: filtering out the errors caused by infinite message loss. ! 2876: We label all loss events (lines 13, 43, and 48) as ! 2877: progress states, using label names with the common 8-character ! 2878: prefix ``progress,'' and look at the cycles that remain. ! 2879: (Labels go behind the ``::'' flags.) ! 2880: .P1 0 ! 2881: $ spin -a ABP1 ! 2882: $ cc pan.c ! 2883: .P3 ! 2884: $ a.out -l ! 2885: pan: non-progress cycle (at depth 133) ! 2886: pan: wrote pan.trail ! 2887: .P3 ! 2888: full statespace search for: ! 2889: assertion violations and non-progress loops ! 2890: search was not completed ! 2891: .P3 ! 2892: vector 44 byte, depth reached 136, loops: 1 ! 2893: .P3 ! 2894: 148 states, stored ! 2895: 2 states, linked ! 2896: 2 states, matched total: 152 ! 2897: .P3 ! 2898: hash conflicts: 0 (resolved) ! 2899: (size 2^18 states, stack frames: 0/26) ! 2900: .P2 ! 2901: This time, the trace reveals an honest and a serious bug in the protocol. ! 2902: The second half of Figure 2 shows the trace-back. ! 2903: .1C ! 2904: .KF ! 2905: .nf ! 2906: .ps -2 ! 2907: .vs -3p ! 2908: .ft CW ! 2909: .TS ! 2910: box expand; ! 2911: l ! 2912: l. ! 2913: $ spin -t -r -s ABP0 ! 2914: <<<<<START OF CYCLE>>>>> ! 2915: proc 1 (sender) line 13, Send err,0,0 -> queue 2 (out) ! 2916: proc 2 (receiver) line 55, Recv err,0,0 <- queue 2 (in) ! 2917: proc 2 (receiver) line 56, Send nak,0,0 -> queue 1 (out) ! 2918: proc 1 (sender) line 19, Recv nak,0,0 <- queue 1 (in) ! 2919: spin: trail ends after 12 steps ! 2920: step 12, #processes: 3 ! 2921: _p[0] = 6 ! 2922: proc 2 (receiver) line 36 (state 21) ! 2923: proc 1 (sender) line 11 (state 6) ! 2924: proc 0 (_init) line 67 (state 4) ! 2925: 3 processes created ! 2926: $ ! 2927: $ spin -t -r -s ABP1 ! 2928: \&... ! 2929: proc 2 (receiver) line 39, Recv mesg,0,0 <- queue 2 (in) ! 2930: proc 2 (receiver) line 47, Send err,0,0 -> queue 1 (out) ! 2931: proc 1 (sender) line 20, Recv err,1,0 <- queue 1 (in) ! 2932: proc 1 (sender) line 12, Send mesg,0,0 -> queue 2 (out) ! 2933: proc 2 (receiver) line 39, Recv mesg,0,0 <- queue 2 (in) ! 2934: proc 2 (receiver) line 52, Send nak,0,0 -> queue 1 (out) ! 2935: proc 1 (sender) line 21, Recv nak,0,0 <- queue 1 (in) ! 2936: proc 1 (sender) line 12, Send mesg,0,0 -> queue 2 (out) ! 2937: proc 2 (receiver) line 39, Recv mesg,0,0 <- queue 2 (in) ! 2938: proc 2 (receiver) line 52, Send nak,0,0 -> queue 1 (out) ! 2939: <<<<<START OF CYCLE>>>>> ! 2940: proc 1 (sender) line 21, Recv nak,0,0 <- queue 1 (in) ! 2941: proc 1 (sender) line 12, Send mesg,0,0 -> queue 2 (out) ! 2942: proc 2 (receiver) line 39, Recv mesg,0,0 <- queue 2 (in) ! 2943: proc 2 (receiver) line 52, Send nak,0,0 -> queue 1 (out) ! 2944: spin: trail ends after 226 steps ! 2945: \&... ! 2946: .TE ! 2947: .fi ! 2948: .ps +2 ! 2949: .vs +3p ! 2950: .SP .5 ! 2951: .ce ! 2952: \fBFigure 2.\fR Error Trails - Extended Alternating Bit Protocol ! 2953: .SP .5 ! 2954: .KE ! 2955: .2C ! 2956: .PP ! 2957: After a single positive acknowledgement is distorted ! 2958: and transformed into an ! 2959: .CW err ! 2960: message, sender and receiver get caught in an infinite ! 2961: cycle, where the sender will stubbornly repeat the last ! 2962: message for which it did not receive an acknowledgement, ! 2963: and the receiver, just as stubbornly, will reject that ! 2964: message with a negative acknowledgment. ! 2965: .NH 2 ! 2966: Digging Deeper ! 2967: .PP ! 2968: This manual can only give an outline of the ! 2969: main features of \*s, and the more common ! 2970: ways in which it can be used for validations. ! 2971: There is a small number of \*s features that ! 2972: have not been discussed here, but that may be useful ! 2973: for tackling non-standard validation problems. ! 2974: \*S, for instance, can give \*P processes access ! 2975: to extra system information, such as the current ! 2976: values of normally invisible local variables, ! 2977: or the current execution states of remote processes. ! 2978: With this extra information it may be easier in ! 2979: some cases to build accurate assertions about ! 2980: required system behavior. ! 2981: .PP ! 2982: \*S also allows for a straightforward validation of ``tasks.'' ! 2983: That is, if the user formalizes a task that is claimed to be ! 2984: performed by the system, \*s can quickly either prove or ! 2985: disprove that claim. ! 2986: The tasks can be used directly to verify any ! 2987: propositional temporal logic formula ! 2988: on the behavior of a system. ! 2989: .PP ! 2990: \*S also allows the user to formalize ``reductions'' of ! 2991: the system state space, which can be used ! 2992: to restrict a search it to a user defined subset. ! 2993: With this method it becomes trivial to verify quickly ! 2994: whether or not a given error pattern is within the range of ! 2995: behaviors of a system, even when a complete validation is ! 2996: considered to be infeasible. ! 2997: .PP ! 2998: For details about these alternative uses of \*P and ! 2999: the \*s software, refer to [5].
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.