Upgrade the version of Spin included with Plan 9 to 4.2.5. NOTE: I do not use Spin, so I'm not sure it's 100% correct, but it seems to work with casual testing. I also did not update the Spin documents in /sys/doc because I am unsure of their origin. Reference: /n/sources/patch/applied/spin425 Date: Wed Aug 31 04:37:34 CES 2005 --- /sys/man/1/spin Wed Aug 31 04:20:47 2005 +++ /sys/man/1/spin Wed Aug 31 04:20:46 2005 @@ -1,151 +1,274 @@ +.ds Z S\s-2PIN\s0 +.ds P P\s-2ROMELA\s0 +.\" +.\" On CYGWIN move this page to c:/cygwin/usr/man/man1/spin.1 +.\" .TH SPIN 1 +.CT 1 comm_mach protocol .SH NAME -spin \- verification tool for concurrent systems +spin \(mi verification tool for models of concurrent systems .SH SYNOPSIS .B spin +.BI "-a [-m]" [ -.BI -n N +.BI -P cpp ] +.I file +.br +.B spin +.BI "[-bglmprsv] [-n\f2N\f(BI]" [ -.B -cplgrsmv +.BI -P cpp ] +.I file +.br +.B spin +.BI "-c [-t]" [ -.B -iat +.BI -P cpp ] +.I file +.br +.B spin +.BI -d [ -.B -V +.BI -P cpp ] +.I file +.br +.B spin +.BI -f +.I LTL +.br +.B spin +.BI -F +.I file +.br +.B spin +.BI "-i [-bglmprsv] [-n\f2N\f(BI]" [ +.BI -P cpp +] .I file +.br +.B spin +.BI "-M [-t]" +[ +.BI -P cpp ] +.I file +.br +.B spin +.BI "-t[N] [-bglmprsv] [-j\f2N\f(BI]" +[ +.BI -P cpp +] +.I file +.br +.B spin +.BI -V +.I file .SH DESCRIPTION -.I Spin +\*Z is a tool for analyzing the logical consistency of -concurrent systems, specifically communication protocols. -The system is specified in a guarded command language called -.SM PROMELA\c -\&. -The language, described in the references, -allows for the dynamic creation of processes, -nondeterministic case selection, loops, gotos, -variables, and the specification of correctness requirements. -The tool has fast algorithms for analyzing arbitrary -liveness and safety conditions. -.PP -Given a model system specified in -.SM PROMELA\c -, -.I spin -can perform interactive, guided, or random simulations -of the system's execution -or it can generate a C program that performs an exhaustive -or approximate verification of the system. -The verifier can check, for instance, if user specified system -invariants are violated during a protocol's execution, or -if non-progress execution cycles exist. +asynchronous systems, specifically distributed software +amd communication protocols. +A verification model of the system is first specified +in a guarded command language called Promela. +This specification language, described in the reference, +allows for the modeling of dynamic creation of +asynchronous processes, +nondeterministic case selection, loops, gotos, local and +global variables. +It also allows for a concise specification of logical +correctness requirements, including, but not restricted +to requirements expressed in linear temporal logic. .PP -Without any options the program performs a random simulation of the system -defined in the input -.IR file , -default standard input. -The option -.BI -n N -sets the random seed to the integer value -.IR N . +Given a Promela model +stored in +.I file , +\*Z can perform interactive, guided, or random simulations +of the system's execution. +It can also generate a C program that performs an exhaustive +or approximate verification of the correctness requirements +for the system. +.\"----------------------a---------------- +.TP +.B -a +Generate a verifier (model checker) for the specification. +The output is written into a set of C files, named +.BR pan. [ cbhmt ], +that can be compiled +.RB ( "cc pan.c" ) +to produce an executable verifier. +The online \*Z manuals (see below) contain +the details on compilation and use of the verifiers. +.\"--------------------------c------------ +.TP +.B -c +Produce an ASCII approximation of a message sequence +chart for a random or guided (when combined with \f3-t\f1) +simulation run. See also option \f3-M\f1. +.\"--------------------------d------------ +.TP +.BI -d +Produce symbol table information for the model specified in +.I file . +For each Promela object this information includes the type, name and +number of elements (if declared as an array), the initial +value (if a data object) or size (if a message channel), the +scope (global or local), and whether the object is declared as +a variable or as a parameter. For message channels, the data types +of the message fields are listed. +For structure variables, the 3rd field defines the +name of the structure declaration that contains the variable. +.\"--------------------------f------------ +.TP +.BI "-f \f2LTL\f1" +Translate the LTL formula \f2LTL\f1 into a never claim. +.br +This option reads a formula in LTL syntax from the second argument +and translates it into Promela syntax (a never claim, qhich is Promela's +equivalent of a B\(u"chi Automaton). +The LTL operators are written: [] (always), <> (eventually), +and U (strong until). There is no X (next) operator, to secure +compatibility with the partial order reduction rules that are +applied during the verification process. +If the formula contains spaces, it should be quoted to form a +single argument to the \*Z command. +.\"--------------------------F------------ +.TP +.BI "-F \f2file\f1" +Translate the LTL formula stored in +.I file +into a never claim. +.br +This behaves identical to option +.B -f +but will read the formula from the +.I file +instead of from the command line. +The file should contain the formula as the first line. Any text +that follows this first line is ignored, so it can be used to +store comments or annotation on the formula. +(On some systems the quoting conventions of the shell complicate +the use of option +.B -f . +Option +.B -F +is meant to solve those problems.) +.\"--------------------------i------------ +.TP +.BI -i +Perform an interactive simulation, prompting the user at +every execution step that requires a nondeterministic choice +to be made. The simulation proceeds without user intervention +when execution is deterministic. +.\"--------------------------M------------ +.TP +.BI -M +Produce a message sequence chart in Postscript form for a +random simulation or a guided simulation +(when combined with \f(BI-t\f1), for the model in +.I file , +and write the result into +.I file.ps . +See also option \f3-c\f1. +.\"--------------------------m------------ +.TP +.BI -m +Changes the semantics of send events. +Ordinarily, a send action will be (blocked) if the +target message buffer is full. +With this option a message sent to a full buffer is lost. +.\"--------------------------n------------ +.TP +.BI "-n\f2N" +Set the seed for a random simulation to the integer value +.I N . +There is no space between the \f(BI-n\f1 and the integer \f2N\f1. +.\"--------------------------t------------ +.TP +.BI -t +Perform a guided simulation, following the error trail that +was produces by an earlier verification run, see the online manuals +for the details on verification. +.\"--------------------------V------------ +.TP +.BI -V +Prints the \*Z version number and exits. +.\"--------------------------.------------ .PP +With only a filename as an argument and no option flags, +\*Z performs a random simulation of the model specified in +the file (standard input is the default if the filename is omitted). +This normally does not generate output, except what is generated +explicitly by the user within the model with \f(CWprintf\f1 +statements, and some details about the final state that is +reached after the simulation completes. The group of options -.B -pglmrsv -is used to set the level of information reported -about the simulation run. +.B -bglmprsv +is used to set the desired level of information that the user wants +about a random, guided, or interactive simulation run. Every line of output normally contains a reference to the source -line in the specification that caused it. +line in the specification that generated it. +If option +.B -i +is added, the simulation is \f2interactive\f1, or if option +.B -t +is added, the simulation is \f2guided\f1. +.\"--------------------------bglprsv------------ .TP -.B c -Show message send and receive operations in tabular form, but -no other information about the execution. +.BI -b +Suppress the execution of \f(CWprintf\f1 statements within the model. .TP -.B p -Show at each time step which process changed state and what source -statement was executed. +.BI -g +Show at each time step the current value of global variables. .TP -.B l +.BI -l In combination with option -.BR p , +.BR -p , show the current value of local variables of the process. .TP -.B g -Show the value of global variables at each time step. +.BI -p +Show at each simulation step which process changed state, +and what source statement was executed. .TP -.B r +.BI -r Show all message-receive events, giving the name and number of the receiving process -and the corresponding source line number. +and the corresponding the source line number. For each message parameter, show the message type and the message channel number and name. .TP -.B s +.BI -s Show all message-send events. .TP -.B m -Ordinarily, a send action will be delayed if the -target message buffer if full. -With this option a message sent to a full buffer is lost. -The option can be combined with -.B -a -(see below). -.TP -.B v -Verbose mode: add extra detail and include more warnings. -.TP -.BI i -Perform an interactive simulation. -.TP -.B a -Generate a protocol-specific verifier. -The output is written into a set of C files, named -.BR pan. [ cbhmt ], -that can be compiled -.RB ( "cc pan.c" ) -to produce an executable verifier. -Systems that require more memory than available -on the target machine can still be analyzed by compiling -the verifier with a bit state space: -.IP -.B " cc -DBITSTATE pan.c -.IP -This collapses the state space to 1 bit per system state, -with minimal side-effects. -Partial order reduction rules normally take effect during the -verification unless the compiler directive -.B -DNOREDUCE -is used. -.IP -The compiled verifiers have their own sets of options, -which can be seen by running them with option -.BR -? . -.TP -.B t -If the verifier finds a violation of a correctness property, -it writes an error trail. -The trail can be inspected in detail by invoking -.I spin -with the -.B -t -option. -In combination with the options -.BR pglrsv , -different views of the error sequence are then be obtained. -.TP -.B V -Print the version number and exit. -.SH SOURCE -.B /sys/src/cmd/spin +.BI -v +Verbose mode, add some more detail, and generat more +hints and warnings about the model. .SH SEE ALSO -G.J. Holzmann, -.I -Design and Validation of Computer Protocols, +Online manuals at spinroot.com: +.br +.in +4 +GettingStarted.pdf, +Roadmap.pdf, +Manual.pdf, +WhatsNew.pdf, +Exercises.pdf +.in -4 +More background information on the system and the verification process, +can be found in, for instance: +.br +.in +4 +G.J. Holzmann, \f2Design and Validation of Computer Protocols\f1, Prentice Hall, 1991. .br -\(em, ``Using -.SM SPIN\c -\&''. +--, `Design and validation of protocols: a tutorial,' +\f2Computer Networks and ISDN Systems\f1, +Vol. 25, No. 9, 1993, pp. 981-1017. +.br +--, `The model checker \*Z,' +\f2IEEE Trans. on SE\f1, Vol, 23, No. 5, May 1997. +.in -4 +.br --- /sys/src/cmd/spin/README Wed Aug 31 04:20:51 2005 +++ /sys/src/cmd/spin/README Wed Aug 31 04:20:51 2005 @@ -1,12 +1,11 @@ the latest version of spin is always available via: - http://cm.bell-labs.com/cm/cs/what/spin/ + http://spinroot.com/spin/whatispin.html to make the sources compile with the mkfile on plan 9 the following changes were made: omitted memory.h from spin.h - omitted malloc.h from ps_msc.c changed /lib/cpp to /bin/cpp in main.c simplified non_fatal() in main.c to remove use of yychar --- /sys/src/cmd/spin/dstep.c Wed Aug 31 04:20:57 2005 +++ /sys/src/cmd/spin/dstep.c Wed Aug 31 04:20:55 2005 @@ -1,14 +1,13 @@ /***** spin: dstep.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" #ifdef PC @@ -26,7 +25,7 @@ static int Tojump[MAXDSTEP], Jumpto[MAXDSTEP], Special[MAXDSTEP]; static void putCode(FILE *, Element *, Element *, Element *, int); -extern int Pid, claimnr; +extern int Pid, claimnr, separate, OkBreak; static void Sourced(int n, int special) @@ -57,7 +56,7 @@ static void Mopup(FILE *fd) -{ int i, j; extern int OkBreak; +{ int i, j; for (i = 0; i < Jt; i++) { for (j = 0; j < Tj; j++) @@ -172,10 +171,21 @@ fprintf(fd, "(1 /* else */)"); break; case 'R': + if (inh++ > 0) fprintf(fd, " || "); + fprintf(fd, "("); TestOnly=1; + putstmnt(fd, ee->n, ee->seqno); + fprintf(fd, ")"); TestOnly=0; + break; case 'r': + if (inh++ > 0) fprintf(fd, " || "); + fprintf(fd, "("); TestOnly=1; + putstmnt(fd, ee->n, ee->seqno); + fprintf(fd, ")"); TestOnly=0; + break; case 's': if (inh++ > 0) fprintf(fd, " || "); fprintf(fd, "("); TestOnly=1; +/* 4.2.1 */ if (Pid != claimnr) fprintf(fd, "(boq == -1) && "); putstmnt(fd, ee->n, ee->seqno); fprintf(fd, ")"); TestOnly=0; break; @@ -194,7 +204,7 @@ } int -putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln) +putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno) { int isg=0; char buf[64]; NextLab[0] = "continue"; @@ -203,13 +213,13 @@ switch (s->frst->n->ntyp) { case UNLESS: non_fatal("'unless' inside d_step - ignored", (char *) 0); - return putcode(fd, s->frst->n->sl->this, nxt, 0, ln); + return putcode(fd, s->frst->n->sl->this, nxt, 0, ln, seqno); case NON_ATOMIC: - (void) putcode(fd, s->frst->n->sl->this, ZE, 1, ln); + (void) putcode(fd, s->frst->n->sl->this, ZE, 1, ln, seqno); break; case IF: fprintf(fd, "if (!("); - if (!CollectGuards(fd, s->frst, 0)) + if (!CollectGuards(fd, s->frst, 0)) /* what about boq? */ fprintf(fd, "1"); fprintf(fd, "))\n\t\t\tcontinue;"); isg = 1; @@ -224,12 +234,24 @@ } break; case 'R': /* <- can't really happen (it's part of a 'c') */ + fprintf(fd, "if (!("); TestOnly=1; + putstmnt(fd, s->frst->n, s->frst->seqno); + fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0; + break; case 'r': - case 's': fprintf(fd, "if (!("); TestOnly=1; putstmnt(fd, s->frst->n, s->frst->seqno); fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0; break; + case 's': + fprintf(fd, "if ("); +#if 1 +/* 4.2.1 */ if (Pid != claimnr) fprintf(fd, "(boq != -1) || "); +#endif + fprintf(fd, "!("); TestOnly=1; + putstmnt(fd, s->frst->n, s->frst->seqno); + fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0; + break; case 'c': fprintf(fd, "if (!("); if (Pid != claimnr) fprintf(fd, "boq == -1 && "); @@ -237,26 +259,40 @@ putstmnt(fd, s->frst->n->lft, s->frst->seqno); fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0; break; + case ELSE: + fprintf(fd, "if (boq != -1 || ("); + if (separate != 2) fprintf(fd, "trpt->"); + fprintf(fd, "o_pm&1))\n\t\t\tcontinue;"); + break; case ASGN: /* new 3.0.8 */ fprintf(fd, "IfNotBlocked"); break; } if (justguards) return 0; - fprintf(fd, "\n\t\tsv_save((char *)&now);\n"); - + fprintf(fd, "\n\t\tsv_save();\n\t\t"); +#if 1 + fprintf(fd, "reached[%d][%d] = 1;\n\t\t", Pid, seqno); + fprintf(fd, "reached[%d][t->st] = 1;\n\t\t", Pid); /* true next state */ + fprintf(fd, "reached[%d][tt] = 1;\n", Pid); /* true current state */ +#endif sprintf(buf, "Uerror(\"block in d_step seq, line %d\")", ln); NextLab[0] = buf; putCode(fd, s->frst, s->extent, nxt, isg); if (nxt) - { if (FirstTime(nxt->Seqno) + { extern Symbol *Fname; + extern int lineno; + + if (FirstTime(nxt->Seqno) && (!(nxt->status & DONE2) || !(nxt->status & D_ATOM))) { fprintf(fd, "S_%.3d_0: /* 1 */\n", nxt->Seqno); nxt->status |= DONE2; LastGoto = 0; } Sourced(nxt->Seqno, 1); + lineno = ln; + Fname = nxt->n->fn; Mopup(fd); } unskip(s->frst->seqno); @@ -299,7 +335,7 @@ if (LastGoto) break; if (e->nxt) { i = target( huntele(e->nxt, - e->status))->Seqno; + e->status, -1))->Seqno; fprintf(fd, "\t\tgoto S_%.3d_0; ", i); fprintf(fd, "/* 'break' */\n"); Dested(i); @@ -316,7 +352,7 @@ case GOTO: if (LastGoto) break; i = huntele( get_lab(e->n,1), - e->status)->Seqno; + e->status, -1)->Seqno; fprintf(fd, "\t\tgoto S_%.3d_0; ", i); fprintf(fd, "/* 'goto' */\n"); Dested(i); --- /sys/src/cmd/spin/flow.c Wed Aug 31 04:21:04 2005 +++ /sys/src/cmd/spin/flow.c Wed Aug 31 04:21:02 2005 @@ -1,14 +1,13 @@ /***** spin: flow.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" #ifdef PC @@ -97,6 +96,7 @@ is_skip(Lextok *n) { return (n->ntyp == PRINT + || n->ntyp == PRINTM || (n->ntyp == 'c' && n->lft && n->lft->ntyp == CONST @@ -113,15 +113,19 @@ { n = e->n; if (is_skip(n) && !has_lab(e, 0)) { cnt++; - if (cnt > 1 && n->ntyp != PRINT) + if (cnt > 1 + && n->ntyp != PRINT + && n->ntyp != PRINTM) { if (verbose&32) printf("spin: line %d %s, redundant skip\n", n->ln, n->fn->name); - if (le) + if (e != s->frst + && e != s->last + && e != s->extent) { e->status |= DONE; /* not unreachable */ le->nxt = e->nxt; /* remove it */ e = le; - } /* else, can't happen */ + } } } else cnt = 0; @@ -309,6 +313,45 @@ return has_chanref(n->rgt); } +void +loose_ends(void) /* properly tie-up ends of sub-sequences */ +{ Element *e, *f; + + for (e = Al_El; e; e = e->Nxt) + { if (!e->n + || !e->nxt) + continue; + switch (e->n->ntyp) { + case ATOMIC: + case NON_ATOMIC: + case D_STEP: + f = e->nxt; + while (f && f->n->ntyp == '.') + f = f->nxt; + if (0) printf("link %d, {%d .. %d} -> %d (ntyp=%d) was %d\n", + e->seqno, + e->n->sl->this->frst->seqno, + e->n->sl->this->last->seqno, + f?f->seqno:-1, f?f->n->ntyp:-1, + e->n->sl->this->last->nxt?e->n->sl->this->last->nxt->seqno:-1); + if (!e->n->sl->this->last->nxt) + e->n->sl->this->last->nxt = f; + else + { if (e->n->sl->this->last->nxt->n->ntyp != GOTO) + { if (!f || e->n->sl->this->last->nxt->seqno != f->seqno) + non_fatal("unexpected: loose ends", (char *)0); + } else + e->n->sl->this->last = e->n->sl->this->last->nxt; + /* + * fix_dest can push a goto into the nxt position + * in that case the goto wins and f is not needed + * but the last fields needs adjusting + */ + } + break; + } } +} + static Element * if_seq(Lextok *n) { int tok = n->ntyp; @@ -547,6 +590,7 @@ for (l = labtab; l; l = l->nxt) if (s == l->s) return (l->e); + lineno = n->ln; Fname = n->fn; if (md) fatal("undefined label %s", s->name); @@ -586,12 +630,19 @@ } void -fix_dest(Symbol *c, Symbol *a) /* label, proctype */ +fix_dest(Symbol *c, Symbol *a) /* c:label name, a:proctype name */ { Label *l; extern Symbol *context; +#if 0 + printf("ref to label '%s' in proctype '%s', search:\n", + c->name, a->name); + for (l = labtab; l; l = l->nxt) + printf(" %s in %s\n", l->s->name, l->c->name); +#endif + for (l = labtab; l; l = l->nxt) { if (strcmp(c->name, l->s->name) == 0 - && strcmp(a->name, l->c->name) == 0) + && strcmp(a->name, l->c->name) == 0) /* ? */ break; } if (!l) @@ -622,6 +673,10 @@ l->e->nxt = y; /* append the goto */ } l->e->status |= CHECK2; /* treat as if global */ + if (l->e->status & (ATOM | L_ATOM | D_ATOM)) + { non_fatal("cannot reference label inside atomic or d_step (%s)", + c->name); + } } int @@ -660,10 +715,28 @@ void make_atomic(Sequence *s, int added) -{ +{ Element *f; + walk_atomic(s->frst, s->last, added); - s->last->status &= ~ATOM; - s->last->status |= L_ATOM; + + f = s->last; + switch (f->n->ntyp) { /* is last step basic stmnt or sequence ? */ + case NON_ATOMIC: + case ATOMIC: + /* redo and search for the last step of that sequence */ + make_atomic(f->n->sl->this, added); + break; + + case UNLESS: + /* escapes are folded into main sequence */ + make_atomic(f->sub->this, added); + break; + + default: + f->status &= ~ATOM; + f->status |= L_ATOM; + break; + } } static void @@ -699,6 +772,11 @@ h = f->n->sl; walk_atomic(h->this->frst, h->this->last, added); break; + case UNLESS: + if (added) + { printf("spin: error, line %3d %s, unless in d_step (ignored)\n", + f->n->ln, f->n->fn->name); + } } for (h = f->sub; h; h = h->nxt) walk_atomic(h->this->frst, h->this->last, added); --- /sys/src/cmd/spin/guided.c Wed Aug 31 04:21:11 2005 +++ /sys/src/cmd/spin/guided.c Wed Aug 31 04:21:10 2005 @@ -1,14 +1,13 @@ /***** spin: guided.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" #include @@ -22,8 +21,8 @@ extern RunList *run, *X; extern Element *Al_El; extern Symbol *Fname, *oFname; -extern int verbose, lineno, xspin, jumpsteps, depth, merger; -extern int nproc, nstop, Tval, Rvous, m_loss, ntrail, columns; +extern int verbose, lineno, xspin, jumpsteps, depth, merger, cutoff; +extern int nproc, nstop, Tval, ntrail, columns; extern short Have_claim, Skip_claim; extern void ana_src(int, int); @@ -60,35 +59,74 @@ { Element *e; for (e = Al_El; e; e = e->Nxt) - if (e->n && e->n->ntyp == ATOMIC - || e->n && e->n->ntyp == NON_ATOMIC - || e->n && e->n->ntyp == D_STEP) + if (e->n + && (e->n->ntyp == ATOMIC + || e->n->ntyp == NON_ATOMIC + || e->n->ntyp == D_STEP)) (void) huntstart(e); } +int +not_claim(void) +{ + return (!Have_claim || !X || X->pid != 0); +} + void match_trail(void) { int i, a, nst; Element *dothis; - RunList *oX; - char snap[256]; + char snap[512], *q; + + /* + * if source model name is leader.pml + * look for the trail file under these names: + * leader.pml.trail + * leader.pml.tra + * leader.trail + * leader.tra + */ if (ntrail) sprintf(snap, "%s%d.trail", oFname->name, ntrail); else sprintf(snap, "%s.trail", oFname->name); - if (!(fd = fopen(snap, "r"))) - { snap[strlen(snap)-2] = '\0'; /* .tra on some pc's */ - if (!(fd = fopen(snap, "r"))) - { printf("spin: cannot find trail file\n"); + + if ((fd = fopen(snap, "r")) == NULL) + { snap[strlen(snap)-2] = '\0'; /* .tra */ + if ((fd = fopen(snap, "r")) == NULL) + { if ((q = strchr(oFname->name, '.')) != NULL) + { *q = '\0'; + if (ntrail) + sprintf(snap, "%s%d.trail", + oFname->name, ntrail); + else + sprintf(snap, "%s.trail", + oFname->name); + *q = '.'; + + if ((fd = fopen(snap, "r")) != NULL) + goto okay; + + snap[strlen(snap)-2] = '\0'; /* last try */ + if ((fd = fopen(snap, "r")) != NULL) + goto okay; + } + printf("spin: cannot find trail file\n"); alldone(1); } } - +okay: if (xspin == 0 && newer(oFname->name, snap)) printf("spin: warning, \"%s\" is newer than %s\n", oFname->name, snap); - Tval = m_loss = 1; /* timeouts and losses may be part of trail */ + Tval = 1; + + /* + * sets Tval because timeouts may be part of trail + * this used to also set m_loss to 1, but that is + * better handled with the runtime -m flag + */ hookup(); @@ -104,6 +142,13 @@ } continue; } + + if (cutoff > 0 && depth >= cutoff) + { printf("-------------\n"); + printf("depth-limit (-u%d steps) reached\n", cutoff); + break; + } + if (Skip_claim && pno == 0) continue; for (dothis = Al_El; dothis; dothis = dothis->Nxt) @@ -112,10 +157,12 @@ } if (!dothis) { printf("%3d: proc %d, no matching stmnt %d\n", - depth, pno, nst); + depth, pno - Have_claim, nst); lost_trail(); } + i = nproc - nstop + Skip_claim; + if (dothis->n->ntyp == '@') { if (pno == i-1) { run = run->nxt; @@ -125,15 +172,19 @@ { dotag(stdout, "\n"); continue; } + if (Have_claim && pno == 0) + printf("%3d: claim terminates\n", + depth); + else printf("%3d: proc %d terminates\n", - depth, pno); + depth, pno - Have_claim); } continue; } if (pno <= 1) continue; /* init dies before never */ printf("%3d: stop error, ", depth); printf("proc %d (i=%d) trans %d, %c\n", - pno, i, nst, dothis->n->ntyp); + pno - Have_claim, i, nst, dothis->n->ntyp); lost_trail(); } for (X = run; X; X = X->nxt) @@ -141,20 +192,20 @@ break; } if (!X) - { printf("%3d: no process %d ", depth, pno); + { printf("%3d: no process %d ", depth, pno - Have_claim); printf("(state %d)\n", nst); lost_trail(); } X->pc = dothis; lineno = dothis->n->ln; Fname = dothis->n->fn; - oX = X; /* a rendezvous could change it */ + if (dothis->n->ntyp == D_STEP) { Element *g, *og = dothis; do { g = eval_sub(og); if (g && depth >= jumpsteps - && ((verbose&32) || (verbose&4))) + && ((verbose&32) || ((verbose&4) && not_claim()))) { if (columns != 2) { p_talk(og, 1); @@ -171,18 +222,19 @@ } og = g; } while (g && g != dothis->nxt); - X->pc = g?huntele(g, 0):g; + X->pc = g?huntele(g, 0, -1):g; } else { -keepgoing: X->pc = eval_sub(dothis); - X->pc = huntele(X->pc, 0); - if (dothis->merge_start) +keepgoing: if (dothis->merge_start) a = dothis->merge_start; else a = dothis->merge; + X->pc = eval_sub(dothis); + if (X->pc) X->pc = huntele(X->pc, 0, a); + if (depth >= jumpsteps - && ((verbose&32) || (verbose&4))) + && ((verbose&32) || ((verbose&4) && not_claim()))) /* -v or -p */ { if (columns != 2) { p_talk(dothis, 1); @@ -201,12 +253,17 @@ if (verbose&1) dumpglobals(); if (verbose&2) dumplocal(X); if (xspin) printf("\n"); + + if (!X->pc) + { X->pc = dothis; + printf("\ttransition failed\n"); + a = 0; /* avoid inf loop */ + } } if (a && X->pc && X->pc->seqno != a) { dothis = X->pc; goto keepgoing; - } - } + } } if (Have_claim && X && X->pid == 0 && dothis && dothis->n @@ -221,8 +278,7 @@ printf("Never claim moves to line %d\t[", lastclaim); comment(stdout, dothis->n, 0); printf("]\n"); - } - } } + } } } printf("spin: trail ends after %d steps\n", depth); wrapup(0); } --- /sys/src/cmd/spin/main.c Wed Aug 31 04:21:19 2005 +++ /sys/src/cmd/spin/main.c Wed Aug 31 04:21:18 2005 @@ -1,14 +1,13 @@ /***** spin: main.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include #include "spin.h" @@ -19,6 +18,9 @@ #ifdef PC #include #include "y_tab.h" + +extern int unlink(const char *); + #else #include #include "y.tab.h" @@ -28,18 +30,26 @@ extern FILE *yyin, *yyout, *tl_out; extern Symbol *context; extern char *claimproc; +extern void repro_src(void); extern void qhide(int); Symbol *Fname, *oFname; -int Etimeouts=0; /* nr timeouts in program */ -int Ntimeouts=0; /* nr timeouts in never claim */ -int analyze=0, columns=0, dumptab=0, has_remote=0; -int interactive=0, jumpsteps=0, m_loss=0, nr_errs=0; -int s_trail=0, ntrail=0, verbose=0, xspin=0, no_print=0, no_wrapup = 0, Caccess=0; -int limited_vis=0, like_java=0; -int dataflow = 1, merger = 1, deadvar = 1, rvopt = 0, ccache = 1; -int separate = 0; /* separate compilation option */ +int Etimeouts; /* nr timeouts in program */ +int Ntimeouts; /* nr timeouts in never claim */ +int analyze, columns, dumptab, has_remote, has_remvar; +int interactive, jumpsteps, m_loss, nr_errs, cutoff; +int s_trail, ntrail, verbose, xspin, notabs, rvopt; +int no_print, no_wrapup, Caccess, limited_vis, like_java; +int separate; /* separate compilation */ +int export_ast; /* pangen5.c */ +int inlineonly; /* show inlined code */ +int seedy; /* be verbose about chosen seed */ + +int dataflow = 1, merger = 1, deadvar = 1, ccache = 1; + +static int preprocessonly, SeedUsed; + #if 0 meaning of flags on verbose: 1 -g global variable values @@ -51,8 +61,6 @@ 64 -w very verbose #endif -static Element *Same; -static int IsAsgn = 0, OrIsAsgn = 0; static char Operator[] = "operator: "; static char Keyword[] = "keyword: "; static char Function[] = "function-name: "; @@ -68,27 +76,35 @@ /* OS2: "spin -Picc -E/Pd+ -E/Q+" */ /* Visual C++: "spin -PCL -E/E */ #ifdef PC -#define CPP "cpp" /* or specify a full path */ +#define CPP "gcc -E -x c" /* most systems have gcc anyway */ + /* else use "cpp" */ #else #ifdef SOLARIS #define CPP "/usr/ccs/lib/cpp" #else -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__OpenBSD__) #define CPP "cpp" #else -#define CPP "/bin/cpp" +#define CPP "/bin/cpp" /* classic Unix systems */ #endif #endif #endif #endif static char *PreProc = CPP; +extern int depth; /* at least some steps were made */ void alldone(int estatus) { - if (strlen(out1) > 0) + if (preprocessonly == 0 + && strlen(out1) > 0) (void) unlink((const char *)out1); + + if (seedy && !analyze && !export_ast + && !s_trail && !preprocessonly && depth > 0) + printf("seed used: %d\n", SeedUsed); + if (xspin && (analyze || s_trail)) { if (estatus) printf("spin: %d error(s) - aborting\n", @@ -101,10 +117,10 @@ void preprocess(char *a, char *b, int a_tmp) -{ char precmd[128], cmd[256]; int i; +{ char precmd[512], cmd[1024]; int i; #ifdef PC extern int try_zpp(char *, char *); - if (try_zpp(a, b)) goto out; + if (PreCnt == 0 && try_zpp(a, b)) goto out; #endif strcpy(precmd, PreProc); for (i = 1; i <= PreCnt; i++) @@ -115,9 +131,13 @@ if (system((const char *)cmd)) { (void) unlink((const char *) b); if (a_tmp) (void) unlink((const char *) a); - alldone(1); /* failed */ + fprintf(stdout, "spin: preprocessing failed\n"); /* 4.1.2 was stderr */ + alldone(1); /* no return, error exit */ } -out: if (a_tmp) (void) unlink((const char *) a); +#ifdef PC +out: +#endif + if (a_tmp) (void) unlink((const char *) a); } FILE * @@ -142,10 +162,11 @@ { printf("use: spin [-option] ... [-option] file\n"); printf("\tNote: file must always be the last argument\n"); + printf("\t-A apply slicing algorithm\n"); printf("\t-a generate a verifier in pan.c\n"); printf("\t-B no final state details in simulations\n"); printf("\t-b don't execute printfs in simulation\n"); - printf("\t-C print channel access info (structview)\n"); + printf("\t-C print channel access info (combine with -g etc.)\n"); printf("\t-c columnated -s -r simulation output\n"); printf("\t-d produce symbol-table information\n"); printf("\t-Dyyy pass -Dyyy to the preprocessor\n"); @@ -155,7 +176,9 @@ printf("\t-F file like -f, but with the LTL "); printf("formula stored in a 1-line file\n"); printf("\t-g print all global variables\n"); + printf("\t-h at end of run, print value of seed for random nr generator used\n"); printf("\t-i interactive (random simulation)\n"); + printf("\t-I show result of inlining and preprocessing\n"); printf("\t-J reverse eval order of nested unlesses\n"); printf("\t-jN skip the first N steps "); printf("in simulation trail\n"); @@ -165,16 +188,20 @@ printf("\t-N file use never claim stored in file\n"); printf("\t-nN seed for random nr generator\n"); printf("\t-o1 turn off dataflow-optimizations in verifier\n"); - printf("\t-o2 turn off dead variables elimination in verifier\n"); + printf("\t-o2 don't hide write-only variables in verifier\n"); printf("\t-o3 turn off statement merging in verifier\n"); printf("\t-Pxxx use xxx for preprocessing\n"); printf("\t-p print all statements\n"); printf("\t-qN suppress io for queue N in printouts\n"); printf("\t-r print receive events\n"); + printf("\t-S1 and -S2 separate pan source for claim and model\n"); printf("\t-s print send events\n"); + printf("\t-T do not indent printf output\n"); + printf("\t-t[N] follow [Nth] simulation trail\n"); + printf("\t-Uyyy pass -Uyyy to the preprocessor\n"); + printf("\t-uN stop a simulation run after N steps\n"); printf("\t-v verbose, more warnings\n"); printf("\t-w very verbose (when combined with -l or -g)\n"); - printf("\t-t[N] follow [Nth] simulation trail\n"); printf("\t-[XYZ] reserved for use by xspin interface\n"); printf("\t-V print version number and exit\n"); alldone(1); @@ -226,9 +253,34 @@ } } +#if 0 +static int +Rename(const char *old, char *new) +{ FILE *fo, *fn; + char buf[1024]; + + if ((fo = fopen(old, "r")) == NULL) + { printf("spin: cannot open %s\n", old); + return 1; + } + if ((fn = fopen(new, "w")) == NULL) + { printf("spin: cannot create %s\n", new); + fclose(fo); + return 2; + } + while (fgets(buf, 1024, fo)) + fputs(buf, fn); + + fclose(fo); + fclose(fn); + + return 0; /* success */ +} +#endif + int main(int argc, char *argv[]) -{ Symbol *s; int preprocessonly = 0; +{ Symbol *s; int T = (int) time((time_t *)0); int usedopts = 0; extern void ana_src(int, int); @@ -244,14 +296,15 @@ /* generate code for separate compilation: S1 or S2 */ case 'S': separate = atoi(&argv[1][2]); /* fall through */ - case 'a': analyze = 1; break; + + case 'A': export_ast = 1; break; case 'B': no_wrapup = 1; break; case 'b': no_print = 1; break; case 'C': Caccess = 1; break; case 'c': columns = 1; break; case 'D': PreArg[++PreCnt] = (char *) &argv[1][0]; - break; + break; /* define */ case 'd': dumptab = 1; break; case 'E': PreArg[++PreCnt] = (char *) &argv[1][2]; break; @@ -260,7 +313,9 @@ case 'f': add_ltl = (char **) argv; argc--; argv++; break; case 'g': verbose += 1; break; + case 'h': seedy = 1; break; case 'i': interactive = 1; break; + case 'I': inlineonly = 1; break; case 'J': like_java = 1; break; case 'j': jumpsteps = atoi(&argv[1][2]); break; case 'l': verbose += 2; break; @@ -278,16 +333,20 @@ break; case 'r': verbose += 8; break; case 's': verbose += 16; break; + case 'T': notabs = 1; break; case 't': s_trail = 1; if (isdigit(argv[1][2])) ntrail = atoi(&argv[1][2]); break; + case 'U': PreArg[++PreCnt] = (char *) &argv[1][0]; + break; /* undefine */ + case 'u': cutoff = atoi(&argv[1][2]); break; /* new 3.4.14 */ case 'v': verbose += 32; break; case 'V': printf("%s\n", Version); alldone(0); break; case 'w': verbose += 64; break; - case 'X': xspin = 1; + case 'X': xspin = notabs = 1; #ifndef PC signal(SIGPIPE, alldone); /* not posix... */ #endif @@ -316,20 +375,13 @@ } if (argc > 1) { char cmd[128], out2[64]; -#ifdef PC - strcpy(out1, "_tmp1_"); - strcpy(out2, "_tmp2_"); -#else - /* extern char *tmpnam(char *); in stdio.h */ + + /* must remain in current dir */ + strcpy(out1, "pan.pre"); + if (add_ltl || nvr_file) - { /* must remain in current dir */ - strcpy(out1, "_tmp1_"); - strcpy(out2, "_tmp2_"); - } else - { (void) tmpnam(out1); - (void) tmpnam(out2); - } -#endif + strcpy(out2, "pan.___"); + if (add_ltl) { tl_out = cpyfile(argv[1], out2); nr_errs = tl_main(2, add_ltl); /* in tl_main.c */ @@ -353,13 +405,8 @@ preprocess(argv[1], out1, 0); if (preprocessonly) - { (void) unlink("pan.pre"); /* remove old version */ - if (rename((const char *) out1, "pan.pre") != 0) - { printf("spin: rename %s failed\n", out1); - alldone(1); - } alldone(0); - } + if (!(yyin = fopen(out1, "r"))) { printf("spin: cannot open %s\n", out1); alldone(1); @@ -372,7 +419,7 @@ strcpy(cmd, argv[1]); oFname = Fname = lookup(cmd); if (oFname->name[0] == '\"') - { int i = strlen(oFname->name); + { int i = (int) strlen(oFname->name); oFname->name[i-1] = '\0'; oFname = lookup(&oFname->name[1]); } @@ -401,19 +448,30 @@ if (columns == 2 && limited_vis) verbose += (1+4); Srand(T); /* defined in run.c */ - s = lookup("_"); s->type = PREDEF; /* a write only global var */ + SeedUsed = T; + s = lookup("_"); s->type = PREDEF; /* write-only global var */ s = lookup("_p"); s->type = PREDEF; s = lookup("_pid"); s->type = PREDEF; s = lookup("_last"); s->type = PREDEF; s = lookup("_nr_pr"); s->type = PREDEF; /* new 3.3.10 */ + yyparse(); fclose(yyin); + loose_ends(); + + if (inlineonly) + { repro_src(); + return 0; + } + chanaccess(); - if (!s_trail && (dataflow || merger)) - ana_src(dataflow, merger); - sched(); - alldone(nr_errs); - return 0; /* can't get here */ + if (!Caccess) + { if (!s_trail && (dataflow || merger)) + ana_src(dataflow, merger); + sched(); + alldone(nr_errs); + } + return 0; } int @@ -463,7 +521,7 @@ } void -trapwonly(Lextok *n, char *s) +trapwonly(Lextok *n, char *unused) { extern int realread; short i = (n->sym)?n->sym->type:0; @@ -502,6 +560,7 @@ Lextok * nn(Lextok *s, int t, Lextok *ll, Lextok *rl) { Lextok *n = (Lextok *) emalloc(sizeof(Lextok)); + static int warn_nn = 0; n->ntyp = (short) t; if (s && s->fn) @@ -558,6 +617,9 @@ } } forbidden = 0; break; + case 'c': + AST_track(n, 0); /* register as a slice criterion */ + /* fall thru */ default: forbidden = 0; break; @@ -566,27 +628,62 @@ { printf("spin: never, saw "); explain(t); printf("\n"); fatal("incompatible with separate compilation",(char *)0); } - } else if (t == ENABLED || t == PC_VAL) - { printf("spin: Warning, using %s outside never-claim\n", + } else if ((t == ENABLED || t == PC_VAL) && !(warn_nn&t)) + { printf("spin: Warning, using %s outside never claim\n", (t == ENABLED)?"enabled()":"pc_value()"); + warn_nn |= t; } else if (t == NONPROGRESS) - { fatal("spin: Error, using np_ outside never-claim\n", (char *)0); + { fatal("spin: Error, using np_ outside never claim\n", (char *)0); } return n; } Lextok * -rem_lab(Symbol *a, Lextok *b, Symbol *c) +rem_lab(Symbol *a, Lextok *b, Symbol *c) /* proctype name, pid, label name */ { Lextok *tmp1, *tmp2, *tmp3; has_remote++; - fix_dest(c, a); /* in case target is jump */ + c->type = LABEL; /* refered to in global context here */ + fix_dest(c, a); /* in case target of rem_lab is jump */ tmp1 = nn(ZN, '?', b, ZN); tmp1->sym = a; tmp1 = nn(ZN, 'p', tmp1, ZN); tmp1->sym = lookup("_p"); tmp2 = nn(ZN, NAME, ZN, ZN); tmp2->sym = a; tmp3 = nn(ZN, 'q', tmp2, ZN); tmp3->sym = c; return nn(ZN, EQ, tmp1, tmp3); +#if 0 + .---------------EQ-------. + / \ + 'p' -sym-> _p 'q' -sym-> c (label name) + / / + '?' -sym-> a (proctype) NAME -sym-> a (proctype name) + / + b (pid expr) +#endif +} + +Lextok * +rem_var(Symbol *a, Lextok *b, Symbol *c, Lextok *ndx) +{ Lextok *tmp1; + + has_remote++; + has_remvar++; + dataflow = 0; /* turn off dead variable resets 4.2.5 */ + tmp1 = nn(ZN, '?', b, ZN); tmp1->sym = a; + tmp1 = nn(ZN, 'p', tmp1, ndx); + tmp1->sym = c; + return tmp1; +#if 0 + cannot refer to struct elements + only to scalars and arrays + + 'p' -sym-> c (variable name) + / \______ possible arrayindex on c + / + '?' -sym-> a (proctype) + / + b (pid expr) +#endif } static void @@ -594,8 +691,8 @@ { FILE *fd = stdout; switch (n) { default: if (n > 0 && n < 256) - fprintf(fd, "%c' = '", n); - fprintf(fd, "%d", n); + fprintf(fd, "'%c' = '", n); + fprintf(fd, "%d'", n); break; case '\b': fprintf(fd, "\\b"); break; case '\t': fprintf(fd, "\\t"); break; @@ -614,10 +711,16 @@ case ASSERT: fprintf(fd, "%sassert", Function); break; case ATOMIC: fprintf(fd, "%satomic", Keyword); break; case BREAK: fprintf(fd, "%sbreak", Keyword); break; + case C_CODE: fprintf(fd, "%sc_code", Keyword); break; + case C_DECL: fprintf(fd, "%sc_decl", Keyword); break; + case C_EXPR: fprintf(fd, "%sc_expr", Keyword); break; + case C_STATE: fprintf(fd, "%sc_state",Keyword); break; + case C_TRACK: fprintf(fd, "%sc_track",Keyword); break; case CLAIM: fprintf(fd, "%snever", Keyword); break; case CONST: fprintf(fd, "a constant"); break; case DECR: fprintf(fd, "%s--", Operator); break; case D_STEP: fprintf(fd, "%sd_step", Keyword); break; + case D_PROCTYPE: fprintf(fd, "%sd_proctype", Keyword); break; case DO: fprintf(fd, "%sdo", Keyword); break; case DOT: fprintf(fd, "."); break; case ELSE: fprintf(fd, "%selse", Keyword); break; @@ -630,11 +733,13 @@ case GE: fprintf(fd, "%s>=", Operator); break; case GOTO: fprintf(fd, "%sgoto", Keyword); break; case GT: fprintf(fd, "%s>", Operator); break; + case HIDDEN: fprintf(fd, "%shidden", Keyword); break; case IF: fprintf(fd, "%sif", Keyword); break; case INCR: fprintf(fd, "%s++", Operator); break; case INAME: fprintf(fd, "inline name"); break; case INLINE: fprintf(fd, "%sinline", Keyword); break; case INIT: fprintf(fd, "%sinit", Keyword); break; + case ISLOCAL: fprintf(fd, "%slocal", Keyword); break; case LABEL: fprintf(fd, "a label-name"); break; case LE: fprintf(fd, "%s<=", Operator); break; case LEN: fprintf(fd, "%slen", Function); break; @@ -655,15 +760,20 @@ case PC_VAL: fprintf(fd, "%spc_value",Function); break; case PNAME: fprintf(fd, "process name"); break; case PRINT: fprintf(fd, "%sprintf", Function); break; + case PRINTM: fprintf(fd, "%sprintm", Function); break; + case PRIORITY: fprintf(fd, "%spriority", Keyword); break; case PROCTYPE: fprintf(fd, "%sproctype",Keyword); break; + case PROVIDED: fprintf(fd, "%sprovided",Keyword); break; case RCV: fprintf(fd, "%s?", Operator); break; case R_RCV: fprintf(fd, "%s??", Operator); break; case RSHIFT: fprintf(fd, "%s>>", Operator); break; case RUN: fprintf(fd, "%srun", Operator); break; case SEP: fprintf(fd, "token: ::"); break; case SEMI: fprintf(fd, ";"); break; + case SHOW: fprintf(fd, "%sshow", Keyword); break; case SND: fprintf(fd, "%s!", Operator); break; case STRING: fprintf(fd, "a string"); break; + case TRACE: fprintf(fd, "%strace", Keyword); break; case TIMEOUT: fprintf(fd, "%stimeout",Keyword); break; case TYPE: fprintf(fd, "data typename"); break; case TYPEDEF: fprintf(fd, "%stypedef",Keyword); break; --- /sys/src/cmd/spin/mesg.c Wed Aug 31 04:21:28 2005 +++ /sys/src/cmd/spin/mesg.c Wed Aug 31 04:21:26 2005 @@ -1,14 +1,13 @@ /***** spin: mesg.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" #ifdef PC @@ -17,7 +16,9 @@ #include "y.tab.h" #endif +#ifndef MAXQ #define MAXQ 2500 /* default max # queues */ +#endif extern RunList *X; extern Symbol *Fname; @@ -58,7 +59,7 @@ qmake(Symbol *s) { Lextok *m; Queue *q; - int i; extern int analyze; + int i; if (!s->ini) return 0; @@ -370,10 +371,13 @@ || strcmp(m->lft->sym->name, "_") != 0) i = eval(m->lft); else i = 0; + + if (verbose&8) sr_talk(n_rem,i,"Recv ","<-",j,q_rem); } + if (verbose&8) for (i = j; i < q->nflds; i++) - sr_talk(n_rem, 0, "Recv ", "<-", j, q_rem); + sr_talk(n_rem, 0, "Recv ", "<-", j, q_rem); if (columns == 2) putarrow(depth, depth); } @@ -385,7 +389,7 @@ void channm(Lextok *n) -{ char lbuf[256]; +{ char lbuf[512]; if (n->sym->type == CHAN) strcat(Buf, n->sym->name); @@ -397,6 +401,7 @@ r = findloc(r); ini_struct(r); printf("%s", r->name); + strcpy(lbuf, ""); struct_name(n->lft, r, 1, lbuf); strcat(Buf, lbuf); } else @@ -409,8 +414,7 @@ static void difcolumns(Lextok *n, char *tr, int v, int j, Queue *q) -{ int cnt = 1; extern int pno; - Lextok *nn = ZN; +{ extern int pno; if (j == 0) { Buf[0] = '\0'; @@ -534,7 +538,7 @@ void sr_buf(int v, int j) { int cnt = 1; Lextok *n; - char lbuf[128]; + char lbuf[256]; for (n = Mtype; n && j; n = n->rgt, cnt++) if (cnt == v) @@ -594,7 +598,16 @@ { int e = 1; if (d == 0 && p->sym && p->sym->type == CHAN) - setaccess(p->sym, ZS, 0, 'L'); + { setaccess(p->sym, ZS, 0, 'L'); + + if (n && n->ntyp == CONST) + fatal("invalid asgn to chan", (char *) 0); + + if (n && n->sym && n->sym->type == CHAN) + { setaccess(n->sym, ZS, 0, 'V'); + return; + } + } if (!n || n->ntyp == LEN || n->ntyp == RUN) return; --- /sys/src/cmd/spin/mkfile Wed Aug 31 04:21:38 2005 +++ /sys/src/cmd/spin/mkfile Wed Aug 31 04:21:37 2005 @@ -13,8 +13,10 @@ pangen3.$O\ pangen4.$O\ pangen5.$O\ + pangen6.$O\ pc_zpp.$O\ ps_msc.$O\ + reprosrc.$O\ run.$O\ sched.$O\ spinlex.$O\ @@ -51,4 +53,4 @@ main.$O pangen2.$O ps_msc.$O: version.h pangen1.$O: pangen1.h pangen3.h -pangen2.$O: pangen2.h pangen4.h pangen5.h +pangen2.$O: pangen2.h pangen4.h pangen5.h --- /sys/src/cmd/spin/pangen1.c Wed Aug 31 04:21:49 2005 +++ /sys/src/cmd/spin/pangen1.c Wed Aug 31 04:21:47 2005 @@ -1,14 +1,13 @@ /***** spin: pangen1.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" #ifdef PC @@ -29,7 +28,9 @@ extern int nrRdy, nqs, mst, Mpars, claimnr, eventmapnr; extern short has_sorted, has_random, has_provided; -int Npars=0, u_sync=0, u_async=0; +int Npars=0, u_sync=0, u_async=0, hastrack = 1; +short has_io = 0; +short has_state=0; /* code contains c_state */ static Symbol *LstSet=ZS; static int acceptors=0, progressors=0, nBits=0; @@ -56,7 +57,10 @@ genheader(void) { ProcList *p; int i; - if (separate == 2) goto here; + if (separate == 2) + { putunames(th); + goto here; + } fprintf(th, "#define SYNC %d\n", u_sync); fprintf(th, "#define ASYNC %d\n\n", u_async); @@ -82,29 +86,39 @@ ntimes(th, 0, 1, Head0); - if (separate == 2) - { ntimes(th, 0, 1, Head1); - LstSet = ZS; - (void) doglobal("", PUTV); - fprintf(th, " uchar sv[VECTORSZ];\n"); - fprintf(th, "} State;\n\n"); - } else - { + if (separate != 2) + { extern void c_add_stack(FILE *); + ntimes(th, 0, 1, Header); - ntimes(th, 0, 1, Head1); + c_add_stack(th); + ntimes(th, 0, 1, Header0); + } + ntimes(th, 0, 1, Head1); - LstSet = ZS; - (void) doglobal("", PUTV); - fprintf(th, " uchar sv[VECTORSZ];\n"); - fprintf(th, "} State;\n\n"); + LstSet = ZS; + (void) doglobal("", PUTV); + + hastrack = c_add_sv(th); + + fprintf(th, " uchar sv[VECTORSZ];\n"); + fprintf(th, "} State"); +#ifdef SOLARIS + fprintf(th,"\n#ifdef GCC\n"); + fprintf(th, "\t__attribute__ ((aligned(8)))"); + fprintf(th, "\n#endif\n\t"); +#endif + fprintf(th, ";\n\n"); + + fprintf(th, "#define HAS_TRACK %d\n", hastrack); + + if (separate != 2) dohidden(); - } } void genaddproc(void) { ProcList *p; - int i; + int i = 0; if (separate ==2) goto shortcut; @@ -117,7 +131,7 @@ ntimes(tc, 0, 1, Addp1); if (has_provided) - { fprintf(tt, "\nint\nprovided(int II, int ot, "); + { fprintf(tt, "\nint\nprovided(int II, unsigned char ot, "); fprintf(tt, "int tt, Trans *t)\n"); fprintf(tt, "{\n\tswitch(ot) {\n"); } @@ -144,6 +158,14 @@ } void +do_locinits(FILE *fd) +{ ProcList *p; + + for (p = rdy; p; p = p->nxt) + c_add_locinit(fd, p->tn, p->n->name); +} + +void genother(void) { ProcList *p; @@ -190,7 +212,9 @@ ntimes(th, nrRdy+1, nrRdy+2, R2); /* +1 for np_ */ fprintf(tc, " iniglobals();\n"); - ntimes(tc, 0, 1, Code2); + ntimes(tc, 0, 1, Code2a); + ntimes(tc, 0, 1, Code2b); /* bfs option */ + ntimes(tc, 0, 1, Code2c); ntimes(tc, 0, nrRdy, R4); fprintf(tc, "}\n\n"); @@ -245,7 +269,7 @@ ln[j].s); goto complain; } - if (l->e->status & ATOM) + if (j > 0 && (l->e->status & ATOM)) { sprintf(foo, "%s label inside atomic", ln[j].s); complain: lineno = l->e->n->ln; @@ -317,7 +341,7 @@ } else if (!(sp->hidden&4)) { if (!(verbose&32)) return; sputtype(buf, sp->type); - i = strlen(buf); + i = (int) strlen(buf); while (buf[--i] == ' ') buf[i] = '\0'; prehint(sp); if (sp->context) @@ -329,7 +353,7 @@ } else if (sp->type != BYTE && !(sp->hidden&8)) { if (!(verbose&32)) return; sputtype(buf, sp->type); - i = strlen(buf); + i = (int) strlen(buf); while (buf[--i] == ' ') buf[i] = '\0'; prehint(sp); if (sp->context) @@ -342,7 +366,7 @@ } int -dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s, char *how) +dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s) { int h, j, k=0; extern int nr_errs; Ordered *walk; Symbol *sp; @@ -364,7 +388,7 @@ break; sprintf(buf, "%s%s:", pre, s); { sprintf(buf2, "\", ((P%d *)pptr(h))->", p); - sprintf(buf3, ");\n", p); + sprintf(buf3, ");\n"); } do_var(ofd, dowhat, "", sp, buf, buf2, buf3); break; @@ -385,6 +409,160 @@ return k; } +void +c_chandump(FILE *fd) +{ Queue *q; + char buf[256]; + int i; + + if (!qtab) + { fprintf(fd, "void\nc_chandump(int unused) "); + fprintf(fd, "{ unused = unused++; /* avoid complaints */ }\n"); + return; + } + + fprintf(fd, "void\nc_chandump(int from)\n"); + fprintf(fd, "{ uchar *z; int slot;\n"); + + fprintf(fd, " from--;\n"); + fprintf(fd, " if (from >= (int) now._nr_qs || from < 0)\n"); + fprintf(fd, " { printf(\"pan: bad qid %%d\\n\", from+1);\n"); + fprintf(fd, " return;\n"); + fprintf(fd, " }\n"); + fprintf(fd, " z = qptr(from);\n"); + fprintf(fd, " switch (((Q0 *)z)->_t) {\n"); + + for (q = qtab; q; q = q->nxt) + { fprintf(fd, " case %d:\n\t\t", q->qid); + sprintf(buf, "((Q%d *)z)->", q->qid); + + fprintf(fd, "for (slot = 0; slot < %sQlen; slot++)\n\t\t", buf); + fprintf(fd, "{ printf(\" [\");\n\t\t"); + for (i = 0; i < q->nflds; i++) + { if (q->fld_width[i] == MTYPE) + { fprintf(fd, "\tprintm(%scontents[slot].fld%d);\n\t\t", + buf, i); + } else + fprintf(fd, "\tprintf(\"%%d,\", %scontents[slot].fld%d);\n\t\t", + buf, i); + } + fprintf(fd, " printf(\"],\");\n\t\t"); + fprintf(fd, "}\n\t\t"); + fprintf(fd, "break;\n"); + } + fprintf(fd, " }\n"); + fprintf(fd, " printf(\"\\n\");\n}\n"); +} + +void +c_var(FILE *fd, char *pref, Symbol *sp) +{ char buf[256]; + int i; + + switch (sp->type) { + case STRUCT: + /* c_struct(fd, pref, sp); */ + fprintf(fd, "\t\tprintf(\"\t(struct %s)\\n\");\n", + sp->name); + sprintf(buf, "%s%s.", pref, sp->name); + c_struct(fd, buf, sp); + break; + case BIT: case BYTE: + case SHORT: case INT: + case UNSIGNED: + sputtype(buf, sp->type); + if (sp->nel == 1) + fprintf(fd, "\tprintf(\"\t%s %s:\t%%d\\n\", %s%s);\n", + buf, sp->name, pref, sp->name); + else + for (i = 0; i < sp->nel; i++) + fprintf(fd, "\tprintf(\"\t%s %s[%d]:\t%%d\\n\", %s%s[%d]);\n", + buf, sp->name, i, pref, sp->name, i); + break; + case CHAN: + if (sp->nel == 1) + { fprintf(fd, "\tprintf(\"\tchan %s (=%%d):\tlen %%d:\\t\", ", + sp->name); + fprintf(fd, "%s%s, q_len(%s%s));\n", + pref, sp->name, pref, sp->name); + fprintf(fd, "\tc_chandump(%s%s);\n", pref, sp->name); + } else + for (i = 0; i < sp->nel; i++) + { fprintf(fd, "\tprintf(\"\tchan %s[%d] (=%%d):\tlen %%d:\\t\", ", + sp->name, i); + fprintf(fd, "%s%s[%d], q_len(%s%s[%d]));\n", + pref, sp->name, i, pref, sp->name, i); + fprintf(fd, "\tc_chandump(%s%s[%d]);\n", + pref, sp->name, i); + } + break; + } +} + +void +c_splurge(FILE *fd, ProcList *p) +{ Ordered *walk; + Symbol *sp; + char pref[64]; + + if (strcmp(p->n->name, ":never:") != 0 + && strcmp(p->n->name, ":trace:") != 0 + && strcmp(p->n->name, ":notrace:") != 0) + for (walk = all_names; walk; walk = walk->next) + { sp = walk->entry; + if (!sp->context + || strcmp(sp->context->name, p->n->name) != 0 + || sp->owner || (sp->hidden&1) + || (sp->type == MTYPE && ismtype(sp->name))) + continue; + + sprintf(pref, "((P%d *)pptr(pid))->", p->tn); + c_var(fd, pref, sp); + } +} + +void +c_wrapper(FILE *fd) /* allow pan.c to print out global sv entries */ +{ Ordered *walk; + ProcList *p; + Symbol *sp; + Lextok *n; + extern Lextok *Mtype; + int j; + + fprintf(fd, "void\nc_globals(void)\n{\t/* int i; */\n"); + fprintf(fd, " printf(\"global vars:\\n\");\n"); + for (walk = all_names; walk; walk = walk->next) + { sp = walk->entry; + if (sp->context || sp->owner || (sp->hidden&1) + || (sp->type == MTYPE && ismtype(sp->name))) + continue; + + c_var(fd, "now.", sp); + } + fprintf(fd, "}\n"); + + fprintf(fd, "void\nc_locals(int pid, int tp)\n{\t/* int i; */\n"); + fprintf(fd, " switch(tp) {\n"); + for (p = rdy; p; p = p->nxt) + { fprintf(fd, " case %d:\n", p->tn); + fprintf(fd, " \tprintf(\"local vars proc %%d (%s):\\n\", pid);\n", + p->n->name); + c_splurge(fd, p); + fprintf(fd, " \tbreak;\n"); + } + fprintf(fd, " }\n}\n"); + + fprintf(fd, "void\nprintm(int x)\n{\n"); + fprintf(fd, " switch (x) {\n"); + for (n = Mtype, j = 1; n && j; n = n->rgt, j++) + fprintf(fd, "\tcase %d: Printf(\"%s\"); break;\n", + j, n->lft->sym->name); + fprintf(fd, " default: Printf(\"%%d\", x);\n"); + fprintf(fd, " }\n"); + fprintf(fd, "}\n"); +} + static int doglobal(char *pre, int dowhat) { Ordered *walk; @@ -396,7 +574,6 @@ { sp = walk->entry; if (!sp->context && !sp->owner - /* && !(sp->hidden&1) */ && sp->type == Types[j]) { if (Types[j] != MTYPE || !ismtype(sp->name)) switch (dowhat) { @@ -513,15 +690,29 @@ put_ptype(char *s, int i, int m0, int m1) { int k; + if (strcmp(s, ":init:") == 0) + fprintf(th, "#define Pinit ((P%d *)this)\n", i); + + if (strcmp(s, ":never:") != 0 + && strcmp(s, ":trace:") != 0 + && strcmp(s, ":notrace:") != 0 + && strcmp(s, ":init:") != 0 + && strcmp(s, "_:never_template:_") != 0 + && strcmp(s, "np_") != 0) + fprintf(th, "#define P%s ((P%d *)this)\n", s, i); + fprintf(th, "typedef struct P%d { /* %s */\n", i, s); fprintf(th, " unsigned _pid : 8; /* 0..255 */\n"); fprintf(th, " unsigned _t : %d; /* proctype */\n", blog(m1)); fprintf(th, " unsigned _p : %d; /* state */\n", blog(m0)); LstSet = ZS; nBits = 8 + blog(m1) + blog(m0); - k = dolocal(tc, "", PUTV, i, s, ""); /* includes pars */ + k = dolocal(tc, "", PUTV, i, s); /* includes pars */ + + c_add_loc(th, s); + fprintf(th, "} P%d;\n", i); - if (!LstSet && k > 0) + if ((!LstSet && k > 0) || has_state) fprintf(th, "#define Air%d 0\n", i); else { fprintf(th, "#define Air%d (sizeof(P%d) - ", i, i); @@ -531,15 +722,8 @@ } if ((LstSet->type != BIT && LstSet->type != UNSIGNED) || LstSet->nel != 1) - { fprintf(th, "Offsetof(P%d, %s%s) - %d*sizeof(", - i, - LstSet->name, -#if 1 - "", -#else - (LstSet->nel > 1)?"[0]":"", -#endif - LstSet->nel); + { fprintf(th, "Offsetof(P%d, %s) - %d*sizeof(", + i, LstSet->name, LstSet->nel); } switch(LstSet->type) { case UNSIGNED: @@ -608,7 +792,7 @@ && separate == 2) return; - ini = huntele(e, e->status)->seqno; + ini = huntele(e, e->status, -1)->seqno; fprintf(th, "#define start%d %d\n", i, ini); if (i == claimnr) fprintf(th, "#define start_claim %d\n", ini); @@ -648,7 +832,7 @@ { if (full_name(tc, t, t->sym, 1)) { lineno = t->ln; Fname = t->fn; - fatal("hidden array in parameter, %s", + fatal("hidden array in parameter %s", t->sym->name); } } else @@ -656,12 +840,17 @@ fprintf(tc, " = par%d;\n", j); } fprintf(tc, "\t\t/* locals: */\n"); - k = dolocal(tc, "", INIV, i, s->name, ""); + k = dolocal(tc, "", INIV, i, s->name); if (k > 0) { fprintf(tc, "#ifdef VAR_RANGES\n"); - (void) dolocal(tc, "logval(\"", LOGV, i, s->name, ""); + (void) dolocal(tc, "logval(\"", LOGV, i, s->name); fprintf(tc, "#endif\n"); } + + fprintf(tc, "#ifdef HAS_CODE\n"); + fprintf(tc, "\t\tlocinit%d(h);\n", i); + fprintf(tc, "#endif\n"); + dumpclaims(tc, i, s->name); fprintf(tc, "\t break;\n"); } @@ -669,28 +858,35 @@ Element * huntstart(Element *f) { Element *e = f; + Element *elast = (Element *) 0; + int cnt = 0; - if (e->n) - { if (e->n->ntyp == '.' && e->nxt) - e = e->nxt; - else if (e->n->ntyp == ATOMIC - || e->n->ntyp == D_STEP - || e->n->ntyp == NON_ATOMIC) - e->n->sl->this->last->nxt = e->nxt; - else if (e->n->ntyp == UNLESS) - return e->sub->this->frst; - } + while (elast != e && cnt++ < 20) /* new 4.0.8 */ + { elast = e; + if (e->n) + { if (e->n->ntyp == '.' && e->nxt) + e = e->nxt; + else if (e->n->ntyp == UNLESS) + e = e->sub->this->frst; + } } + + if (cnt >= 20 || !e) + fatal("confusing control structure", (char *) 0); return e; } Element * -huntele(Element *f, int o) +huntele(Element *f, int o, int stopat) { Element *g, *e = f; - int cnt; /* a precaution against loops */ + int cnt=0; /* a precaution against loops */ if (e) - for (cnt=0; cnt < 10 && e->n; cnt++) - { switch (e->n->ntyp) { + for (cnt = 0; cnt < 20 && e->n; cnt++) + { + if (e->seqno == stopat) + break; + + switch (e->n->ntyp) { case GOTO: g = get_lab(e->n,1); cross_dsteps(e->n, g->n); @@ -702,19 +898,20 @@ g = e->nxt; break; case UNLESS: - g = huntele(e->sub->this->frst, o); + g = huntele(e->sub->this->frst, o, stopat); break; case D_STEP: case ATOMIC: case NON_ATOMIC: - e->n->sl->this->last->nxt = e->nxt; - default: /* fall through */ + default: return e; } if ((o & ATOM) && !(g->status & ATOM)) return e; e = g; } + if (cnt >= 20 || !e) + fatal("confusing control structure", (char *) 0); return e; } @@ -743,6 +940,7 @@ nBits++; break; } /* else fall through */ + if (!(sp->hidden&1) && (verbose&32)) printf("spin: warning: bit-array %s[%d] mapped to byte-array\n", sp->name, sp->nel); nBits += 8*sp->nel; /* mapped onto array of uchars */ @@ -768,6 +966,7 @@ sp->name); LstSet = ZS; break; + case CODE_FRAG: case PREDEF: return; default: @@ -791,21 +990,48 @@ } void +qlen_type(int qmax) +{ + fprintf(th, "\t"); + if (qmax < 256) + fprintf(th, "uchar"); + else if (qmax < 65535) + fprintf(th, "ushort"); + else + fprintf(th, "uint"); + fprintf(th, " Qlen; /* q_size */\n"); +} + +void genaddqueue(void) { char buf0[256]; - int j; + int j, qmax = 0; Queue *q; ntimes(tc, 0, 1, Addq0); + if (has_io && !nqs) + fprintf(th, "#define NQS 1 /* nqs=%d, but has_io */\n", nqs); + else + fprintf(th, "#define NQS %d\n", nqs); fprintf(th, "short q_flds[%d];\n", nqs+1); fprintf(th, "short q_max[%d];\n", nqs+1); + + for (q = qtab; q; q = q->nxt) + if (q->nslots > qmax) + qmax = q->nslots; + for (q = qtab; q; q = q->nxt) { j = q->qid; fprintf(tc, "\tcase %d: j = sizeof(Q%d);", j, j); fprintf(tc, " q_flds[%d] = %d;", j, q->nflds); fprintf(tc, " q_max[%d] = %d;", j, max(1,q->nslots)); fprintf(tc, " break;\n"); - ntimes(th, j, j+1, R9); + + fprintf(th, "typedef struct Q%d {\n", j); + qlen_type(qmax); /* 4.2.2 */ + fprintf(th, " uchar _t; /* q_type */\n"); + fprintf(th, " struct {\n"); + for (j = 0; j < q->nflds; j++) { switch (q->fld_width[j]) { case BIT: @@ -832,7 +1058,12 @@ fprintf(th, " } contents[%d];\n", max(1, q->nslots)); fprintf(th, "} Q%d;\n", q->qid); } - ntimes(th, 0, 1, R10); + + fprintf(th, "typedef struct Q0 {\t/* generic q */\n"); + qlen_type(qmax); /* 4.2.2 */ + fprintf(th, " uchar _t;\n"); + fprintf(th, "} Q0;\n"); + ntimes(tc, 0, 1, Addq1); if (has_random) @@ -866,6 +1097,7 @@ fprintf(tc, "}\n"); } + fprintf(tc, "#if NQS>0\n"); fprintf(tc, "void\nqsend(int into, int sorted"); for (j = 0; j < Mpars; j++) fprintf(tc, ", int fld%d", j); @@ -879,33 +1111,35 @@ if (q->nslots == 0) /* reset handshake point */ fprintf(tc, "\t\t(trpt+2)->o_m = 0;\n"); - if (has_sorted) - { fprintf(tc, "\t\tif (!sorted) goto append%d;\n", q->qid); - fprintf(tc, "\t\tfor (j = 0; j < %sQlen; j++)\n", buf0); - fprintf(tc, "\t\t{\t/* find insertion point */\n"); - sprintf(buf0, "((Q%d *)z)->contents[j].fld", q->qid); - for (j = 0; j < q->nflds; j++) - { fprintf(tc, "\t\t\tif (fld%d > %s%d) continue;\n", - j, buf0, j); - fprintf(tc, "\t\t\tif (fld%d < %s%d) ", j, buf0, j); - fprintf(tc, "goto found%d;\n\n", q->qid); - } - fprintf(tc, "\t\t}\n"); - fprintf(tc, "\tfound%d:\n", q->qid); - sprintf(buf0, "((Q%d *)z)->", q->qid); - fprintf(tc, "\t\tfor (k = %sQlen - 1; k >= j; k--)\n", buf0); - fprintf(tc, "\t\t{\t/* shift up */\n"); - for (j = 0; j < q->nflds; j++) - { fprintf(tc, "\t\t\t%scontents[k+1].fld%d = ", - buf0, j); - fprintf(tc, "%scontents[k].fld%d;\n", - buf0, j); + if (has_sorted) + { fprintf(tc, "\t\tif (!sorted) goto append%d;\n", q->qid); + fprintf(tc, "\t\tfor (j = 0; j < %sQlen; j++)\n", buf0); + fprintf(tc, "\t\t{\t/* find insertion point */\n"); + sprintf(buf0, "((Q%d *)z)->contents[j].fld", q->qid); + for (j = 0; j < q->nflds; j++) + { fprintf(tc, "\t\t\tif (fld%d > %s%d) continue;\n", + j, buf0, j); + fprintf(tc, "\t\t\tif (fld%d < %s%d) ", j, buf0, j); + fprintf(tc, "goto found%d;\n\n", q->qid); + } + fprintf(tc, "\t\t}\n"); + fprintf(tc, "\tfound%d:\n", q->qid); + sprintf(buf0, "((Q%d *)z)->", q->qid); + fprintf(tc, "\t\tfor (k = %sQlen - 1; k >= j; k--)\n", buf0); + fprintf(tc, "\t\t{\t/* shift up */\n"); + for (j = 0; j < q->nflds; j++) + { fprintf(tc, "\t\t\t%scontents[k+1].fld%d = ", + buf0, j); + fprintf(tc, "%scontents[k].fld%d;\n", + buf0, j); + } + fprintf(tc, "\t\t}\n"); + fprintf(tc, "\tappend%d:\t/* insert in slot j */\n", q->qid); } - fprintf(tc, "\t\t}\n"); - fprintf(tc, "\tappend%d:\t/* insert in slot j */\n", q->qid); - } - fprintf(tc, "\t\t(trpt+1)->bup.oval = j;\n"); + fprintf(tc, "#ifdef HAS_SORTED\n"); + fprintf(tc, "\t\t(trpt+1)->ipt = j;\n"); /* ipt was bup.oval */ + fprintf(tc, "#endif\n"); fprintf(tc, "\t\t%sQlen = %sQlen + 1;\n", buf0, buf0); sprintf(buf0, "((Q%d *)z)->contents[j].fld", q->qid); for (j = 0; j < q->nflds; j++) @@ -939,16 +1173,23 @@ fprintf(tc, "\t\t}\n"); } fprintf(tc, "\t\tif (done)\n"); - fprintf(tc, "\t\t{ j = %sQlen;\n", buf0); - fprintf(tc, "\t\t %sQlen = --j;\n", buf0); - fprintf(tc, "\t\t for (k=slot; kcontents", q->qid); - for (j = 0; j < q->nflds; j++) - { fprintf(tc, "\t%s[k].fld%d = \n", buf0, j); - fprintf(tc, "\t\t%s[k+1].fld%d;\n", buf0, j); - } - fprintf(tc, "\t\t }\n"); + if (q->nslots == 0) + { fprintf(tc, "\t\t{ j = %sQlen - 1;\n", buf0); + fprintf(tc, "\t\t %sQlen = 0;\n", buf0); + sprintf(buf0, "\t\t\t((Q%d *)z)->contents", q->qid); + } else + { fprintf(tc, "\t\t{ j = %sQlen;\n", buf0); + fprintf(tc, "\t\t %sQlen = --j;\n", buf0); + fprintf(tc, "\t\t for (k=slot; kcontents", q->qid); + for (j = 0; j < q->nflds; j++) + { fprintf(tc, "\t%s[k].fld%d = \n", buf0, j); + fprintf(tc, "\t\t%s[k+1].fld%d;\n", buf0, j); + } + fprintf(tc, "\t\t }\n"); + } + for (j = 0; j < q->nflds; j++) fprintf(tc, "%s[j].fld%d = 0;\n", buf0, j); fprintf(tc, "\t\t\tif (fld+1 != %d)\n\t\t\t", q->nflds); --- /sys/src/cmd/spin/pangen1.h Wed Aug 31 04:22:07 2005 +++ /sys/src/cmd/spin/pangen1.h Wed Aug 31 04:22:01 2005 @@ -1,38 +1,45 @@ /***** spin: pangen1.h *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ -static char *Code2[] = { /* the tail of procedure run() */ +static char *Code2a[] = { /* the tail of procedure run() */ "#if defined(VERI) && !defined(NOREDUCE) && !defined(NP)", - " if (!state_tables)", + " if (!state_tables", + "#ifdef HAS_CODE", + " && !readtrail", + "#endif", + " )", " { printf(\"warning: for p.o. reduction to be valid \");", - " printf(\"the never claim must be stutter-closed\\n\");", + " printf(\"the never claim must be stutter-invariant\\n\");", " printf(\"(never claims generated from LTL \");", - " printf(\"formulae are stutter-closed)\\n\");", + " printf(\"formulae are stutter-invariant)\\n\");", " }", "#endif", " UnBlock; /* disable rendez-vous */", - "#ifdef MEMCNT", - " overhead = memcnt;", - "#endif", "#ifdef BITSTATE", - " SS = (uchar *) emalloc(1<<(ssize-3));", +#ifndef POWOW + " if (udmem)", + " { udmem *= 1024L*1024L;", + " SS = (uchar *) emalloc(udmem);", + " bstore = bstore_mod;", + " } else", +#endif + " SS = (uchar *) emalloc(1L<<(ssize-3));", "#else", " hinit();", "#endif", "#if defined(FULLSTACK) && defined(BITSTATE)", " onstack_init();", "#endif", - "#ifdef CNTRSTACK", - " LL = (uchar *) emalloc(1<<(ssize-3));", + "#if defined(CNTRSTACK) && !defined(BFS)", + " LL = (uchar *) emalloc(1L<<(ssize-3));", "#endif", " stack = ( Stack *) emalloc(sizeof(Stack));", " svtack = (Svtack *) emalloc(sizeof(Svtack));", @@ -50,20 +57,26 @@ " now._event = start_event;", " reached[EVENT_TRACE][start_event] = 1;", "#endif", + + "#ifdef HAS_CODE", + " globinit();", + "#endif", + "#ifdef BITSTATE", "go_again:", + "#endif", " do_the_search();", - "#if defined(BITSTATE)", + "#ifdef BITSTATE", " if (--Nrun > 0 && HASH_CONST[++HASH_NR])", " { printf(\"Run %%d:\\n\", HASH_NR);", " wrap_stats();", " printf(\"\\n\");", - " memset(SS, 0, 1<<(ssize-3));", + " memset(SS, 0, 1L<<(ssize-3));", "#if defined(CNTRSTACK)", - " memset(LL, 0, 1<<(ssize-3));", + " memset(LL, 0, 1L<<(ssize-3));", "#endif", "#if defined(FULLSTACK)", " memset((uchar *) S_Tab, 0, ", - " (1<<(ssize-3))*sizeof(struct H_el *));", + " maxdepth*sizeof(struct H_el *));", "#endif", " nstates=nlinks=truncs=truncs2=ngrabs = 0;", " nlost=nShadow=hcmp = 0;", @@ -73,29 +86,42 @@ " }", "#endif", "}", + "#ifdef HAS_PROVIDED", + "int provided(int, uchar, int, Trans *);", + "#endif", #ifndef PRINTF - "#include ", - "void", + "int", "Printf(const char *fmt, ...)", "{ /* Make sure the args to Printf", " * are always evaluated (e.g., they", " * could contain a run stmnt)", - " * but don't generate the output", + " * but do not generate the output", " * during verification runs", " * unless explicitly wanted", " * If this fails on your system", " * compile SPIN itself -DPRINTF", " * and this code is not generated", " */", + "#ifdef HAS_CODE", + " if (readtrail)", + " { va_list args;", + " va_start(args, fmt);", + " vprintf(fmt, args);", + " va_end(args);", + " return 1;", + " }", + "#endif", "#ifdef PRINTF", " va_list args;", " va_start(args, fmt);", " vprintf(fmt, args);", " va_end(args);", "#endif", + " return 1;", "}", #endif + "extern void printm(int);", "#ifndef SC", "#define getframe(i) &trail[i];", @@ -105,7 +131,7 @@ "static int stackwrite;", "static int stackread;", "static Trail frameptr;", - "Trail *" + "Trail *", "getframe(int d)", "{", " if (CNT1 == CNT2)", @@ -119,7 +145,7 @@ " { printf(\"getframe: cannot open %%s\\n\", stackfile);", " wrapup();", " }", - " if (lseek(stackread, d*sizeof(Trail), SEEK_SET) == -1", + " if (lseek(stackread, d* (off_t) sizeof(Trail), SEEK_SET) == -1", " || read(stackread, &frameptr, sizeof(Trail)) != sizeof(Trail))", " { printf(\"getframe: frame read error\\n\");", " wrapup();", @@ -147,10 +173,1064 @@ "#endif", "void", + "pan_exit(int val)", + "{ if (signoff) printf(\"--end of output--\\n\");", + " exit(val);", + "}", + + "#ifdef HAS_CODE", + "char *", + "transmognify(char *s)", + "{ char *v, *w;", + " static char buf[2][2048];", + " int i, toggle = 0;", + + " if (strlen(s) > 2047) return s;", + " memset(buf[0], 0, 2048);", + " memset(buf[1], 0, 2048);", + " strcpy(buf[toggle], s);", + " while ((v = strstr(buf[toggle], \"{c_code\")))", /* assign v */ + " { *v = '\\0'; v++;", + " strcpy(buf[1-toggle], buf[toggle]);", + " for (w = v; *w != '}' && *w != '\\0'; w++) /* skip */;", + " if (*w != '}') return s;", + " *w = '\\0'; w++;", + " for (i = 0; code_lookup[i].c; i++)", + " if (strcmp(v, code_lookup[i].c) == 0", + " && strlen(v) == strlen(code_lookup[i].c))", + " { if (strlen(buf[1-toggle])", + " + strlen(code_lookup[i].t)", + " + strlen(w) > 2047)", + " return s;", + " strcat(buf[1-toggle], code_lookup[i].t);", + " break;", + " }", + " strcat(buf[1-toggle], w);", + " toggle = 1 - toggle;", + " }", + " buf[toggle][2047] = '\\0';", + " return buf[toggle];", + "}", + "#else", + "char * transmognify(char *s) { return s; }", + "#endif", + + "#ifdef HAS_CODE", + "void", + "add_src_txt(int ot, int tt)", + "{ Trans *t;", + " char *q;", + "", + " for (t = trans[ot][tt]; t; t = t->nxt)", + " { printf(\"\\t\\t\");", + + " q = transmognify(t->tp);", + " for ( ; *q; q++)", + " if (*q == '\\n')", + " printf(\"\\\\n\");", + " else", + " putchar(*q);", + " printf(\"\\n\");", + " }", + "}", + "void", + "wrap_trail(void)", + "{ static int wrap_in_progress = 0;", + " int i; short II;", + " P0 *z;", + "", + " if (wrap_in_progress++) return;", + "", + " printf(\"spin: trail ends after %%d steps\\n\", depth);", + " if (onlyproc >= 0)", + " { if (onlyproc >= now._nr_pr) pan_exit(0);", + " II = onlyproc;", + " z = (P0 *)pptr(II);", + " printf(\"%%3d:\tproc %%d (%%s) \",", + " depth, II, procname[z->_t]);", + " for (i = 0; src_all[i].src; i++)", + " if (src_all[i].tp == (int) z->_t)", + " { printf(\" line %%3d\",", + " src_all[i].src[z->_p]);", + " break;", + " }", + " printf(\" (state %%2d)\", z->_p);", + " if (!stopstate[z->_t][z->_p])", + " printf(\" (invalid end state)\");", + " printf(\"\\n\");", + " add_src_txt(z->_t, z->_p);", + " pan_exit(0);", + " }", + " printf(\"#processes %%d:\\n\", now._nr_pr);", + " if (depth < 0) depth = 0;", + " for (II = 0; II < now._nr_pr; II++)", + " { z = (P0 *)pptr(II);", + " printf(\"%%3d:\tproc %%d (%%s) \",", + " depth, II, procname[z->_t]);", + " for (i = 0; src_all[i].src; i++)", + " if (src_all[i].tp == (int) z->_t)", + " { printf(\" line %%3d\",", + " src_all[i].src[z->_p]);", + " break;", + " }", + " printf(\" (state %%2d)\", z->_p);", + " if (!stopstate[z->_t][z->_p])", + " printf(\" (invalid end state)\");", + " printf(\"\\n\");", + " add_src_txt(z->_t, z->_p);", + " }", + " c_globals();", + " for (II = 0; II < now._nr_pr; II++)", + " { z = (P0 *)pptr(II);", + " c_locals(II, z->_t);", + " }", + "#ifdef ON_EXIT", + " ON_EXIT;", + "#endif", + " pan_exit(0);", + "}", + "FILE *", + "findtrail(void)", + "{ FILE *fd;", + " char fnm[512], *q;", + " if (whichtrail)", + " { sprintf(fnm, \"%%s%%d.%%s\", TrailFile, whichtrail, tprefix);", + " fd = fopen(fnm, \"r\");", + " if (fd == NULL && (q = strchr(TrailFile, \'.\')))", + " { *q = \'\\0\';", /* e.g., strip .pml on original file */ + " sprintf(fnm, \"%%s%%d.%%s\", TrailFile, whichtrail, tprefix);", + " *q = \'.\';", + " fd = fopen(fnm, \"r\");", + " if (fd == NULL)", + " { printf(\"pan: cannot find %%s%%d.%%s or %%s\\n\", ", + " TrailFile, whichtrail, tprefix, fnm);", + " pan_exit(1);", + " } }", + " } else", + " { sprintf(fnm, \"%%s.%%s\", TrailFile, tprefix);", + " fd = fopen(fnm, \"r\");", + " if (fd == NULL && (q = strchr(TrailFile, \'.\')))", + " { *q = \'\\0\';", /* e.g., strip .pml on original file */ + " sprintf(fnm, \"%%s.%%s\", TrailFile, tprefix);", + " *q = \'.\';", + " fd = fopen(fnm, \"r\");", + " if (fd == NULL)", + " { printf(\"pan: cannot find %%s.%%s or %%s\\n\", ", + " TrailFile, tprefix, fnm);", + " pan_exit(1);", + " } } }", + " if (fd == NULL)", + " { printf(\"pan: cannot find trailfile %%s\\n\", fnm);", + " pan_exit(1);", + " }", + " return fd;", + "}", + "", + "uchar do_transit(Trans *, short);", + "", + "void", + "getrail(void)", + "{ FILE *fd;", + " char *q;", + " int i, t_id, lastnever=-1; short II;", + " Trans *t;", + " P0 *z;", + "", + " fd = findtrail(); /* exits if unsuccessful */", + " while (fscanf(fd, \"%%d:%%d:%%d\\n\", &depth, &i, &t_id) == 3)", + " { if (depth == -1)", + " printf(\"<<<<>>>>\\n\");", + " if (depth < 0)", + " continue;", + " II = i;", + "", + " z = (P0 *)pptr(II);", + " for (t = trans[z->_t][z->_p]; t; t = t->nxt)", + " if (t->t_id == t_id)", + " break;", + " if (!t)", + " { for (i = 0; i < NrStates[z->_t]; i++)", + " { t = trans[z->_t][i];", + " if (t && t->t_id == t_id)", + " { printf(\" Recovered at state %%d\\n\", i);", + " z->_p = i;", + " goto recovered;", + " } }", + " printf(\"pan: Error, proc %%d type %%d state %%d: \",", + " II, z->_t, z->_p);", + " printf(\"transition %%d not found\\n\", t_id);", + " for (t = trans[z->_t][z->_p]; t; t = t->nxt)", + " printf(\" t_id %%d -- case %%d, [%%s]\\n\",", + " t->t_id, t->forw, t->tp);", + " break; /* pan_exit(1); */", + " }", + "recovered:", + " q = transmognify(t->tp);", + " if (gui) simvals[0] = \'\\0\';", + + " this = pptr(II);", + " trpt->tau |= 1;", /* timeout always possible */ + " if (!do_transit(t, II))", + " { if (onlyproc >= 0 && II != onlyproc)", + " goto moveon;", + " printf(\"pan: error, next transition UNEXECUTABLE on replay\\n\");", + " printf(\" most likely causes: missing c_track statements\\n\");", + " printf(\" or illegal side-effects in c_expr statements\\n\");", + " }", + + " if (onlyproc >= 0 && II != onlyproc)", + " goto moveon;", + + " if (verbose)", + " { printf(\"depth: %%3d proc: %%3d trans: %%3d (%%d procs) \",", + " depth, II, t_id, now._nr_pr);", + " printf(\"forw=%%3d [%%s]\\n\", t->forw, q);", + "", + " c_globals();", + " for (i = 0; i < now._nr_pr; i++)", + " { c_locals(i, ((P0 *)pptr(i))->_t);", + " }", + " } else", + " if (strcmp(procname[z->_t], \":never:\") == 0)", + " { if (lastnever != (int) z->_p)", + " { for (i = 0; src_all[i].src; i++)", + " if (src_all[i].tp == (int) z->_t)", + " { printf(\"MSC: ~G %%d\\n\",", + " src_all[i].src[z->_p]);", + " break;", + " }", + " if (!src_all[i].src)", + " printf(\"MSC: ~R %%d\\n\", z->_p);", + " }", + " lastnever = z->_p;", + " goto sameas;", + " } else", + " if (strcmp(procname[z->_t], \":np_:\") != 0)", + " {", + "sameas: if (no_rck) goto moveon;", + " if (coltrace)", + " { printf(\"%%d: \", depth);", + " for (i = 0; i < II; i++)", + " printf(\"\\t\\t\");", + " printf(\"%%s(%%d):\", procname[z->_t], II);", + " printf(\"[%%s]\\n\", q);", + " } else", + " { if (strlen(simvals) > 0) {", + " printf(\"%%3d: proc %%2d (%%s)\", ", + " depth, II, procname[z->_t]);", + " for (i = 0; src_all[i].src; i++)", + " if (src_all[i].tp == (int) z->_t)", + " { printf(\" line %%3d \\\"pan_in\\\" \",", + " src_all[i].src[z->_p]);", + " break;", + " }", + " printf(\"(state %%d)\t[values: %%s]\\n\", z->_p, simvals);", + " }", + " printf(\"%%3d: proc %%2d (%%s)\", ", + " depth, II, procname[z->_t]);", + " for (i = 0; src_all[i].src; i++)", + " if (src_all[i].tp == (int) z->_t)", + " { printf(\" line %%3d \\\"pan_in\\\" \",", + " src_all[i].src[z->_p]);", + " break;", + " }", + " printf(\"(state %%d)\t[%%s]\\n\", z->_p, q);", + " printf(\"\\n\");", + " } }", + "moveon: z->_p = t->st;", + " }", + " wrap_trail();", + "}", + "#endif", + "int", + "f_pid(int pt)", + "{ int i;", + " P0 *z;", + " for (i = 0; i < now._nr_pr; i++)", + " { z = (P0 *)pptr(i);", + " if (z->_t == (unsigned) pt)", + " return BASE+z->_pid;", + " }", + " return -1;", + "}", + "#ifdef VERI", + "void check_claim(int);", + "#endif", + "", + "#ifdef BITSTATE", +#ifndef POWOW + "int", + "bstore_mod(char *v, int n) /* hasharray size not a power of two */", + "{ unsigned long x, y;", + " unsigned int i = 1;", + "", + " d_hash((uchar *) v, n); /* sets j3, j4, K1, K2 */", + " x = K2; y = j3;", + " for (;;)", + " { if (!(SS[x%%udmem]&(1< RANDSTOR) return 0;", + "#endif", + " for (;;)", + " { SS[x%%udmem] |= (1< RANDSTOR) return 0;", + "#endif", + " for (;;)", + " { SS[x] |= (1< 0)", + " sprintf(fnm, \"%%s%%d.%%s\",", + " TrailFile, Nr_Trails-1, tprefix);", + " else", + " sprintf(fnm, \"%%s.%%s\", TrailFile, tprefix);", + "", + " if ((fd = creat(fnm, (unsigned short) TMODE)) < 0)", + " { if ((q = strchr(TrailFile, \'.\')))", + " { *q = \'\\0\';", /* strip .pml */ + " if (iterative == 0 && Nr_Trails-1 > 0)", + " sprintf(fnm, \"%%s%%d.%%s\",", + " TrailFile, Nr_Trails-1, tprefix);", + " else", + " sprintf(fnm, \"%%s.%%s\", TrailFile, tprefix);", + " *q = \'.\';", + " fd = creat(fnm, (unsigned short) TMODE);", + " } }", + " if (fd < 0)", + " { printf(\"cannot create %%s\\n\", fnm);", + " perror(\"cause\");", + " } else", + " printf(\"pan: wrote %%s\\n\", fnm);", + "", + " return fd;", + "}", + 0 +}; + +static char *Code2b[] = { /* breadth-first search option */ + "#ifdef BFS", + "#define QPROVISO", + "#ifndef INLINE_REV", + "#define INLINE_REV", + "#endif", + "", + "typedef struct SV_Hold {", + " State *sv;", + " int sz;", + " struct SV_Hold *nxt;", + "} SV_Hold;", + "", + "typedef struct EV_Hold {", + " char *sv;", /* Mask */ + " int sz;", /* vsize */ + " int nrpr;", + " int nrqs;", + " int *po, *ps;", + " int *qo, *qs;", + " struct EV_Hold *nxt;", + "} EV_Hold;", + "", + "typedef struct BFS_Trail {", + " Trail *frame;", + " SV_Hold *onow;", + " EV_Hold *omask;", + "#ifdef QPROVISO", + " struct H_el *lstate;", + "#endif", + " short boq;", + " struct BFS_Trail *nxt;", + "} BFS_Trail;", + "", + "BFS_Trail *bfs_trail, *bfs_bot, *bfs_free;", + "", + "SV_Hold *svhold, *svfree;", + "", + "uchar do_reverse(Trans *, short, uchar);", + "void snapshot(void);", + "", + "SV_Hold *", + "getsv(int n)", + "{ SV_Hold *h = (SV_Hold *) 0, *oh;", + "", + " oh = (SV_Hold *) 0;", + " for (h = svfree; h; oh = h, h = h->nxt)", + " { if (n == h->sz)", + " { if (!oh)", + " svfree = h->nxt;", + " else", + " oh->nxt = h->nxt;", + " h->nxt = (SV_Hold *) 0;", + " break;", + " }", + " if (n < h->sz)", + " { h = (SV_Hold *) 0;", + " break;", + " }", + " /* else continue */", + " }", + "", + " if (!h)", + " { h = (SV_Hold *) emalloc(sizeof(SV_Hold));", + " h->sz = n;", + " h->sv = (State *) emalloc(sizeof(State) - VECTORSZ + n);", + " }", + " return h;", + "}", + "", + "EV_Hold *", + "getsv_mask(int n)", + "{ EV_Hold *h;", + " static EV_Hold *kept = (EV_Hold *) 0;", + "", + " for (h = kept; h; h = h->nxt)", + " if (n == h->sz", + " && (memcmp((char *) Mask, (char *) h->sv, n) == 0)", + " && (now._nr_pr == h->nrpr)", + " && (now._nr_qs == h->nrqs)", + " && (memcmp((char *) proc_offset, (char *) h->po, now._nr_pr * sizeof(int)) == 0)", + " && (memcmp((char *) proc_skip, (char *) h->ps, now._nr_pr * sizeof(int)) == 0)", + " && (memcmp((char *) q_offset, (char *) h->qo, now._nr_qs * sizeof(int)) == 0)", + " && (memcmp((char *) q_skip, (char *) h->qs, now._nr_qs * sizeof(int)) == 0))", + " break;", + " if (!h)", + " { h = (EV_Hold *) emalloc(sizeof(EV_Hold));", + " h->sz = n;", + " h->nrpr = now._nr_pr;", + " h->nrqs = now._nr_qs;", + "", + " h->sv = (char *) emalloc(n * sizeof(char));", + " memcpy((char *) h->sv, (char *) Mask, n);", + "", + " if (now._nr_pr > 0)", + " { h->po = (int *) emalloc(now._nr_pr * sizeof(int));", + " h->ps = (int *) emalloc(now._nr_pr * sizeof(int));", + " memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(int));", + " memcpy((char *) h->ps, (char *) proc_skip, now._nr_pr * sizeof(int));", + " }", + " if (now._nr_qs > 0)", + " { h->qo = (int *) emalloc(now._nr_qs * sizeof(int));", + " h->qs = (int *) emalloc(now._nr_qs * sizeof(int));", + " memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(int));", + " memcpy((char *) h->qs, (char *) q_skip, now._nr_qs * sizeof(int));", + " }", + "", + " h->nxt = kept;", + " kept = h;", + " }", + " return h;", + "}", + "", + "void", + "freesv(SV_Hold *p)", + "{ SV_Hold *h, *oh;", + "", + " oh = (SV_Hold *) 0;", + " for (h = svfree; h; oh = h, h = h->nxt)", + " if (h->sz >= p->sz)", + " break;", + "", + " if (!oh)", + " { p->nxt = svfree;", + " svfree = p;", + " } else", + " { p->nxt = h;", + " oh->nxt = p;", + " }", + "}", + "", + "BFS_Trail *", + "get_bfs_frame(void)", + "{ BFS_Trail *t;", + "", + " if (bfs_free)", + " { t = bfs_free;", + " bfs_free = bfs_free->nxt;", + " t->nxt = (BFS_Trail *) 0;", + " } else", + " { t = (BFS_Trail *) emalloc(sizeof(BFS_Trail));", + " }", + " t->frame = (Trail *) emalloc(sizeof(Trail));", /* always new */ + " return t;", + "}", + "", + "void", + "push_bfs(Trail *f, int d)", + "{ BFS_Trail *t;", + "", + " t = get_bfs_frame();", + " memcpy((char *)t->frame, (char *)f, sizeof(Trail));", + " t->frame->o_tt = d; /* depth */", + "", + " t->boq = boq;", + " t->onow = getsv(vsize);", + " memcpy((char *)t->onow->sv, (char *)&now, vsize);", + " t->omask = getsv_mask(vsize);", + "#if defined(FULLSTACK) && defined(QPROVISO)", + " t->lstate = Lstate;", + "#endif", + " if (!bfs_bot)", + " { bfs_bot = bfs_trail = t;", + " } else", + " { bfs_bot->nxt = t;", + " bfs_bot = t;", + " }", + "#ifdef CHECK", + " printf(\"PUSH %%u (%%d)\\n\", t->frame, d);", + "#endif", + "}", + "", + "Trail *", + "pop_bfs(void)", + "{ BFS_Trail *t;", + "", + " if (!bfs_trail)", + " return (Trail *) 0;", + "", + " t = bfs_trail;", + " bfs_trail = t->nxt;", + " if (!bfs_trail)", + " bfs_bot = (BFS_Trail *) 0;", + "#if defined(QPROVISO) && !defined(BITSTATE) && !defined(NOREDUCE)", + " if (t->lstate) t->lstate->tagged = 0;", + "#endif", + "", + " t->nxt = bfs_free;", + " bfs_free = t;", + "", + " vsize = t->onow->sz;", + " boq = t->boq;", + "", + " memcpy((uchar *) &now, (uchar *) t->onow->sv, vsize);", + " memcpy((uchar *) Mask, (uchar *) t->omask->sv, vsize);", + + " if (now._nr_pr > 0)", + " { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(int));", + " memcpy((char *)proc_skip, (char *)t->omask->ps, now._nr_pr * sizeof(int));", + " }", + " if (now._nr_qs > 0)", + " { memcpy((uchar *)q_offset, (uchar *)t->omask->qo, now._nr_qs * sizeof(int));", + " memcpy((uchar *)q_skip, (uchar *)t->omask->qs, now._nr_qs * sizeof(int));", + " }", + + " freesv(t->onow); /* omask not freed */", + "#ifdef CHECK", + " printf(\"POP %%u (%%d)\\n\", t->frame, t->frame->o_tt);", + "#endif", + " return t->frame;", + "}", + "", + "void", + "store_state(Trail *ntrpt, int shortcut, short oboq)", + "{", + "#ifdef VERI", + " Trans *t2 = (Trans *) 0;", + " uchar ot; int tt, E_state;", + " uchar o_opm = trpt->o_pm, *othis = this;", + "", + " if (shortcut)", + " {", + "#ifdef VERBOSE", + " printf(\"claim: shortcut\\n\");", + "#endif", + " goto store_it; /* no claim move */", + " }", + "", + " this = (((uchar *)&now)+proc_offset[0]); /* 0 = never claim */", + " trpt->o_pm = 0;", /* to interpret else in never claim */ + "", + " tt = (int) ((P0 *)this)->_p;", + " ot = (uchar) ((P0 *)this)->_t;", + "", + "#ifdef HAS_UNLESS", + " E_state = 0;", + "#endif", + " for (t2 = trans[ot][tt]; t2; t2 = t2?t2->nxt:(Trans *)0)", + " {", + "#ifdef HAS_UNLESS", + " if (E_state > 0", + " && E_state != t2->e_trans)", + " break;", + "#endif", + " if (do_transit(t2, 0))", + " {", + "#ifdef VERBOSE", + " if (!reached[ot][t2->st])", + " printf(\"depth: %%d -- claim move from %%d -> %%d\\n\",", + " trpt->o_tt, ((P0 *)this)->_p, t2->st);", + "#endif", + "#ifdef HAS_UNLESS", + " E_state = t2->e_trans;", + "#endif", + " if (t2->st > 0)", + " { ((P0 *)this)->_p = t2->st;", + " reached[ot][t2->st] = 1;", + "#ifndef NOCLAIM", + " check_claim(t2->st);", + "#endif", + " }", + " if (now._nr_pr == 0) /* claim terminated */", + " uerror(\"end state in claim reached\");", + "", + "#ifdef PEG", + " peg[t2->forw]++;", + "#endif", + " trpt->o_pm |= 1;", + " if (t2->atom&2)", /* atomic in claim */ + " Uerror(\"atomic in claim not supported in BFS mode\");", + "store_it:", + "", + "#endif", /* VERI */ + "", + "#ifdef BITSTATE", + " if (!bstore((char *)&now, vsize))", + "#else", + "#ifdef MA", + " if (!gstore((char *)&now, vsize, 0))", + "#else", + " if (!hstore((char *)&now, vsize))", + "#endif", + "#endif", + " { nstates++;", + "#ifndef NOREDUCE", + " trpt->tau |= 64;", /* succ definitely outside stack */ + "#endif", + "#if SYNC", + " if (boq != -1)", + " midrv++;", + " else if (oboq != -1)", + " { Trail *x;", + " x = (Trail *) trpt->ostate; /* pre-rv state */", + " if (x) x->o_pm |= 4; /* mark success */", + " }", + "#endif", + " push_bfs(ntrpt, trpt->o_tt+1);", + " } else", + " { truncs++;", + + "#if !defined(NOREDUCE) && defined(FULLSTACK) && defined(QPROVISO)", + "#if !defined(QLIST) && !defined(BITSTATE)", + " if (Lstate && Lstate->tagged) trpt->tau |= 64;", + "#else", + " if (trpt->tau&32)", + " { BFS_Trail *tprov;", + " for (tprov = bfs_trail; tprov; tprov = tprov->nxt)", + " if (!memcmp((uchar *)&now, (uchar *)tprov->onow->sv, vsize))", + " { trpt->tau |= 64;", + " break; /* state is in queue */", + " } }", + "#endif", + "#endif", + " }", + "#ifdef VERI", + " ((P0 *)this)->_p = tt; /* reset claim */", + " if (t2)", + " do_reverse(t2, 0, 0);", + " else", + " break;", + " } }", + " this = othis;", + " trpt->o_pm = o_opm;", + "#endif", + "}", + "", + "void", + "bfs(void)", + "{ Trans *t; Trail *ntrpt, *otrpt, *x;", + " uchar _n, _m, ot, nps = 0;", + " int tt, E_state;", + " short II, From = (short) (now._nr_pr-1), To = BASE;", + " short oboq = boq;", + "", + " ntrpt = (Trail *) emalloc(sizeof(Trail));", + " trpt->ostate = (struct H_el *) 0;", + " trpt->tau = 0;", + "", + " trpt->o_tt = -1;", + " store_state(ntrpt, 0, oboq); /* initial state */", + "", + " while ((otrpt = pop_bfs())) /* also restores now */", + " { memcpy((char *) trpt, (char *) otrpt, sizeof(Trail));", + "#if defined(C_States) && (HAS_TRACK==1)", + " c_revert((uchar *) &(now.c_state[0]));", + "#endif", + " if (trpt->o_pm & 4)", + " {", + "#ifdef VERBOSE", + " printf(\"Revisit of atomic not needed (%%d)\\n\",", + " trpt->o_pm);", /* at least 1 rv succeeded */ + "#endif", + " continue;", + " }", + "#ifndef NOREDUCE", + " nps = 0;", + "#endif", + " if (trpt->o_pm == 8)", + " { revrv++;", + " if (trpt->tau&8)", + " {", + "#ifdef VERBOSE", + " printf(\"Break atomic (pm:%%d,tau:%%d)\\n\",", + " trpt->o_pm, trpt->tau);", + "#endif", + " trpt->tau &= ~8;", + " }", + "#ifndef NOREDUCE", + " else if (trpt->tau&32)", /* was a preselected move */ + " {", + "#ifdef VERBOSE", + " printf(\"Void preselection (pm:%%d,tau:%%d)\\n\",", + " trpt->o_pm, trpt->tau);", + "#endif", + " trpt->tau &= ~32;", + " nps = 1; /* no preselection in repeat */", + " }", + "#endif", + " }", + " trpt->o_pm &= ~(4|8);", + " if (trpt->o_tt > mreached)", + " { mreached = trpt->o_tt;", + " if (mreached%%10 == 0)", + " { printf(\"Depth= %%7d States= %%7g \", mreached, nstates);", + " printf(\"Transitions= %%7g \", nstates+truncs);", + "#ifdef MA", + " printf(\"Nodes= %%7d \", nr_states);", + "#endif", + " printf(\"Memory= %%-6.3f\\n\", memcnt/1000000.);", + " fflush(stdout);", + " } }", + " depth = trpt->o_tt;", + + " if (depth >= maxdepth)", + " {", + "#if SYNC", + " Trail *x;", + " if (boq != -1)", + " { x = (Trail *) trpt->ostate;", + " if (x) x->o_pm |= 4; /* not failing */", + " }", + "#endif", + " truncs++;", + " if (!warned)", + " { warned = 1;", + " printf(\"error: max search depth too small\\n\");", + " }", + " if (bounded)", + " uerror(\"depth limit reached\");", + " continue;", + " }", + +/* PO */ + "#ifndef NOREDUCE", + " if (boq == -1 && !(trpt->tau&8) && nps == 0)", + " for (II = now._nr_pr-1; II >= BASE; II -= 1)", + " {", + "Pickup: this = pptr(II);", + " tt = (int) ((P0 *)this)->_p;", + " ot = (uchar) ((P0 *)this)->_t;", + " if (trans[ot][tt]->atom & 8)", /* safe */ + " { t = trans[ot][tt];", + " if (t->qu[0] != 0)", + " { Ccheck++;", + " if (!q_cond(II, t))", + " continue;", + " Cholds++;", + " }", + " From = To = II;", + " trpt->tau |= 32; /* preselect marker */", + "#ifdef DEBUG", + " printf(\"%%3d: proc %%d PreSelected (tau=%%d)\\n\", ", + " depth, II, trpt->tau);", + "#endif", + " goto MainLoop;", + " } }", + " trpt->tau &= ~32;", /* not preselected */ + "#endif", +/* PO */ + "Repeat:", + " if (trpt->tau&8) /* atomic */", + " { From = To = (short ) trpt->pr;", + " nlinks++;", + " } else", + " { From = now._nr_pr-1;", + " To = BASE;", + " }", + "MainLoop:", + " _n = _m = 0;", + " for (II = From; II >= To; II -= 1)", + " {", + " this = (((uchar *)&now)+proc_offset[II]);", + " tt = (int) ((P0 *)this)->_p;", + " ot = (uchar) ((P0 *)this)->_t;", + "#if SYNC", + " /* no rendezvous with same proc */", + " if (boq != -1 && trpt->pr == II) continue;", + "#endif", + " ntrpt->pr = (uchar) II;", + " ntrpt->st = tt; ", + " trpt->o_pm &= ~1; /* no move yet */", + "#ifdef EVENT_TRACE", + " trpt->o_event = now._event;", + "#endif", + "#ifdef HAS_PROVIDED", + " if (!provided(II, ot, tt, t)) continue;", + "#endif", + "#ifdef HAS_UNLESS", + " E_state = 0;", + "#endif", + " for (t = trans[ot][tt]; t; t = t->nxt)", + " {", + "#ifdef HAS_UNLESS", + " if (E_state > 0", + " && E_state != t->e_trans)", + " break;", + "#endif", + " ntrpt->o_t = t;", + "", + " oboq = boq;", + "", + " if (!(_m = do_transit(t, II)))", + " continue;", + "", + " trpt->o_pm |= 1; /* we moved */", + " (trpt+1)->o_m = _m; /* for unsend */", + "#ifdef PEG", + " peg[t->forw]++;", + "#endif", + "#ifdef CHECK", + " printf(\"%%3d: proc %%d exec %%d, \",", + " depth, II, t->forw);", + " printf(\"%%d to %%d, %%s %%s %%s\",", + " tt, t->st, t->tp,", + " (t->atom&2)?\"atomic\":\"\",", + " (boq != -1)?\"rendez-vous\":\"\");", + "#ifdef HAS_UNLESS", + " if (t->e_trans)", + " printf(\" (escapes to state %%d)\", t->st);", + "#endif", + " printf(\" %%saccepting [tau=%%d]\\n\",", + " (trpt->o_pm&2)?\"\":\"non-\", trpt->tau);", + "#endif", + "#ifdef HAS_UNLESS", + " E_state = t->e_trans;", + "#if SYNC>0", + " if (t->e_trans > 0 && (boq != -1 /* || oboq != -1 */))", + " { fprintf(efd, \"error:\tthe use of rendezvous stmnt in the escape clause\\n\");", + " fprintf(efd, \"\tof an unless stmnt is not compatible with -DBFS\\n\");", + " pan_exit(1);", + " }", + "#endif", + "#endif", + " if (t->st > 0) ((P0 *)this)->_p = t->st;", + "", + " /* ptr to pred: */ ntrpt->ostate = (struct H_el *) otrpt;", + " ntrpt->st = tt;", + " if (boq == -1 && (t->atom&2)) /* atomic */", + " ntrpt->tau = 8; /* record for next move */", + " else", + " ntrpt->tau = 0;", + "", + " store_state(ntrpt, (boq != -1 || (t->atom&2)), oboq);", + "#ifdef EVENT_TRACE", + " now._event = trpt->o_event;", + "#endif", + "", + " /* undo move and continue */", + " trpt++; /* this is where ovals and ipt are set */", + " do_reverse(t, II, _m); /* restore now. */", + " trpt--;", + "#ifdef CHECK", + " printf(\"%%3d: proc %%d \", depth, II);", + " printf(\"reverses %%d, %%d to %%d,\",", + " t->forw, tt, t->st);", + " printf(\" %%s [abit=%%d,adepth=%%d,\",", + " t->tp, now._a_t, A_depth);", + " printf(\"tau=%%d,%%d]\\n\",", + " trpt->tau, (trpt-1)->tau);", + "#endif", + " reached[ot][t->st] = 1;", + " reached[ot][tt] = 1;", + "", + " ((P0 *)this)->_p = tt;", + " _n |= _m;", + " } }", +/* PO */ + "#ifndef NOREDUCE", + " /* preselected - no succ definitely outside stack */", + " if ((trpt->tau&32) && !(trpt->tau&64))", + " { From = now._nr_pr-1; To = BASE;", + "#ifdef DEBUG", + " printf(\"%%3d: proc %%d UnSelected (_n=%%d, tau=%%d)\\n\", ", + " depth, II+1, (int) _n, trpt->tau);", + "#endif", + " _n = 0; trpt->tau &= ~32;", + " if (II >= BASE)", + " goto Pickup;", + " goto MainLoop;", + " }", + " trpt->tau &= ~(32|64);", + "#endif", +/* PO */ + " if (_n != 0)", + " continue;", + "#ifdef DEBUG", + " printf(\"%%3d: no move [II=%%d, tau=%%d, boq=%%d, _nr_pr=%%d]\\n\",", + " depth, II, trpt->tau, boq, now._nr_pr);", + "#endif", + " if (boq != -1)", + " { failedrv++;", + " x = (Trail *) trpt->ostate; /* pre-rv state */", + " if (!x) continue; /* root state */", + " if ((x->tau&8) || (x->tau&32)) /* break atomic or preselect at parent */", + " { x->o_pm |= 8; /* mark failure */", + " this = (((uchar *)&now)+proc_offset[otrpt->pr]);", + "#ifdef VERBOSE", + " printf(\"\\treset state of %%d from %%d to %%d\\n\",", + " otrpt->pr, ((P0 *)this)->_p, otrpt->st);", + "#endif", + " ((P0 *)this)->_p = otrpt->st;", + " unsend(boq); /* retract rv offer */", + " boq = -1;", + + " push_bfs(x, x->o_tt);", + "#ifdef VERBOSE", + " printf(\"failed rv, repush with %%d\\n\", x->o_pm);", + "#endif", + " }", + "#ifdef VERBOSE", + " else printf(\"failed rv, tau at parent: %%d\\n\", x->tau);", + "#endif", + " } else if (now._nr_pr > 0)", + " {", + " if ((trpt->tau&8)) /* atomic */", + " { trpt->tau &= ~(1|8); /* 1=timeout, 8=atomic */", + "#ifdef DEBUG", + " printf(\"%%3d: atomic step proc %%d blocks\\n\",", + " depth, II+1);", + "#endif", + " goto Repeat;", + " }", + "", + " if (!(trpt->tau&1)) /* didn't try timeout yet */", + " { trpt->tau |= 1;", + "#ifdef DEBUG", + " printf(\"%%d: timeout\\n\", depth);", + "#endif", + " goto MainLoop;", + " }", + "#ifndef VERI", + " if (!noends && !a_cycles && !endstate())", + " uerror(\"invalid end state\");", + "#endif", + " } }", + "}", + "", + "void", + "putter(Trail *trpt, int fd)", + "{ long j;", + "", + " if (!trpt) return;", + "", + " if (trpt != (Trail *) trpt->ostate)", + " putter((Trail *) trpt->ostate, fd);", + "", + " if (trpt->o_t)", + " { sprintf(snap, \"%%d:%%d:%%d\\n\",", + " trcnt++, trpt->pr, trpt->o_t->t_id);", + " j = strlen(snap);", + " if (write(fd, snap, j) != j)", + " { printf(\"pan: error writing %%s\\n\", fnm);", + " exit(1);", + " } }", + "}", + "", + "void", + "nuerror(char *str)", + "{ int fd = make_trail();", + " if (fd < 0) return;", + "#ifdef VERI", + " sprintf(snap, \"-2:%%d:-2\\n\", VERI);", + " write(fd, snap, strlen(snap));", + "#endif", + "#ifdef MERGED", + " sprintf(snap, \"-4:-4:-4\\n\");", + " write(fd, snap, strlen(snap));", + "#endif", + " trcnt = 1;", + " putter(trpt, fd);", + " close(fd);", + " if (errors >= upto && upto != 0)", + " wrapup();", + "}", + "#endif", /* BFS */ + 0, +}; + +static char *Code2c[] = { + "void", "do_the_search(void)", "{ int i;", - " depth=mreached=0;", - " trpt = &trail[depth];", + " depth = mreached = 0;", + " trpt = &trail[0];", "#ifdef VERI", " trpt->tau |= 4; /* the claim moves first */", "#endif", @@ -205,16 +1285,36 @@ "#endif", " }", "#endif", + + "#if defined(C_States) && (HAS_TRACK==1)", + " /* capture initial state of tracked C objects */", + " c_update((uchar *) &(now.c_state[0]));", + "#endif", + + "#ifdef HAS_CODE", + " if (readtrail) getrail(); /* no return */", + "#endif", + "#ifdef BFS", + " bfs();", + "#else", + "#if defined(C_States) && defined(HAS_STACK) && (HAS_TRACK==1)", + " /* initial state of tracked & unmatched objects */", + " c_stack((uchar *) &(svtack->c_stack[0]));", + "#endif", + "#ifdef RANDOMIZE", + " srand(123);", + "#endif", " new_state(); /* start 1st DFS */", + "#endif", "}", "#ifdef INLINE_REV", - "char", - "do_reverse(Trans *t, short II, char M)", - "{ char m = M;", - " short tt = (short) ((P0 *)this)->_p;", + "uchar", + "do_reverse(Trans *t, short II, uchar M)", + "{ uchar _m = M;", + " int tt = (int) ((P0 *)this)->_p;", "#include REVERSE_MOVES", - "R999: return m;", + "R999: return _m;", "}", "#endif", @@ -222,24 +1322,30 @@ "#ifdef EVENT_TRACE", "static char _tp = 'n'; static int _qid = 0;", "#endif", - "char", - "do_transit(Trans *t, short II, int n)", - "{ char m;", - " short tt = (short) ((P0 *)this)->_p;", - " char ot = (char) ((P0 *)this)->_t;", + "uchar", + "do_transit(Trans *t, short II)", + "{ uchar _m = 0;", + " int tt = (int) ((P0 *)this)->_p;", + "#ifdef M_LOSS", + " uchar delta_m = 0;", + "#endif", "#ifdef EVENT_TRACE", " short oboq = boq;", - " if (II == EVENT_TRACE) boq = -1;", + " uchar ot = (uchar) ((P0 *)this)->_t;", + " if (ot == EVENT_TRACE) boq = -1;", "#define continue { boq = oboq; return 0; }", "#else", "#define continue return 0", + "#ifdef SEPARATE", + " uchar ot = (uchar) ((P0 *)this)->_t;", + "#endif", "#endif", "#include FORWARD_MOVES", "P999:", "#ifdef EVENT_TRACE", - " boq = oboq;", + " if (ot == EVENT_TRACE) boq = oboq;", "#endif", - " return m;", + " return _m;", "#undef continue", "}", @@ -248,41 +1354,40 @@ "require(char tp, int qid)", "{ Trans *t;", " _tp = tp; _qid = qid;", - "#ifdef NEGATED_TRACE", - " if (now._event == endevent)", - " { depth++; trpt++;", - " uerror(\"event_trace error (all events matched)\");", - "#ifndef NP", - " if (accpstate[EVENT_TRACE][now._event])", - " trpt->o_pm |= 2;", - "#else", - " if (progstate[EVENT_TRACE][now._event])", - " trpt->o_pm |= 4;", - "#endif", - " trpt--; depth--;", - " now._event = start_event;", - " return;", - " } else", - "#else", + "", " if (now._event != endevent)", - "#endif", " for (t = trans[EVENT_TRACE][now._event]; t; t = t->nxt)", - " { if (do_transit(t, EVENT_TRACE, 0))", + " { if (do_transit(t, EVENT_TRACE))", " { now._event = t->st;", " reached[EVENT_TRACE][t->st] = 1;", "#ifdef VERBOSE", " printf(\" event_trace move to -> %%d\\n\", t->st);", "#endif", - "#ifndef NP", + "#ifndef BFS", + "#ifndef NP", " if (accpstate[EVENT_TRACE][now._event])", " (trpt+1)->o_pm |= 2;", - "#else", + "#else", " if (progstate[EVENT_TRACE][now._event])", " (trpt+1)->o_pm |= 4;", + "#endif", + "#endif", + "#ifdef NEGATED_TRACE", + " if (now._event == endevent)", + " {", + "#ifndef BFS", + " depth++; trpt++;", + "#endif", + " uerror(\"event_trace error (all events matched)\");", + "#ifndef BFS", + " trpt--; depth--;", + "#endif", + " break;", + " }", "#endif", " for (t = t->nxt; t; t = t->nxt)", - " { if (do_transit(t, EVENT_TRACE, 0))", - " uerror(\"non-determinism in event-trace\");", + " { if (do_transit(t, EVENT_TRACE))", + " Uerror(\"non-determinism in event-trace\");", " }", " return;", " }", @@ -294,10 +1399,14 @@ " }", "#ifdef NEGATED_TRACE", " now._event = start_event; /* only 1st try will count */", - "#else", + "#else", + "#ifndef BFS", " depth++; trpt++;", + "#endif", " uerror(\"event_trace error (no matching event)\");", + "#ifndef BFS", " trpt--; depth--;", + "#endif", "#endif", "}", "#endif", @@ -305,7 +1414,7 @@ "int", "enabled(int iam, int pid)", "{ Trans *t; uchar *othis = this;", - " int res = 0; short tt; char ot;", + " int res = 0; int tt; uchar ot;", "#ifdef VERI", " /* if (pid > 0) */ pid++;", "#endif", @@ -315,10 +1424,10 @@ " return 0;", " this = pptr(pid);", " TstOnly = 1;", - " tt = (short) ((P0 *)this)->_p;", + " tt = (int) ((P0 *)this)->_p;", " ot = (uchar) ((P0 *)this)->_t;", " for (t = trans[ot][tt]; t; t = t->nxt)", - " if (do_transit(t, pid, 0))", + " if (do_transit(t, (short) pid))", " { res = 1;", " break;", " }", @@ -347,7 +1456,7 @@ "stack2disk(void)", "{", " if (!stackwrite", - " && (stackwrite = creat(stackfile, 0666)) <= 0)", + " && (stackwrite = creat(stackfile, 0666)) < 0)", " Uerror(\"cannot create stackfile\");", "", " if (write(stackwrite, trail, DDD*sizeof(Trail))", @@ -366,15 +1475,15 @@ " memmove(&trail[DDD], trail, (HHH-DDD+2)*sizeof(Trail));", "", " if (!stackwrite", - " || lseek(stackwrite, -DDD*sizeof(Trail), SEEK_CUR) == -1)", + " || lseek(stackwrite, -DDD* (off_t) sizeof(Trail), SEEK_CUR) == -1)", " Uerror(\"disk2stack lseek error\");", "", " if (!stackread", " && (stackread = open(stackfile, 0)) < 0)", " Uerror(\"cannot open stackfile\");", "", - " if (lseek(stackread, (CNT1-CNT2)*DDD*sizeof(Trail), SEEK_SET) == -1)", - " Uerror(\"disk2stack lseek error2\");", + " if (lseek(stackread, (CNT1-CNT2)*DDD* (off_t) sizeof(Trail), SEEK_SET) == -1)", + " Uerror(\"disk2stack lseek error\");", "", " have = read(stackread, trail, DDD*sizeof(Trail));", " if (have != DDD*sizeof(Trail))", @@ -384,28 +1493,36 @@ "uchar *", "Pptr(int x)", /* as a fct, to avoid a problem with the p9 compiler */ - "{ if (proc_offset[x])", - " return (uchar *) pptr(x);", - " else", + "{ if (x < 0 || x >= MAXPROC || !proc_offset[x])", /* does not exist */ " return noptr;", + " else", + " return (uchar *) pptr(x);", "}", + "int qs_empty(void);", - "extern void check_claim(int);", - - "/* new_state() is the main search routine in the verifier", + "/*", + " * new_state() is the main DFS search routine in the verifier", " * it has a lot of code ifdef-ed together to support", - " * different search modes -- this makes it quite unreadable", - " * of course. if you are studying the code, first", - " * let the C preprocessor generate a specific version", - " * from the pan.c source, e.g. by saying:", - " * /lib/cpp -DNOREDUCE -DBITSTATE pan.c > Pan.c", - " * and study the resulting file, rather than this one", + " * different search modes, which makes it quite unreadable.", + " * if you are studying the code, first use the C preprocessor", + " * to generate a specific version from the pan.c source,", + " * e.g. by saying:", + " * gcc -E -DNOREDUCE -DBITSTATE pan.c > ppan.c", + " * and then study the resulting file, rather than this one", " */", + "#if !defined(BFS) && (!defined(BITSTATE) || !defined(MA))", "void", "new_state(void)", "{ Trans *t;", - " char n, m, ot;", - " short II, JJ=0, tt, kk;\n", + " uchar _n, _m, ot;", + "#ifdef RANDOMIZE", + " short ooi, eoi;", + "#endif", + "#ifdef M_LOSS", + " uchar delta_m = 0;", + "#endif", + " short II, JJ = 0, kk;", + " int tt;", " short From = now._nr_pr-1, To = BASE;", "Down:", "#ifdef CHECK", @@ -421,8 +1538,9 @@ " maxdepth += DDD;", " hiwater += DDD;", " trpt -= DDD;", - "if(verbose)", - "printf(\"zap %%d: %%d (maxdepth now %%d)\\n\", CNT1, hiwater, maxdepth);", + " if(verbose)", + " printf(\"zap %%d: %%d (maxdepth now %%d)\\n\",", + " CNT1, hiwater, maxdepth);", " }", "#endif", @@ -439,6 +1557,7 @@ " { warned = 1;", " printf(\"error: max search depth too small\\n\");", " }", + " if (bounded) uerror(\"depth limit reached\");", " (trpt-1)->tau |= 16; /* worstcase guess */", " goto Up;", " }", @@ -478,57 +1597,51 @@ "#endif", " if (!(trpt->tau&8)) /* if no atomic move */", " {", - "#ifdef CNTRSTACK", /* -> bitstate, reduced, safety */ - " d_hash((uchar *)&now, vsize);", + "#ifdef BITSTATE", + "#ifdef CNTRSTACK", /* -> bitstate, reduced, safety */ + " II = bstore((char *)&now, vsize);", " trpt->j6 = j1; trpt->j7 = j2;", " JJ = LL[j1] && LL[j2];", - "#endif", - "#ifdef FULLSTACK", - "#ifdef BITSTATE", - " JJ = onstack_now();", "#else", -"#ifdef MA", + "#ifdef FULLSTACK", + " JJ = onstack_now();", /* sets j1 */ + "#else", + "#ifndef NOREDUCE", + " JJ = II; /* worstcase guess for p.o. */", + "#endif", + "#endif", + " II = bstore((char *)&now, vsize);", /* sets j1-j4 */ + "#endif", + "#else", + "#ifdef MA", " II = gstore((char *)&now, vsize, 0);", -"#else", - " II = hstore((char *)&now, vsize, 1);", -"#endif", + "#ifndef FULLSTACK", + " JJ = II;", + "#else", + " JJ = (II == 2)?1:0;", + "#endif", + "#else", + " II = hstore((char *)&now, vsize);", + "#ifdef FULLSTACK", " JJ = (II == 2)?1:0;", + "#endif", "#endif", "#endif", - - "#ifdef BITSTATE", - "#ifndef CNTRSTACK", /* !reduced */ - " d_hash((uchar *) &now, vsize);", - "#endif", - " kk = II = ((SS[j2]&j3) && (SS[j1]&j4));", - "#ifdef DEBUG", - " if (II) printf(\"Old bitstate\\n\");", - " else printf(\"New bitstate\\n\");", - "#endif", - "#else", - "#ifndef FULLSTACK", -"#ifdef MA", - " JJ = II = gstore((char *) &now, vsize, 0);", -"#else", - " II = hstore((char *)&now, vsize, 2);", -"#endif", - "#endif", " kk = (II == 1 || II == 2);", - "#endif", "#ifndef SAFETY", "#if defined(FULLSTACK) && defined(BITSTATE)", " if (!JJ && (now._a_t&1) && depth > A_depth)", " { int oj1 = j1;", " uchar o_a_t = now._a_t;", - " now._a_t &= ~(1|16|32);", - " if (onstack_now())", + " now._a_t &= ~(1|16|32);", /* 1st stack */ + " if (onstack_now())", /* changes j1 */ " { II = 3;", "#ifdef VERBOSE", - " printf(\"state match on 1st dfs stack\\n\");", + " printf(\"state match on 1st dfs stack\\n\");", "#endif", " }", - " now._a_t = o_a_t;", + " now._a_t = o_a_t;", /* restore */ " j1 = oj1;", " }", "#endif", @@ -538,48 +1651,38 @@ " if (fairness && now._cnt[1] > 1) /* was != 0 */", " {", "#ifdef VERBOSE", - " printf(\" fairness count non-zero\\n\");", + " printf(\"\tfairness count non-zero\\n\");", "#endif", - " II = 0;", + " II = 0;", /* treat as new state */ " } else", "#endif", " {", "#ifdef BITSTATE", " depthfound = Lstate->tagged - 1;", - "#ifdef NP", - " uerror(\"non-progress cycle\");", - "#else", - " uerror(\"acceptance cycle\");", - "#endif", "#else", " depthfound = depth_of(Lstate);", - "#ifdef NP", + " nShadow--;", + "#endif", + "#ifdef NP", " uerror(\"non-progress cycle\");", - "#else", + "#else", " uerror(\"acceptance cycle\");", - "#endif", - " nShadow--;", "#endif", " goto Up;", " }", " }", "#endif", - "#if !defined(FULLSTACK) && !defined(CNTRSTACK) && defined(BITSTATE)", - "#ifndef NOREDUCE", - " JJ = II; /* worstcase guess for p.o. */", - "#endif", - "#endif", "#ifndef NOREDUCE", "#ifndef SAFETY", " if ((II && JJ) || (II == 3))", " { /* marker for liveness proviso */", - " truncs2++;", " (trpt-1)->tau |= 16;", + " truncs2++;", " }", "#else", " if (!II || !JJ)", - " { /* has successor outside stack */", + " { /* successor outside stack */", " (trpt-1)->tau |= 64;", " }", "#endif", @@ -590,60 +1693,69 @@ " }", " if (!kk)", " { nstates++;", + " if ((unsigned long) nstates%%1000000 == 0)", + " snapshot();", "#ifdef SVDUMP", - " if (vprefix > 0)", - " if (write(svfd, (uchar *) &now, vprefix) != vprefix)", - " { fprintf(efd, \"writing %%s.svd failed\\n\", Source);", - " wrapup();", - " }", - "#endif", - " if ((unsigned long) nstates%%1000000 == 0)", - " snapshot();", - "#ifdef MA", - "#ifdef W_XPT", - " if ((unsigned long) nstates%%W_XPT == 0)", - " { void w_xpoint(void);", - " w_xpoint();", - " }", + " if (vprefix > 0)", + " if (write(svfd, (uchar *) &now, vprefix) != vprefix)", + " { fprintf(efd, \"writing %%s.svd failed\\n\", Source);", + " wrapup();", + " }", "#endif", + "#if defined(MA) && defined(W_XPT)", + " if ((unsigned long) nstates%%W_XPT == 0)", + " { void w_xpoint(void);", + " w_xpoint();", + " }", "#endif", " }", - "#ifdef BITSTATE", - "#ifdef RANDSTOR", - " if (rand()%%100 <= RANDSTOR)", - "#endif", - " { SS[j2] |= j3; SS[j1] |= j4; }", - "#endif", "#if defined(FULLSTACK) || defined(CNTRSTACK)", " onstack_put();", "#ifdef DEBUG2", "#if defined(FULLSTACK) && !defined(MA)", - " printf(\"%%d: putting %%u (%%d)\\n\", depth,", - " trpt->ostate, ", - " (trpt->ostate)?trpt->ostate->tagged:0);", + " printf(\"%%d: putting %%u (%%d)\\n\", depth,", + " trpt->ostate, ", + " (trpt->ostate)?trpt->ostate->tagged:0);", "#else", - " printf(\"%%d: putting\\n\", depth);", + " printf(\"%%d: putting\\n\", depth);", "#endif", "#endif", "#endif", " } }", + + " if (depth > mreached)", " mreached = depth;", "#ifdef VERI", " if (trpt->tau&4)", "#endif", " trpt->tau &= ~(1|2); /* timeout and -request off */", - " n = 0;", + " _n = 0;", "#if SYNC", " (trpt+1)->o_n = 0;", "#endif", "#ifdef VERI", " if (now._nr_pr == 0) /* claim terminated */", - " uerror(\"endstate in claim reached\");", + " uerror(\"end state in claim reached\");", " check_claim(((P0 *)pptr(0))->_p);", "Stutter:", " if (trpt->tau&4) /* must make a claimmove */", - " { II = 0; /* never */", + " {", + + "#ifndef NOFAIR", + " if ((now._a_t&2) /* A-bit set */", + " && now._cnt[now._a_t&1] == 1)", + " { now._a_t &= ~2;", + " now._cnt[now._a_t&1] = 0;", + " trpt->o_pm |= 16;", + "#ifdef DEBUG", + " printf(\"%%3d: fairness Rule 3.: _a_t = %%d\\n\",", + " depth, now._a_t);", + "#endif", + " }", + "#endif", + + " II = 0; /* never */", " goto Veri0;", " }", "#endif", @@ -687,7 +1799,7 @@ " {", "Resume: /* pick up here if preselect fails */", " this = pptr(II);", - " tt = (short) ((P0 *)this)->_p;", + " tt = (int) ((P0 *)this)->_p;", " ot = (uchar) ((P0 *)this)->_t;", " if (trans[ot][tt]->atom & 8)", " { t = trans[ot][tt];", @@ -717,7 +1829,9 @@ " }", " trpt->tau &= ~32;", "#endif", + "#if !defined(NOREDUCE) || (defined(ETIM) && !defined(VERI))", "Again:", + "#endif", " /* The Main Expansion Loop over Processes */", " trpt->o_pm &= ~(8|16|32|64); /* fairness-marks */", @@ -760,8 +1874,11 @@ " /* no rendezvous with same proc */", " if (boq != -1 && trpt->pr == II) continue;", "#endif", - "Veri0: this = pptr(II);", - " tt = (short) ((P0 *)this)->_p;", + "#ifdef VERI", + "Veri0:", + "#endif", + " this = pptr(II);", + " tt = (int) ((P0 *)this)->_p;", " ot = (uchar) ((P0 *)this)->_t;", "#ifdef NIBIS", @@ -776,8 +1893,8 @@ " && From != To)", /* not inside atomic seq */ " { if (t->qu[0] == 0", /* unconditional */ " || q_cond(II, t))", /* true condition */ - " { m = t->om;", - " if (m>n||(n>3&&m!=0)) n=m;", + " { _m = t->om;", + " if (_m>_n||(_n>3&&_m!=0)) _n=_m;", " continue; /* did it before */", " } }", "#endif", @@ -814,10 +1931,32 @@ "#ifdef HAS_UNLESS", " trpt->e_state = 0;", "#endif", - "#ifdef EVENT_TRACE", - " (trpt+1)->pr = II;", + " (trpt+1)->pr = (uchar) II;", /* for uerror */ + " (trpt+1)->st = tt;", + + "#ifdef RANDOMIZE", + " for (ooi = eoi = 0, t = trans[ot][tt]; t; t = t->nxt, ooi++)", + " if (strcmp(t->tp, \"else\") == 0)", + " eoi++;", + "", + " if (eoi)", + " { t = trans[ot][tt];", + "#ifdef VERBOSE", + " printf(\"randomizer: suppressed, saw else\\n\");", "#endif", + " } else", + " { eoi = rand()%%ooi;", + "#ifdef VERBOSE", + " printf(\"randomizer: skip %%d in %%d\\n\", eoi, ooi);", + "#endif", + " for (t = trans[ot][tt]; t; t = t->nxt)", + " if (eoi-- <= 0) break;", + " }", + "DOMORE:", + " for ( ; t && ooi > 0; t = t->nxt, ooi--)", + "#else", " for (t = trans[ot][tt]; t; t = t->nxt)", + "#endif", " {", "#ifdef HAS_UNLESS", " /* exploring all transitions from", @@ -833,15 +1972,13 @@ " break;", " }", "#endif", - "#ifdef EVENT_TRACE", - " (trpt+1)->o_t = t;", - "#endif", + " (trpt+1)->o_t = t;", /* for uerror */ "#ifdef INLINE", "#include FORWARD_MOVES", + "P999: /* jumps here when move succeeds */", "#else", - " if (!(m = do_transit(t, II, n))) continue;", + " if (!(_m = do_transit(t, II))) continue;", "#endif", - "P999: /* jumps here when move succeeds */", " if (boq == -1)", "#ifdef CTL", " /* for branching-time, can accept reduction only if */", @@ -868,12 +2005,16 @@ " tt, t->st, t->tp,", " (t->atom&2)?\"atomic\":\"\",", " (boq != -1)?\"rendez-vous\":\"\");", - "#ifdef HAS_UNLESS", - " if (t->e_trans)", - " printf(\" (escapes to state %%d)\", t->st);", - "#endif", - " printf(\" %%saccepting [tau=%%d]\\n\",", - " (trpt->o_pm&2)?\"\":\"non-\", trpt->tau);", + "#ifdef HAS_UNLESS", + " if (t->e_trans)", + " printf(\" (escapes to state %%d)\",", + " t->st);", + "#endif", + " printf(\" %%saccepting [tau=%%d]\\n\",", + " (trpt->o_pm&2)?\"\":\"non-\", trpt->tau);", + "#endif", + "#ifdef RANDOMIZE", + " printf(\" randomizer %%d\\n\", ooi);", "#endif", "#endif", @@ -888,7 +2029,7 @@ "#endif", " depth++; trpt++;", - " trpt->pr = II;", + " trpt->pr = (uchar) II;", " trpt->st = tt;", " trpt->o_pm &= ~(2|4);", " if (t->st > 0)", @@ -897,8 +2038,11 @@ " }", "#ifndef SAFETY", " if (a_cycles)", - " { int ii;", - "#define PQ ((P0 *)pptr(ii))", + " {", + "#if (ACCEPT_LAB>0 && !defined(NP)) || (PROG_LAB>0 && defined(HAS_NP))", + " int ii;", + "#endif", + "#define P__Q ((P0 *)pptr(ii))", "#if ACCEPT_LAB>0", "#ifdef NP", " /* state 1 of np_ claim is accepting */", @@ -906,7 +2050,7 @@ " trpt->o_pm |= 2;", "#else", " for (ii = 0; ii < (int) now._nr_pr; ii++)", - " { if (accpstate[PQ->_t][PQ->_p])", + " { if (accpstate[P__Q->_t][P__Q->_p])", " { trpt->o_pm |= 2;", " break;", " } }", @@ -914,18 +2058,21 @@ "#endif", "#if defined(HAS_NP) && PROG_LAB>0", " for (ii = 0; ii < (int) now._nr_pr; ii++)", - " { if (progstate[PQ->_t][PQ->_p])", + " { if (progstate[P__Q->_t][P__Q->_p])", " { trpt->o_pm |= 4;", " break;", " } }", "#endif", - "#undef PQ", + "#undef P__Q", " }", "#endif", - " trpt->o_t = t; trpt->o_n = n;", + " trpt->o_t = t; trpt->o_n = _n;", " trpt->o_ot = ot; trpt->o_tt = tt;", - " trpt->o_To = To; trpt->o_m = m;", + " trpt->o_To = To; trpt->o_m = _m;", " trpt->tau = 0;", +"#ifdef RANDOMIZE", + " trpt->oo_i = ooi;", +"#endif", " if (boq != -1 || (t->atom&2))", " { trpt->tau |= 8;", "#ifdef VERI", @@ -980,7 +2127,7 @@ "#ifndef NOFAIR", " if (trpt->o_pm&128) /* fairness alg */", " { now._cnt[now._a_t&1] = trpt->bup.oval;", - " n = 1; trpt->o_pm &= ~128;", + " _n = 1; trpt->o_pm &= ~128;", " depth--; trpt--;", "#if defined(VERBOSE) || defined(CHECK)", " printf(\"%%3d: reversed fairness default move\\n\", depth);", @@ -1010,12 +2157,15 @@ " if ((now._a_t&1) && depth <= A_depth)", " return; /* to checkcycles() */", "#endif", - " t = trpt->o_t; n = trpt->o_n;", + " t = trpt->o_t; _n = trpt->o_n;", " ot = trpt->o_ot; II = trpt->pr;", " tt = trpt->o_tt; this = pptr(II);", - " To = trpt->o_To; m = trpt->o_m;", + " To = trpt->o_To; _m = trpt->o_m;", +"#ifdef RANDOMIZE", + " ooi = trpt->oo_i;", +"#endif", "#ifdef INLINE_REV", - " m = do_reverse(t, II, m);", + " _m = do_reverse(t, II, _m);", "#else", "#include REVERSE_MOVES", "R999: /* jumps here when done */", @@ -1043,11 +2193,11 @@ "#endif", " depth--; trpt--;", "#ifdef NIBIS", - " (trans[ot][tt])->om = m; /* head of list */", + " (trans[ot][tt])->om = _m; /* head of list */", "#endif", " /* i.e., not set if rv fails */", - " if (m)", + " if (_m)", " {", "#if defined(VERI) && !defined(NP)", " if (II == 0 && verbose && !reached[ot][t->st])", @@ -1058,15 +2208,30 @@ " }", "#endif", " reached[ot][t->st] = 1;", + " reached[ot][tt] = 1;", " }", "#ifdef HAS_UNLESS", " else trpt->e_state = 0; /* undo */", "#endif", - " if (m>n||(n>3&&m!=0)) n=m;", + " if (_m>_n||(_n>3&&_m!=0)) _n=_m;", " ((P0 *)this)->_p = tt;", " } /* all options */", + "#ifdef RANDOMIZE", + " if (!t && ooi > 0)", /* means we skipped some initial options */ + " { t = trans[ot][tt];", + "#ifdef VERBOSE", + " printf(\"randomizer: continue for %%d more\\n\", ooi);", + "#endif", + " goto DOMORE;", + " }", + "#ifdef VERBOSE", + " else", + " printf(\"randomizer: done\\n\");", + "#endif", + "#endif", + "#ifndef NOFAIR", " /* Fairness: undo Rule 2 */", " if ((trpt->o_pm&32)",/* rule 2 was applied */ @@ -1085,7 +2250,7 @@ "#endif", " trpt->o_pm &= ~(32|64);", " } else", /* process blocked */ - " { if (n > 0)", /* a prev proc didn't */ + " { if (_n > 0)", /* a prev proc didn't */ " {", /* start over */ " trpt->o_pm &= ~64;", " II = From+1;", @@ -1118,7 +2283,7 @@ * by stuttering extension, here or elsewhere */ " if (fairness", - " && n == 0 /* nobody moved */", + " && _n == 0 /* nobody moved */", "#ifdef VERI", " && !(trpt->tau&4) /* in program move */", "#endif", @@ -1132,13 +2297,13 @@ "#endif", "#ifndef NOREDUCE", " /* see below */", - " && !((trpt->tau&32) && (n == 0 || (trpt->tau&16)))", + " && !((trpt->tau&32) && (_n == 0 || (trpt->tau&16)))", "#endif", " && now._cnt[now._a_t&1] > 0) /* needed more procs */", " { depth++; trpt++;", " trpt->o_pm |= 128 | ((trpt-1)->o_pm&(2|4));", " trpt->bup.oval = now._cnt[now._a_t&1];", - " now._cnt[now._a_t&1] = 1; /* gh,1/99 was 0 */", + " now._cnt[now._a_t&1] = 1;", "#ifdef VERI", " trpt->tau = 4;", "#else", @@ -1152,7 +2317,7 @@ " goto Down;", " }", "#endif", - "Q999: /* returns here with n>0 when done */;", + "Q999: /* returns here with _n>0 when done */;", " if (trpt->o_pm&8)", " { now._a_t &= ~2;", @@ -1180,10 +2345,10 @@ " if ((trpt->tau&32) && !(trpt->tau&64))", " { From = now._nr_pr-1; To = BASE;", "#ifdef DEBUG", - " printf(\"%%3d: proc %%d UnSelected (n=%%d, tau=%%d)\\n\", ", - " depth, II+1, n, trpt->tau);", + " printf(\"%%3d: proc %%d UnSelected (_n=%%d, tau=%%d)\\n\", ", + " depth, II+1, _n, trpt->tau);", "#endif", - " n = 0; trpt->tau &= ~(16|32|64);", + " _n = 0; trpt->tau &= ~(16|32|64);", " if (II >= BASE) /* II already decremented */", " goto Resume;", " else", @@ -1193,11 +2358,11 @@ " /* at least one move that was preselected at this */", " /* level, blocked or truncated at the next level */", "/* implied: #ifdef FULLSTACK */", - " if ((trpt->tau&32) && (n == 0 || (trpt->tau&16)))", + " if ((trpt->tau&32) && (_n == 0 || (trpt->tau&16)))", " {", "#ifdef DEBUG", - " printf(\"%%3d: proc %%d UnSelected (n=%%d, tau=%%d)\\n\", ", - " depth, II+1, n, trpt->tau);", + " printf(\"%%3d: proc %%d UnSelected (_n=%%d, tau=%%d)\\n\", ", + " depth, II+1, (int) _n, trpt->tau);", "#endif", " if (a_cycles && (trpt->tau&16))", " { if (!(now._a_t&1))", @@ -1229,12 +2394,12 @@ "#endif", "#endif", " From = now._nr_pr-1; To = BASE;", - " n = 0; trpt->tau &= ~(16|32|64);", + " _n = 0; trpt->tau &= ~(16|32|64);", " goto Again; /* do full search */", " } /* else accept reduction */", " } else", " { From = now._nr_pr-1; To = BASE;", - " n = 0; trpt->tau &= ~(16|32|64);", + " _n = 0; trpt->tau &= ~(16|32|64);", " if (II >= BASE) /* already decremented */", " goto Resume;", " else", @@ -1244,7 +2409,7 @@ "#endif", "#endif", - " if (n == 0 || ((trpt->tau&4) && (trpt->tau&2)))", + " if (_n == 0 || ((trpt->tau&4) && (trpt->tau&2)))", " {", "#ifdef DEBUG", " printf(\"%%3d: no move [II=%%d, tau=%%d, boq=%%d]\\n\",", @@ -1255,19 +2420,18 @@ " if (boq != -1) goto Done;", "#endif", " /* ok if no procs or we're at maxdepth */", - " if (now._nr_pr == 0", + " if ((now._nr_pr == 0 && (!strict || qs_empty()))", "#ifdef OTIM", " || endstate()", "#endif", " || depth >= maxdepth-1) goto Done;", - /* new location of atomic block code -- BEFORE timeout */ " if ((trpt->tau&8) && !(trpt->tau&4))", " { trpt->tau &= ~(1|8);", " /* 1=timeout, 8=atomic */", " From = now._nr_pr-1; To = BASE;", "#ifdef DEBUG", - " printf(\"%%3d: atomic step proc %%d \", depth, II);", + " printf(\"%%3d: atomic step proc %%d \", depth, II+1);", " printf(\"unexecutable\\n\");", "#endif", "#ifdef VERI", @@ -1316,15 +2480,10 @@ "#endif", /* old location of atomic block code */ - "BreakOut:", "#ifdef VERI", - "#ifndef NOSTUTTER", -#if 1 + "BreakOut:", + "#ifndef NOSTUTTER", " if (!(trpt->tau&4))", -#else - /* visser's example shows this is insufficient: */ - " if ((now._a_t&1) && !(trpt->tau&4))", -#endif " { trpt->tau |= 4; /* claim stuttering */", " trpt->tau |= 128; /* stutter mark */", "#ifdef DEBUG", @@ -1332,17 +2491,29 @@ "#endif", " goto Stutter;", " }", - "#endif", + "#else", + " ;", + "#endif", "#else", " if (!noends && !a_cycles && !endstate())", - " uerror(\"invalid endstate\");", + " { depth--; trpt--; /* new 4.2.3 */", + " uerror(\"invalid end state\");", + " depth++; trpt++;", + " }", + "#ifndef NOSTUTTER", + " else if (a_cycles && (trpt->o_pm&2)) /* new 4.2.4 */", + " { depth--; trpt--;", + " uerror(\"accept stutter\");", + " depth++; trpt++;", + " }", + "#endif", "#endif", " }", "Done:", " if (!(trpt->tau&8)) /* not in atomic seqs */", " {", "#ifndef SAFETY", - " if (n != 0", /* we made a move */ + " if (_n != 0", /* we made a move */ "#ifdef VERI", " /* --after-- a program-step, i.e., */", " /* after backtracking a claim-step */", @@ -1354,12 +2525,23 @@ " && !(now._a_t&1))", /* not in 2nd DFS */ " {", "#ifndef NOFAIR", - " if (fairness)", + " if (fairness)", /* implies a_cycles */ " {", "#ifdef VERBOSE", " printf(\"Consider check %%d %%d...\\n\",", " now._a_t, now._cnt[0]);", "#endif", +#if 0 + the a-bit is set, which means that the fairness + counter is running -- it was started in an accepting state. + we check that the counter reached 1, which means that all + processes moved least once. + this means we can start the search for cycles - + to be able to return to this state, we should be able to + run down the counter to 1 again -- which implies a visit to + the accepting state -- even though the Seed state for this + search is itself not necessarily accepting +#endif " if ((now._a_t&2) /* A-bit */", " && (now._cnt[0] == 1))", " checkcycles();", @@ -1411,25 +2593,22 @@ " }", " if (depth > 0) goto Up;", "}\n", + "#else", + "void new_state(void) { /* place holder */ }", + "#endif", /* BFS */ + "", "void", "assert(int a, char *s, int ii, int tt, Trans *t)", "{", " if (!a && !noasserts)", " { char bad[1024];", - " if (strlen(s) > 999) s[999] = '\\0';", - " sprintf(bad, \"assertion violated %%s\", s);", - " depth++; trpt++;", - " if (t) {", - " trpt->pr = ii;", - " trpt->st = tt;", - " trpt->o_t = t;", - " } else {", - " trpt->pr = (trpt-1)->pr;", - " trpt->st = (trpt-1)->st;", - " trpt->o_t = (trpt-1)->o_t;", - " }", + " strcpy(bad, \"assertion violated \");", + " if (strlen(s) > 1000)", + " { strncpy(&bad[19], (const char *) s, 1000);", + " bad[1019] = '\\0';", + " } else", + " strcpy(&bad[19], s);", " uerror(bad);", - " depth--; trpt--;", " }", "}", "#ifndef NOBOUNDCHECK", @@ -1443,15 +2622,25 @@ "#endif", "void", "wrap_stats(void)", - "{ double a, b;", - "#ifdef COVEST", - " extern double log(double);\n", - "#endif", + "{", " if (nShadow>0)", - " printf(\"%%8g states, stored (%%g visited)\\n\",", + " printf(\"%%8g states, stored (%%g visited)\\n\",", " nstates - nShadow, nstates);", " else", - " printf(\"%%8g states, stored\\n\", nstates);", + " printf(\"%%8g states, stored\\n\", nstates);", + "#ifdef BFS", + "#if SYNC", + " printf(\" %%8g nominal states (- rv and atomic)\\n\", nstates-midrv-nlinks+revrv);", + " printf(\" %%8g rvs succeeded\\n\", midrv-failedrv);", + "#else", + " printf(\" %%8g nominal states (stored-atomic)\\n\", nstates-nlinks);", + "#endif", + "#ifdef DEBUG", + " printf(\" %%8g midrv\\n\", midrv);", + " printf(\" %%8g failedrv\\n\", failedrv);", + " printf(\" %%8g revrv\\n\", revrv);", + "#endif", + "#endif", " printf(\"%%8g states, matched\\n\", truncs);", "#ifdef CHECK", " printf(\"%%8g matches within stack\\n\",truncs2);", @@ -1463,68 +2652,108 @@ " printf(\"%%8g transitions (= stored+matched)\\n\",", " nstates+truncs);", " printf(\"%%8g atomic steps\\n\", nlinks);", - " if (nlost) printf(\"%%g lost messages\\n\", (double)nlost);", - "#ifdef BITSTATE", - "#ifdef CHECK", - " printf(\"%%8g states allocated for dfs stack\\n\", ngrabs);", - "#endif", - " a = (double) (1<<(ssize-3)); a = 8.*a; /* avoid overflow on << */", - " b = nstates+1.;", - "#ifdef COVEST", - " printf(\"coverage estimate: %%0.1f%%%%\\n\",", - " (100.*b)/(log(1. - b / a)/log(1. - 1. / a)));", - "#endif", - " printf(\"hash factor: %%g \", a/b);", - " if (!single)", - " { if (a/b > 100.)", - "#ifdef COVEST", - " printf(\"(good confidence estimate)\\n\");", - " else if (a/b > 10.)", - " printf(\"(medium confidence estimate)\\n\");", - " else", - " printf(\"(low confidence estimate, best if >100)\\n\");", - " } else", - " { if (a/b > 1000.)", - " printf(\"(good confidence estimate)\\n\");", - " else if (a/b > 100.)", - " printf(\"(medium confidence estimate)\\n\");", - " else", - " printf(\"(low confidence estimate (1-bit hash), best if >1000)\\n\");", + " if (nlost) printf(\"%%g lost messages\\n\", (double) nlost);", + "", + "#ifndef BITSTATE", + " printf(\"hash conflicts: %%g (resolved)\\n\", hcmp);", "#else", - " printf(\"(expected coverage: >= 99.9%%%% on avg.)\\n\");", - " else if (a/b > 10.)", - " printf(\"(expected coverage: >= 98%%%% on avg.)\\n\");", - " else", - " printf(\"(best coverage if >100)\\n\");", - " } else", - " { if (a/b > 1000.)", - " printf(\"(expected coverage: >= 99.9%%%% on avg.)\\n\");", - " else if (a/b > 100.)", - " printf(\"(expected coverage: >= 98%%%% on avg.)\\n\");", - " else", - " printf(\"(best coverage (1-bit hash) if >1000)\\n\");", + "#ifdef CHECK", + " printf(\"%%8g states allocated for dfs stack\\n\", ngrabs);", + "#endif", + " printf(\"\\nhash factor: %%4g (best if > 100.)\\n\\n\",", + " (double)(1<<(ssize-8)) / (double) nstates * 256.0);", + " printf(\"bits set per state: %%u (-k%%u)\\n\", hfns, hfns);", + "#if 0", +#ifndef POWOW + " if (udmem)", + " printf(\"total bits available: %%8g (-M%%ld)\\n\",", + " ((double) udmem) * 8.0, udmem/(1024L*1024L));", + " else", +#endif + " printf(\"total bits available: %%8g (-w%%d)\\n\",", + " ((double) (1L << (ssize-4)) * 16.0), ssize);", "#endif", - " }", - - "#else", - " printf(\"hash conflicts: %%g (resolved)\\n\", hcmp);", +"#ifdef COVEST", + " /* this code requires compilation with -lm on some systems */", + " { double pow(double, double);", + " double log(double);", + " unsigned int best_k;", + " double i, n = 30000.0L;", + " double f, p, q, m, c, est = 0.0L, k = (double)hfns;", + " c = (double) nstates / n;", + " m = (double) (1<<(ssize-8)) * 256.0L / c;", + " p = 1.0L - (k / m); q = 1.0L;", + " for (i = 0.0L; i - est < n; i += 1.0L)", + " { q *= p;", + " est += pow(1.0L - q, k);", + " }", + " f = m/i;", + " est *= c;", + " i *= c;", + " /* account for loss from enhanced double hashing */", + " if (hfns > 2) est += i * pow(0.5, (double) ssize * 2.0);", + "", + " if (f < 1.134) best_k = 1;", + " else if (f < 2.348) best_k = 2;", + " else if (f < 3.644) best_k = 3;", + " else best_k = (unsigned int) (pow(3.8L,1.0L/(f+4.2L))*f*.69315L + 0.99999999L);", + "", + " if (best_k != hfns && best_k > ssize)", + " best_k = (unsigned int) 1.0 + ssize/log((double)best_k / (double)ssize + 3.0);", + "", + " if (best_k > 32)", + " best_k = 1 + (unsigned int) (32.0/log((double)best_k/35.0));", + "", + " if (est * (double) nstates < 1.0)", + " { printf(\"prob. of omissions: negligible\\n\");", + " return; /* no hints needed */", + " }", + "", + " if (best_k != hfns)", + " { printf(\"hint: repeating the search with -k%%u \", best_k);", + " printf(\"may increase accuracy\\n\");", + " } else", + " { printf(\"hint: the current setting for -k (-k%%d) \", hfns);", + " printf(\"is likely to be optimal for -w%%d\\n\", ssize);", + " }", + " if (ssize < 32)", + " { printf(\"hint: increasing -w above -w%%d \", ssize);", + " printf(\"will increase accuracy (max is -w34)\\n\");", + " printf(\"(in xspin, increase Estimated State Space Size)\\n\");", + " } }", +"#endif", "#endif", "}", "void", "wrapup(void)", - "{ double nr1, nr2, nr3 = 0.0, nr4;", - "#ifndef BITSTATE", - " double tmp_nr;", + "{", + "#if defined(BITSTATE) || !defined(NOCOMP)", + " double nr1, nr2, nr3 = 0.0, nr4, nr5 = 0.0;", + "#if !defined(MA) && (defined(MEMCNT) || defined(MEMLIM))", + " int mverbose = 1;", + "#else", + " int mverbose = verbose;", + "#endif", "#endif", + + " signal(SIGINT, SIG_DFL);", " printf(\"(%%s)\\n\", Version);", " if (!done) printf(\"Warning: Search not completed\\n\");", "#ifdef SC", " (void) unlink((const char *)stackfile);", "#endif", + "#ifdef BFS", + " printf(\" + Using Breadth-First Search\\n\");", + "#endif", "#ifndef NOREDUCE", " printf(\" + Partial Order Reduction\\n\");", "#endif", +#if 0 + "#ifdef QPROVISO", + " printf(\" + Queue Proviso\\n\");", + "#endif", +#endif "#ifdef COLLAPSE", " printf(\" + Compression\\n\");", "#endif", @@ -1559,7 +2788,7 @@ "#endif", "#endif", "#ifdef VERI", - " printf(\"\tnever-claim \t+\\n\");", + " printf(\"\tnever claim \t+\\n\");", " printf(\"\tassertion violations\t\");", " if (noasserts)", " printf(\"- (disabled by -A flag)\\n\");", @@ -1567,9 +2796,9 @@ " printf(\"+ (if within scope of claim)\\n\");", "#else", "#ifdef NOCLAIM", - " printf(\"\tnever-claim \t- (not selected)\\n\");", + " printf(\"\tnever claim \t- (not selected)\\n\");", "#else", - " printf(\"\tnever-claim \t- (none specified)\\n\");", + " printf(\"\tnever claim \t- (none specified)\\n\");", "#endif", " printf(\"\tassertion violations\t\");", " if (noasserts)", @@ -1591,14 +2820,14 @@ " printf(\"\tcycle checks \t- (disabled by -DSAFETY)\\n\");", "#endif", "#ifdef VERI", - " printf(\"\tinvalid endstates\t- \");", + " printf(\"\tinvalid end states\t- \");", " printf(\"(disabled by \");", " if (noends)", " printf(\"-E flag)\\n\\n\");", " else", - " printf(\"never-claim)\\n\\n\");", + " printf(\"never claim)\\n\\n\");", "#else", - " printf(\"\tinvalid endstates\t\");", + " printf(\"\tinvalid end states\t\");", " if (noends)", " printf(\"- (disabled by -E flag)\\n\\n\");", " else", @@ -1617,66 +2846,81 @@ " }", "#endif", " wrap_stats();", - " printf(\"(max size 2^%%d states\", ssize);", - "#ifdef CHECK", - " printf(\", stackframes: %%d/%%d)\\n\\n\", smax, svmax);", + " printf(\"stackframes: %%d/%%d\\n\\n\", smax, svmax);", " printf(\"stats: fa %%d, fh %%d, zh %%d, zn %%d - \",", " Fa, Fh, Zh, Zn);", " printf(\"check %%d holds %%d\\n\", Ccheck, Cholds);", " printf(\"stack stats: puts %%d, probes %%d, zaps %%d\\n\",", " PUT, PROBE, ZAPS);", "#else", - " printf(\")\\n\\n\");", + " printf(\"\\n\");", "#endif", - - "#ifdef MEMCNT", + "", "#if defined(BITSTATE) || !defined(NOCOMP)", " nr1 = (nstates-nShadow)*", " (double)(hmax+sizeof(struct H_el)-sizeof(unsigned));", + "#ifdef BFS", + " nr2 = 0.0;", + "#else", " nr2 = (double) ((maxdepth+3)*sizeof(Trail));", - "#ifndef BITSTATE", - "#if !defined(MA) || defined(COLLAPSE)", - " nr3 = (double) (1< 0.0)", + " printf(\"%%-6.3f\tmemory used for bit stack\\n\",", + " nr5/1000000.);", + " remainder = remainder - nr3 - nr5;", + "#else", " printf(\"%%-6.3f\tactual memory usage for states\",", " tmp_nr/1000000.);", + " remainder = remainder - tmp_nr;", " printf(\" (\");", " if (tmp_nr > 0.)", - " { if (tmp_nr > nr1)", - " printf(\"unsuccessful \");", + " { if (tmp_nr > nr1) printf(\"unsuccessful \");", " printf(\"compression: %%.2f%%%%)\\n\",", " (100.0*tmp_nr)/nr1);", " } else", " printf(\"less than 1k)\\n\");", - "#ifndef MA", + "#ifndef MA", " if (tmp_nr > 0.)", " { printf(\"\tState-vector as stored = %%.0f byte\",", " (tmp_nr)/(nstates-nShadow) -", @@ -1684,25 +2928,36 @@ " printf(\" + %%d byte overhead\\n\",", " sizeof(struct H_el)-sizeof(unsigned));", " }", - "#endif", - "#if !defined(MA) || defined(COLLAPSE)", - " printf(\"%%-6.3f\tmemory used for hash-table (-w%%d)\\n\",", + "#endif", + "#if !defined(MA) || defined(COLLAPSE)", + " printf(\"%%-6.3f\tmemory used for hash table (-w%%d)\\n\",", " nr3/1000000., ssize);", + " remainder = remainder - nr3;", + "#endif", "#endif", - "#endif", + "#ifndef BFS", " printf(\"%%-6.3f\tmemory used for DFS stack (-m%%d)\\n\",", " nr2/1000000., maxdepth);", - " /* remainder is mem used for proc and chan stacks */", - " /* and memory lost in allocator (=fragment) */", + "#endif", + " if (remainder - fragment > 0.0)", + " printf(\"%%-6.3f\tother (proc and chan stacks)\\n\",", + " (remainder-fragment)/1000000.);", + " if (fragment > 0.0)", + " printf(\"%%-6.3f\tmemory lost to fragmentation\\n\",", + " fragment/1000000.);", " printf(\"%%-6.3f\ttotal actual memory usage\\n\\n\",", " memcnt/1000000.);", - " } else", + " }", + "#ifndef MA", + " else", + "#endif", "#endif", + "#ifndef MA", " printf(\"%%-6.3f\tmemory usage (Mbyte)\\n\\n\",", " memcnt/1000000.);", - "#endif", + "#endif", "#ifdef COLLAPSE", - " printf(\"nr of templates: [ globals procs chans ]\\n\");", + " printf(\"nr of templates: [ globals chans procs ]\\n\");", " printf(\"collapse counts: [ \");", " { int i; for (i = 0; i < 256+2; i++)", " if (ncomps[i] != 0)", @@ -1725,139 +2980,109 @@ "#ifdef SVDUMP", " if (vprefix > 0) close(svfd);", "#endif", - " exit(0);", + " pan_exit(0);", "}\n", "void", - "stopped(int arg)", - "{ printf(\"Interrupted\\n\");", - " wrapup();", + "stopped(int arg)", + "{ printf(\"Interrupted\\n\");", + " wrapup();", + "}", + "/*", + " * based on Bob Jenkins hash-function from 1996", + " * see: http://www.burtleburtle.net/bob/", + " */", + "", +"#ifdef HASH64", + /* 64-bit Jenkins hash: http://burtleburtle.net/bob/c/lookup8.c */ + "#define mix(a,b,c) \\", + "{ a -= b; a -= c; a ^= (c>>43); \\", + " b -= c; b -= a; b ^= (a<<9); \\", + " c -= a; c -= b; c ^= (b>>8); \\", + " a -= b; a -= c; a ^= (c>>38); \\", + " b -= c; b -= a; b ^= (a<<23); \\", + " c -= a; c -= b; c ^= (b>>5); \\", + " a -= b; a -= c; a ^= (c>>35); \\", + " b -= c; b -= a; b ^= (a<<49); \\", + " c -= a; c -= b; c ^= (b>>11); \\", + " a -= b; a -= c; a ^= (c>>12); \\", + " b -= c; b -= a; b ^= (a<<18); \\", + " c -= a; c -= b; c ^= (b>>22); \\", + "}", +"#else", + "#define mix(a,b,c) \\", + "{ a -= b; a -= c; a ^= (c>>13); \\", + " b -= c; b -= a; b ^= (a<<8); \\", + " c -= a; c -= b; c ^= (b>>13); \\", + " a -= b; a -= c; a ^= (c>>12); \\", + " b -= c; b -= a; b ^= (a<<16); \\", + " c -= a; c -= b; c ^= (b>>5); \\", + " a -= b; a -= c; a ^= (c>>3); \\", + " b -= c; b -= a; b ^= (a<<10); \\", + " c -= a; c -= b; c ^= (b>>15); \\", + "}", +"#endif", + "void", + "d_hash(uchar *Cp, int Om) /* double bit hash - Jenkins */", + "{ unsigned long a = 0x9e3779b9, b, c = 0, len, length;", + " unsigned long *k = (unsigned long *) Cp;", + "", + " length = len = (unsigned long) ((unsigned long) Om + WS-1)/WS;", + "", + " b = HASH_CONST[HASH_NR];", + " while (len >= 3)", + " { a += k[0];", + " b += k[1];", + " c += k[2];", + " mix(a,b,c);", + " k += 3; len -= 3;", + " }", + " c += length;", + " switch (len) {", + " case 2: b += k[1];", + " case 1: a += k[0];", + " }", + " mix(a,b,c);", + " j1 = c&nmask; j3 = a&7;", /* 1st bit */ + " j2 = b&nmask; j4 = (a>>3)&7;", /* 2nd bit */ + " K1 = c; K2 = b;", /* no nmask */ "}", "void", - "d_hash(uchar *Cp, int Om)", - "{ long z = (long) HASH_CONST[HASH_NR];", - " long *q, *r, h;", - " long m, n;", - "#ifndef BCOMP", - " uchar *cp = Cp;", - " long om = (long) Om;", - "#else", - " uchar *cp = (uchar *) &comp_now;", - " char *vv = (char *) Cp;", - " char *v = (char *) &comp_now;", - " long i, om;", - " for (i = 0; i < Om; i++, vv++)", - " if (!Mask[i]) *v++ = *vv;", - " for (i = 0; i < WS-1; i++)", - " *v++ = 0;", - " v -= i;", - " om = v - (char *)&comp_now;", - "#endif", - " h = (om+sizeof(long)-1)/sizeof(long);", - " m = n = -1;", - " q = r = (long *) cp;", - " r += (long) h;", - " do {", - " if (m < 0)", - " { m += m;", - " m ^= z;", - " } else", - " m += m;", - " m ^= *q++;", - " if (n < 0)", - " { n += n;", - " n ^= z;", - " } else", - " n += n;", - " n ^= *--r;", - " } while (--h > 0);", - " J1 = (m ^ (m>>(8*sizeof(long)-ssize)))&mask;", - " J2 = (n ^ (n>>(8*sizeof(long)-ssize)))&mask;", - "#if 0", - " j3 = (1<<(J1&7)); j1 = J1>>3;", - " j4 = (1<<(J2&7)); j2 = J2>>3;", - "#endif", - " if (!single)", - " { j3 = (1<<(J1&7)); j2 = J2>>3;", - " j4 = (1<<(J2&7)); j1 = J1>>3;", - " } else /* single-bit address */", - " { J1 = J1^J2; /* use all bits */", - " j3 = (1<<(J1&7)); j2 = J1>>3;", - " j1 = 0; j4 = 1;", - " }", - "}\n", - "#ifdef HYBRID_HASH", - "long", - "#else", - "void", - "#endif", - "s_hash(uchar *cp, int om) /* single forward hash */", - "{ long z = (long) HASH_CONST[HASH_NR];", - " long *q;", - " long h;", - " long m = -1;", - " h = (om+sizeof(long)-1)/sizeof(long);", - " q = (long *) cp;", - " do {", - " if (m < 0)", - " { m += m;", - " m ^= z;", - " } else", - " m += m;", - " m ^= *q++;", - " } while (--h > 0);", + "s_hash(uchar *cp, int om)", + "{ d_hash(cp, om); /* sets K1 and K2 */", "#ifdef BITSTATE", - " if (S_Tab == H_tab)", - " j1 = (m^(m>>(8*sizeof(long)-(ssize-3))))&((1<<(ssize-3))-1);", + " if (S_Tab == H_tab)", /* state stack in bitstate search */ + " j1 = K1 %% omaxdepth;", " else", - "#endif", - " j1 = (m^(m>>(8*sizeof(long)-ssize)))&mask;", - "#ifdef HYBRID_HASH", - "#ifndef BITSTATE", - " if ((om&(sizeof(void *)-1)) == 1) /* very badly aligned */", - " { /* use last data byte as first byte of hash */", - " j1 = (j1 & (~255)) | cp[om-1];", - " return om-1; /* perfect alignment */", - " }", - "#endif", - " return om;", - "#endif", - "}", - "#if defined(HC) || (defined(BITSTATE) && defined(LC))", - "void", - "r_hash(uchar *cp, int om) /* reverse direction from s_hash */", - "{ long z = (long) HASH_CONST[HASH_NR];", - " long *r, h, n = -1;", - " h = (om+sizeof(long)-1)/sizeof(long);", - " r = (long *) cp + h;", - " do {", - " if (n < 0)", - " { n += n;", - " n ^= z;", - " } else", - " n += n;", - " n ^= *--r;", - " } while (--h > 0);", - " J3 = n; /* the compressed state vector */", - " n = -1; /* forward hash for hash_table index */", - " h = (om+sizeof(long)-1)/sizeof(long);", - " r = (long *) cp;", - " do {", - " if (n < 0)", - " { n += n;", - " n ^= z;", - " } else", - " n += n;", - " n ^= *r++;", - " } while (--h > 0);", - " J4 = n; /* more bits, when needed */", - " j1 = (n^(n>>(8*sizeof(long)-ssize)))&((1<<(ssize-3))-1);", + "#endif", /* if (S_Tab != H_Tab) */ + " if (ssize < 8*WS)", + " j1 = K1&mask;", + " else", + " j1 = K1;", + "}", + "#ifndef RANDSTOR", + "int *prerand;", + "void", + "inirand(void)", + "{ int i;", + " srand(123); /* fixed startpoint */", + " prerand = (int *) emalloc((omaxdepth+3)*sizeof(int));", + " for (i = 0; i < omaxdepth+3; i++)", + " prerand[i] = rand();", + "}", + "int", + "pan_rand(void)", + "{ if (!prerand) inirand();", + " return prerand[depth];", "}", "#endif", - "unsigned long TMODE = 0666; /* default permission bits for trail files */", + "", "int", "main(int argc, char *argv[])", "{ void to_compile(void);\n", " efd = stderr; /* default */", + "#ifdef BITSTATE", + " bstore = bstore_reg; /* default */", + "#endif", " while (argc > 1 && argv[1][0] == '-')", " { switch (argv[1][1]) {", "#ifndef SAFETY", @@ -1869,9 +3094,10 @@ "#endif", "#endif", " case 'A': noasserts = 1; break;", + " case 'b': bounded = 1; break;", " case 'c': upto = atoi(&argv[1][2]); break;", " case 'd': state_tables++; break;", - " case 'e': every_error = 1; break;", + " case 'e': every_error = 1; Nr_Trails = 1; break;", " case 'E': noends = 1; break;", "#ifdef SC", " case 'F': if (strlen(argv[1]) > 2)", @@ -1886,6 +3112,9 @@ " case 'I': iterative = 2; every_error = 1; break;", " case 'i': iterative = 1; every_error = 1; break;", " case 'J': like_java = 1; break; /* Klaus Havelund */", + "#ifdef BITSTATE", + " case 'k': hfns = atoi(&argv[1][2]); break;", + "#endif", "#ifndef SAFETY", "#ifdef NP", " case 'l': a_cycles = 1; break;", @@ -1894,31 +3123,96 @@ " usage(efd); break;", "#endif", "#endif", +#ifndef POWOW + "#ifdef BITSTATE", + " case 'M': udmem = atoi(&argv[1][2]); break;", + " case 'G': udmem = atoi(&argv[1][2]); udmem *= 1024; break;", + "#else", + " case 'M': case 'G':", + " fprintf(stderr, \"-M and -G affect only -DBITSTATE\\n\");", + " break;", + "#endif", +#endif " case 'm': maxdepth = atoi(&argv[1][2]); break;", " case 'n': no_rck = 1; break;", "#ifdef SVDUMP", " case 'p': vprefix = atoi(&argv[1][2]); break;", "#endif", " case 'q': strict = 1; break;", + "#ifdef HAS_CODE", + " case 'r':", + "samething: readtrail = 1;", + " if (isdigit(argv[1][2]))", + " whichtrail = atoi(&argv[1][2]);", + " break;", + " case 'P': readtrail = 1; onlyproc = atoi(&argv[1][2]); break;", + " case 'C': coltrace = 1; goto samething;", + " case 'g': gui = 1; goto samething;", + "#endif", " case 'R': Nrun = atoi(&argv[1][2]); break;", - " case 's': single = 1; break;", + "#ifdef BITSTATE", + " case 's': hfns = 1; break;", + "#endif", " case 'T': TMODE = 0444; break;", " case 't': if (argv[1][2]) tprefix = &argv[1][2]; break;", " case 'V': printf(\"Generated by %%s\\n\", Version);", - " to_compile(); exit(0); break;", + " to_compile(); pan_exit(0); break;", " case 'v': verbose = 1; break;", " case 'w': ssize = atoi(&argv[1][2]); break;", + " case 'Y': signoff = 1; break;", " case 'X': efd = stdout; break;", " default : usage(efd); break;", " }", " argc--; argv++;", " }", + "#ifdef OHASH", + " fprintf(efd, \"warning: -DOHASH no longer supported (directive ignored)\\n\");", + "#endif", + "#ifdef JHASH", + " fprintf(efd, \"warning: -DJHASH no longer supported (directive ignored)\\n\");", + "#endif", + "#ifdef HYBRID_HASH", + " fprintf(efd, \"warning: -DHYBRID_HASH no longer supported (directive ignored)\\n\");", + "#endif", + "#ifdef NOCOVEST", + " fprintf(efd, \"warning: -DNOCOVEST no longer supported (directive ignored)\\n\");", + "#endif", + "#ifdef BITSTATE", + "#ifdef BCOMP", + " fprintf(efd, \"warning: -DBCOMP no longer supported (directive ignored)\\n\");", + "#endif", + " if (hfns <= 0)", + " { hfns = 1;", + " fprintf(efd, \"warning: using -k%%d as minimal usable value\\n\", hfns);", + " }", + "#endif", + " omaxdepth = maxdepth;", + "#ifdef BITSTATE", + " if (WS == 4 && ssize > 34)", /* 32-bit word size */ + " { ssize = 34;", + " fprintf(efd, \"warning: using -w%%d as max usable value\\n\", ssize);", + "/*", + " * -w35 would not work: 35-3 = 32 but 1^31 is the largest", + " * power of 2 that can be represented in an unsigned long", + " */", + " }", + "#else", + " if (WS == 4 && ssize > 27)", + " { ssize = 27;", + " fprintf(efd, \"warning: using -w%%d as max usable value\\n\", ssize);", + "/*", + " * for emalloc, the lookup table size multiplies by 4 for the pointers", + " * the largest power of 2 that can be represented in a ulong is 1^31", + " * hence the largest number of lookup table slots is 31-4 = 27", + " */", + " }", + + "#endif", " if (iterative && TMODE != 0666)", " { TMODE = 0666;", " fprintf(efd, \"warning: -T ignored when -i or -I is used\\n\");", " }", "#ifdef SC", - " omaxdepth = maxdepth;", " hiwater = HHH = maxdepth-10;", " DDD = HHH/2;", " if (!stackfile)", @@ -1927,63 +3221,94 @@ " }", " if (iterative)", " { fprintf(efd, \"error: cannot use -i or -I with -DSC\\n\");", - " exit(1);", + " pan_exit(1);", " }", "#endif", + "#if (defined(R_XPT) || defined(W_XPT)) && !defined(MA)", + " fprintf(efd, \"error: -D?_XPT requires -DMA\\n\");", + " exit(1);", + "#endif", + + " if (iterative && a_cycles)", + " fprintf(efd, \"warning: -i or -I work for safety properties only\\n\");", + + "#ifdef BFS", + "#if defined(SC)", + " fprintf(efd, \"error: -DBFS not compatible with -DSC\\n\");", + " exit(1);", + "#endif", + "#if defined(HAS_LAST)", + " fprintf(efd, \"error: -DBFS not compatible with _last\\n\");", + " exit(1);", + "#endif", + "#if defined(REACH)", + " fprintf(efd, \"warning: -DREACH redundant when -DBFS is used\\n\");", + "#endif", + "#if defined(HAS_STACK)", + " fprintf(efd, \"error: cannot use UnMatched qualifier on c_track with BFS\\n\");", + " exit(1);", + "#endif", + "#endif", + "#if defined(MERGED) && defined(PEG)", " fprintf(efd, \"error: to allow -DPEG use: spin -o3 -a %%s\\n\", Source);", " fprintf(efd, \" to turn off transition merge optimization\\n\");", - " exit(1);", + " pan_exit(1);", "#endif", "#ifdef HC", "#ifdef NOCOMP", " fprintf(efd, \"error: cannot combine -DHC and -DNOCOMP\\n\");", - " exit(1);", + " pan_exit(1);", "#endif", "#ifdef BITSTATE", " fprintf(efd, \"error: cannot combine -DHC and -DBITSTATE\\n\");", - " exit(1);", + " pan_exit(1);", "#endif", "#endif", "#if defined(SAFETY) && defined(NP)", " fprintf(efd, \"error: cannot combine -DNP and -DSAFETY\\n\");", - " exit(1);", + " pan_exit(1);", "#endif", "#ifdef MA", "#ifdef BITSTATE", " fprintf(efd, \"error: cannot combine -DMA and -DBITSTATE\\n\");", - " exit(1);", + " pan_exit(1);", "#endif", " if (MA <= 0)", " { fprintf(efd, \"usage: -DMA=N with N > 0 and < VECTORSZ\\n\");", - " exit(1);", + " pan_exit(1);", " }", "#endif", "#ifdef COLLAPSE", "#if defined(BITSTATE)", " fprintf(efd, \"error: cannot combine -DBITSTATE and -DCOLLAPSE\\n\");", - " exit(1);", + " pan_exit(1);", "#endif", "#if defined(NOCOMP)", " fprintf(efd, \"error: cannot combine -DNOCOMP and -DCOLLAPSE\\n\");", - " exit(1);", + " pan_exit(1);", "#endif", "#endif", - " if (maxdepth <= 0 || ssize <= 0) usage(efd);", + " if (maxdepth <= 0 || ssize <= 1) usage(efd);", "#if SYNC>0 && !defined(NOREDUCE)", " if (a_cycles && fairness)", " { fprintf(efd, \"error: p.o. reduction not compatible with \");", " fprintf(efd, \"fairness (-f) in models\\n\");", " fprintf(efd, \" with rendezvous operations: \");", " fprintf(efd, \"recompile with -DNOREDUCE\\n\");", - " exit(1);", + " pan_exit(1);", + " }", + "#endif", + "#if defined(REM_VARS) && !defined(NOREDUCE)", + " { fprintf(efd, \"warning: p.o. reduction not compatible with \");", + " fprintf(efd, \"remote varrefs (use -DNOREDUCE)\\n\");", " }", "#endif", "#if defined(NOCOMP) && !defined(BITSTATE)", " if (a_cycles)", " { fprintf(efd, \"error: -DNOCOMP voids -l and -a\\n\");", - " exit(1);", + " pan_exit(1);", " }", "#endif", @@ -2030,54 +3355,79 @@ "#if defined(HAS_ENABLED)", " fprintf(efd, \"error: reduced search precludes \");", " fprintf(efd, \"use of 'enabled()'\\n\");", - " exit(1);", + " pan_exit(1);", "#endif", "#if defined(HAS_PCVALUE)", " fprintf(efd, \"error: reduced search precludes \");", " fprintf(efd, \"use of 'pcvalue()'\\n\");", - " exit(1);", + " pan_exit(1);", "#endif", "#if defined(HAS_BADELSE)", " fprintf(efd, \"error: reduced search precludes \");", " fprintf(efd, \"using 'else' combined with i/o stmnts\\n\");", - " exit(1);", + " pan_exit(1);", "#endif", "#if defined(HAS_LAST)", " fprintf(efd, \"error: reduced search precludes \");", " fprintf(efd, \"use of _last\\n\");", - " exit(1);", + " pan_exit(1);", "#endif", "#endif", "#if SYNC>0 && !defined(NOREDUCE)", "#ifdef HAS_UNLESS", " fprintf(efd, \"warning: use of a rendezvous stmnts in the escape\\n\");", - " fprintf(efd, \"\tof an unless clause, could make p.o. reduction\\n\");", + " fprintf(efd, \"\tof an unless clause, if present, could make p.o. reduction\\n\");", " fprintf(efd, \"\tinvalid (use -DNOREDUCE to avoid this)\\n\");", + "#ifdef BFS", + " fprintf(efd, \"\t(this type of rv is also not compatible with -DBFS)\\n\");", + "#endif", "#endif", "#endif", "#if !defined(REACH) && !defined(BITSTATE)", - " if (iterative != 0)", + " if (iterative != 0 && a_cycles == 0)", " fprintf(efd, \"warning: -i and -I need -DREACH to work accurately\\n\");", "#endif", "#if defined(BITSTATE) && defined(REACH)", " fprintf(efd, \"warning: -DREACH voided by -DBITSTATE\\n\");", "#endif", + "#if defined(MA) && defined(REACH)", + " fprintf(efd, \"warning: -DREACH voided by -DMA\\n\");", + "#endif", "#if defined(FULLSTACK) && defined(CNTRSTACK)", " fprintf(efd, \"error: cannot combine\");", " fprintf(efd, \" -DFULLSTACK and -DCNTRSTACK\\n\");", - " exit(1);", + " pan_exit(1);", "#endif", - "#ifdef VERI", + "#if defined(VERI)", "#if ACCEPT_LAB>0", - " if (!a_cycles && !state_tables)", - " { fprintf(efd, \"warning: never-claim + accept-labels \");", + "#ifndef BFS", + " if (!a_cycles", + "#ifdef HAS_CODE", + " && !readtrail", + "#endif", + " && !state_tables)", + " { fprintf(efd, \"warning: never claim + accept labels \");", " fprintf(efd, \"requires -a flag to fully verify\\n\");", " }", + "#else", + " if (", + "#ifdef HAS_CODE", + " !readtrail", + "#endif", + " && !state_tables)", + " { fprintf(efd, \"warning: verification in BFS mode \");", + " fprintf(efd, \"is restricted to safety properties\\n\");", + " }", + "#endif", "#endif", "#endif", "#ifndef SAFETY", - " if (!a_cycles && !state_tables)", + " if (!a_cycles", + "#ifdef HAS_CODE", + " && !readtrail", + "#endif", + " && !state_tables)", " { fprintf(efd, \"hint: this search is more efficient \");", " fprintf(efd, \"if pan.c is compiled -DSAFETY\\n\");", " }", @@ -2096,14 +3446,47 @@ "#endif", "#endif", " signal(SIGINT, stopped);", - " mask = ((1<= 32)", + " { mask = 0xffffffff;", + "#ifdef BITSTATE", + " switch (ssize) {", + " case 34: nmask = (mask>>1); break;", + " case 33: nmask = (mask>>2); break;", + " default: nmask = (mask>>3); break;", + " }", + "#else", + " nmask = mask;", + "#endif", + " } else if (WS == 8)", + " { mask = ((1L<>3;", + "#else", + " nmask = mask;", + "#endif", + " } else if (WS != 4)", + " { fprintf(stderr, \"pan: wordsize %%d not supported\\n\", WS);", + " exit(1);", + " } else /* WS == 4 and ssize < 32 */", + " { mask = ((1L<>3);", + " }", + /****************** end **********************/ + + "#ifdef BFS", + " trail = (Trail *) emalloc(6*sizeof(Trail));", + " trail += 3;", + "#else", " trail = (Trail *) emalloc((maxdepth+3)*sizeof(Trail));", " trail++; /* protect trpt-1 refs at depth 0 */", + "#endif", "#ifdef SVDUMP", " if (vprefix > 0)", " { char nm[64];", " sprintf(nm, \"%%s.svd\", Source);", - " if ((svfd = creat(nm, 0666)) <= 0)", + " if ((svfd = creat(nm, 0666)) < 0)", " { fprintf(efd, \"couldn't create %%s\\n\", nm);", " vprefix = 0;", " } }", @@ -2118,7 +3501,8 @@ " done = 1;", " wrapup();", " return 0;", - "}\n", + "}", /* end of main() */ + "", "void", "usage(FILE *fd)", "{", @@ -2134,21 +3518,25 @@ " fprintf(fd, \"\t-a,-l,-f -> are disabled by -DSAFETY\\n\");", "#endif", " fprintf(fd, \"\t-A ignore assert() violations\\n\");", + " fprintf(fd, \"\t-b consider it an error to exceed the depth-limit\\n\");", " fprintf(fd, \"\t-cN stop at Nth error \");", " fprintf(fd, \"(defaults to -c1)\\n\");", " fprintf(fd, \"\t-d print state tables and stop\\n\");", " fprintf(fd, \"\t-e create trails for all errors\\n\");", - " fprintf(fd, \"\t-E ignore invalid endstates\\n\");", + " fprintf(fd, \"\t-E ignore invalid end states\\n\");", "#ifdef SC", " fprintf(fd, \"\t-Ffile use 'file' to store disk-stack\\n\");", "#endif", "#ifndef NOFAIR", " fprintf(fd, \"\t-f add weak fairness (to -a or -l)\\n\");", "#endif", - " fprintf(fd, \"\t-hN choose other hash-function 1..32\\n\");", + " fprintf(fd, \"\t-hN use different hash-seed N:1..32\\n\");", " fprintf(fd, \"\t-i search for shortest path to error\\n\");", " fprintf(fd, \"\t-I like -i, but approximate and faster\\n\");", " fprintf(fd, \"\t-J reverse eval order of nested unlesses\\n\");", + "#ifdef BITSTATE", + " fprintf(fd, \"\t-kN set N bits per state (defaults to 3)\\n\");", + "#endif", "#ifndef SAFETY", "#ifdef NP", " fprintf(fd, \"\t-l find non-progress cycles\\n\");", @@ -2158,45 +3546,67 @@ " fprintf(fd, \"compilation with -DNP\\n\");", "#endif", "#endif", +#ifndef POWOW + "#ifdef BITSTATE", + " fprintf(fd, \"\t-MN use N Megabytes for bitstate hash array\\n\");", + " fprintf(fd, \"\t-GN use N Gigabytes for bitstate hash array\\n\");", + "#endif", +#endif " fprintf(fd, \"\t-mN max depth N steps (default=10k)\\n\");", " fprintf(fd, \"\t-n no listing of unreached states\\n\");", "#ifdef SVDUMP", " fprintf(fd, \"\t-pN create svfile (save N bytes per state)\\n\");", "#endif", - " fprintf(fd, \"\t-q require empty chans in valid endstates\\n\");", + " fprintf(fd, \"\t-q require empty chans in valid end states\\n\");", + "#ifdef HAS_CODE", + " fprintf(fd, \"\t-r read and execute trail - can add -v,-n,-PN,-g,-C\\n\");", + " fprintf(fd, \"\t-rN read and execute N-th error trail\\n\");", + " fprintf(fd, \"\t-C read and execute trail - columnated output (can add -v,-n)\\n\");", + " fprintf(fd, \"\t-PN read and execute trail - restrict trail output to proc N\\n\");", + " fprintf(fd, \"\t-g read and execute trail + msc gui support\\n\");", + "#endif", "#ifdef BITSTATE", " fprintf(fd, \"\t-RN repeat run Nx with N \");", " fprintf(fd, \"[1..32] independent hash functions\\n\");", + " fprintf(fd, \"\t-s same as -k1 (single bit per state)\\n\");", "#endif", - " fprintf(fd, \"\t-s 1-bit hashing (default is 2-bit)\\n\");", " fprintf(fd, \"\t-T create trail files in read-only mode\\n\");", " fprintf(fd, \"\t-tsuf replace .trail with .suf on trailfiles\\n\");", " fprintf(fd, \"\t-V print SPIN version number\\n\");", " fprintf(fd, \"\t-v verbose -- filenames in unreached state listing\\n\");", " fprintf(fd, \"\t-wN hashtable of 2^N entries\");", " fprintf(fd, \"(defaults to -w%%d)\\n\", ssize);", - " exit(1);", + " pan_exit(1);", "}", "", "char *", "Malloc(unsigned long n)", "{ char *tmp;", - "#ifdef MEMCNT", + "#if defined(MEMCNT) || defined(MEMLIM)", " if (memcnt+ (double) n > memlim) goto err;", "#endif", -"#ifdef PC", +"#if 1", " tmp = (char *) malloc(n);", + " if (!tmp)", "#else", + /* on linux machines, a large amount of memory is set aside + * for malloc, whether it is used or not + * using sbrk would make this memory arena inaccessible + * the reason for using sbrk was originally to provide a + * small additional speedup (since this memory is never released) + */ " tmp = (char *) sbrk(n);", + " if (tmp == (char *) -1L)", "#endif", - " if (tmp == (char *) -1L)", /* was: if ((int)tmp == -1) */ " {", + "#if defined(MEMCNT) || defined(MEMLIM)", "err:", + "#endif", " printf(\"pan: out of memory\\n\");", - "#ifdef MEMCNT", + "#if defined(MEMCNT) || defined(MEMLIM)", " printf(\"\t%%g bytes used\\n\", memcnt);", " printf(\"\t%%g bytes more needed\\n\", (double) n);", - " printf(\"\t%%g bytes limit (2^MEMCNT)\\n\",", + " printf(\"\t%%g bytes limit\\n\",", " memlim);", "#endif", "#ifdef COLLAPSE", @@ -2220,9 +3630,7 @@ "#endif", " wrapup();", " }", - "#ifdef MEMCNT", - " memcnt += n;", - "#endif", + " memcnt += (double) n;", " return tmp;", "}", "", @@ -2235,11 +3643,11 @@ " return (char *) NULL;", " if (n&(sizeof(void *)-1)) /* for proper alignment */", " n += sizeof(void *)-(n&(sizeof(void *)-1));", - " if (left < (long) n)", + " if ((unsigned long) left < n)", /* was: (left < (long)n) */ " { grow = (n < CHUNK) ? CHUNK : n;", - "#ifdef PC", +#if 1 " have = Malloc(grow);", - "#else", +#else " /* gcc's sbrk can give non-aligned result */", " grow += sizeof(void *); /* allow realignment */", " have = Malloc(grow);", @@ -2248,7 +3656,7 @@ " - (((unsigned) have)&(sizeof(void *)-1)));", " grow -= sizeof(void *);", " }", - "#endif", +#endif " fragment += (double) left;", " left = grow;", " }", @@ -2268,7 +3676,10 @@ "#if defined(MA) && !defined(SAFETY)", "int", "Unwind(void)", - "{ Trans *t; char ot, m; short tt; short II, i;\n", + "{ Trans *t; uchar ot, _m; int tt; short II;", + "#ifdef VERBOSE", + " int i;", + "#endif", " uchar oat = now._a_t;", " now._a_t &= ~(1|16|32);", " memcpy((char *) &comp_now, (char *) &now, vsize);", @@ -2321,7 +3732,7 @@ " t = trpt->o_t;", " ot = trpt->o_ot; II = trpt->pr;", " tt = trpt->o_tt; this = pptr(II);", - " m = do_reverse(t, II, trpt->o_m);", + " _m = do_reverse(t, II, trpt->o_m);", "#ifdef VERBOSE", " printf(\"%%3d: proc %%d \", depth, II);", " printf(\"reverses %%d, %%d to %%d,\",", @@ -2337,7 +3748,7 @@ "#else", " trpt--;", "#endif", - " reached[ot][t->st] = 1;", + " /* reached[ot][t->st] = 1; 3.4.13 */", " ((P0 *)this)->_p = tt;", "#ifndef NOFAIR", " if ((trpt->o_pm&32))", @@ -2363,25 +3774,44 @@ " return 0;", "}", "#endif", + "static char unwinding;", "void", "uerror(char *str)", - "{ static char laststr[256];\n", - " if (strcmp(str, laststr))", + "{ static char laststr[256];", + " int is_cycle;", + "", + " if (unwinding) return; /* 1.4.2 */", + " if (strncmp(str, laststr, 254))", " printf(\"pan: %%s (at depth %%d)\\n\", str,", " (depthfound==-1)?depth:depthfound);", - " strcpy(laststr, str);", + " strncpy(laststr, str, 254);", " errors++;", - " if (every_error != 0", + "#ifdef HAS_CODE", + " if (readtrail) { wrap_trail(); return; }", + "#endif", + " is_cycle = (strstr(str, \" cycle\") != (char *) 0);", + " if (!is_cycle)", + " { depth++; trpt++;", /* include failed step */ + " }", + " if ((every_error != 0)", " || errors == upto)", " {", "#if defined(MA) && !defined(SAFETY)", - " if (strstr(str, \" cycle\"))", + " if (is_cycle)", " { int od = depth;", + " unwinding = 1;", " depthfound = Unwind();", + " unwinding = 0;", " depth = od;", " }", "#endif", +"#ifdef BFS", + " if (depth > 1) trpt--;", + " nuerror(str);", + " if (depth > 1) trpt++;", +"#else", " putrail();", +"#endif", "#if defined(MA) && !defined(SAFETY)", " if (strstr(str, \" cycle\"))", " { if (every_error)", @@ -2390,35 +3820,31 @@ " }", "#endif", " }", + " if (!is_cycle)", + " { depth--; trpt--; /* undo */", + " }", +"#ifndef BFS", " if (iterative != 0 && maxdepth > 0)", " { maxdepth = (iterative == 1)?(depth-1):(depth/2);", " warned = 1;", " printf(\"pan: reducing search depth to %%d\\n\",", " maxdepth);", - " } else if (errors >= upto && upto != 0)", + " } else", +"#endif", + " if (errors >= upto && upto != 0)", " wrapup();", - " depthfound = -1; /* tripakis */", - "}\n", - "void", - "r_ck(uchar *which, int N, int M, short *src, S_F_MAP *mp)", - "{ int i, m=0;\n", - "#ifdef VERI", - " if (M == VERI && !verbose) return;", - "#endif", - " printf(\"unreached in proctype %%s\\n\", procname[M]);", - " for (i = 1; i < N; i++)", - " if (which[i] == 0 && trans[M][i])", - " xrefsrc((int) src[i], mp, M, i);", - " else", - " m++;", - " printf(\"\t(%%d of %%d states)\\n\", N-1-m, N-1);", + " depthfound = -1;", "}\n", - "void", + "int", "xrefsrc(int lno, S_F_MAP *mp, int M, int i)", "{ Trans *T; int j;", " for (T = trans[M][i]; T; T = T->nxt)", " if (T && T->tp)", - " { printf(\"\\tline %%d\", lno);", + " { if (strcmp(T->tp, \".(goto)\") == 0", + " || strncmp(T->tp, \"goto :\", 6) == 0)", + " return 1; /* not reported */", + "", + " printf(\"\\tline %%d\", lno);", " if (verbose)", " for (j = 0; j < sizeof(mp); j++)", " if (i >= mp[j].from && i <= mp[j].upto)", @@ -2427,28 +3853,43 @@ " }", " printf(\", state %%d\", i);", " if (strcmp(T->tp, \"\") != 0)", - " printf(\", \\\"%%s\\\"\", T->tp);", - " else if (stopstate[M][i])", - " printf(\", -endstate-\");", + " { char *q;", + " q = transmognify(T->tp);", + " printf(\", \\\"%%s\\\"\", q);", + " } else if (stopstate[M][i])", + " printf(\", -end state-\");", " printf(\"\\n\");", " }", + " return 0;", + "}\n", + "void", + "r_ck(uchar *which, int N, int M, short *src, S_F_MAP *mp)", + "{ int i, m=0;\n", + "#ifdef VERI", + " if (M == VERI && !verbose) return;", + "#endif", + " printf(\"unreached in proctype %%s\\n\", procname[M]);", + " for (i = 1; i < N; i++)", +#if 0 + " if (which[i] == 0 /* && trans[M][i] */)", +#else + " if (which[i] == 0", + " && (mapstate[M][i] == 0", + " || which[mapstate[M][i]] == 0))", +#endif + " m += xrefsrc((int) src[i], mp, M, i);", + " else", + " m++;", + " printf(\"\t(%%d of %%d states)\\n\", N-1-m, N-1);", "}\n", "void", "putrail(void)", "{ int fd; long i, j;", " Trail *trl;", - " char snap[64], fnm[256];", - " if (iterative == 0 && Nr_Trails++ > 0)", - " sprintf(fnm, \"%%s%%d.%%s\",", - " TrailFile, Nr_Trails, tprefix);", - " else", - " sprintf(fnm, \"%%s.%%s\",", - " TrailFile, tprefix);", - " if ((fd = creat(fnm, TMODE)) <= 0)", - " { printf(\"cannot create %%s\\n\", fnm);", - " perror(\"cause\");", - " return;", - " }", + " char snap[64];", + "", + " fd = make_trail();", + " if (fd < 0) return;", "#ifdef VERI", " sprintf(snap, \"-2:%%d:-2\\n\", VERI);", " write(fd, snap, strlen(snap));", @@ -2461,23 +3902,22 @@ " { if (i == depthfound+1)", " write(fd, \"-1:-1:-1\\n\", 9);", " trl = getframe(i);", + " if (!trl->o_t) continue;", " if (trl->o_pm&128) continue;", " sprintf(snap, \"%%d:%%d:%%d\\n\", ", " i, trl->pr, trl->o_t->t_id);", " j = strlen(snap);", " if (write(fd, snap, j) != j)", - " { printf(\"pan: error writing %%s\\n\", fnm);", + " { printf(\"pan: error writing trailfile\\n\");", " close(fd);", " wrapup();", " }", " }", - " printf(\"pan: wrote %%s\\n\", fnm);", " close(fd);", "}\n", "void", - "sv_save(char *won) /* push state vector onto save stack */", - "{", - " if (!svtack->nxt)", + "sv_save(void) /* push state vector onto save stack */", + "{ if (!svtack->nxt)", " { svtack->nxt = (Svtack *) emalloc(sizeof(Svtack));", " svtack->nxt->body = emalloc(vsize*sizeof(char));", " svtack->nxt->lst = svtack;", @@ -2494,10 +3934,13 @@ " svtack->o_boq = boq;", "#endif", " svtack->o_delta = vsize; /* don't compress */", - " memcpy((char *)(svtack->body), won, vsize);", - "#ifdef DEBUG", + " memcpy((char *)(svtack->body), (char *) &now, vsize);", + "#if defined(C_States) && defined(HAS_STACK) && (HAS_TRACK==1)", + " c_stack((uchar *) &(svtack->c_stack[0]));", + "#endif", + "#ifdef DEBUG", " printf(\"%%d: sv_save\\n\", depth);", - "#endif", + "#endif", "}\n", "void", "sv_restor(void) /* pop state vector from save stack */", @@ -2506,6 +3949,14 @@ "#if SYNC", " boq = svtack->o_boq;", "#endif", + + "#if defined(C_States) && (HAS_TRACK==1)", + "#ifdef HAS_STACK", + " c_unstack((uchar *) &(svtack->c_stack[0]));", + "#endif", + " c_revert((uchar *) &(now.c_state[0]));", + "#endif", + " if (vsize != svtack->o_delta)", " Uerror(\"sv_restor\");", " if (!svtack->lst)", @@ -2553,7 +4004,10 @@ "}\n", "void", "q_restor(void)", - "{ int k; char *z = (char *) &now;\n", + "{ char *z = (char *) &now;", + "#ifndef NOCOMP", + " int k, k_end;", + "#endif", " q_offset[now._nr_qs] = stack->o_offset;", " q_skip[now._nr_qs] = stack->o_skip;", "#ifndef XUSAFE", @@ -2567,12 +4021,15 @@ "#endif", " now._nr_qs += 1;", "#ifndef NOCOMP", - " k = stack->o_offset - stack->o_skip;", + " k_end = stack->o_offset;", + " k = k_end - stack->o_skip;", "#if SYNC", - " if (q_zero(now._nr_qs)) k += stack->o_delta;", + "#ifndef BFS", + " if (q_zero(now._nr_qs)) k_end += stack->o_delta;", "#endif", - " for ( ; k < stack->o_offset; k++)", - " Mask[k] = 1; /* align */", + "#endif", + " for ( ; k < k_end; k++)", + " Mask[k] = 1;", "#endif", " if (!stack->lst) /* debugging */", " Uerror(\"error: q_restor\");", @@ -2583,13 +4040,13 @@ " int *ptr;", " struct IntChunks *nxt;", "} IntChunks;", - "IntChunks *filled_chunks[128];", - "IntChunks *empty_chunks[128];", + "IntChunks *filled_chunks[512];", + "IntChunks *empty_chunks[512];", "int *", "grab_ints(int nr)", "{ IntChunks *z;", - " if (nr >= 128) Uerror(\"cannot happen grab_int\");", + " if (nr >= 512) Uerror(\"cannot happen grab_int\");", " if (filled_chunks[nr])", " { z = filled_chunks[nr];", " filled_chunks[nr] = filled_chunks[nr]->nxt;", @@ -2611,71 +4068,12 @@ " z->nxt = filled_chunks[nr];", " filled_chunks[nr] = z;", "}", -#if 0 - "void", - "p_q_restor(int h, int K)", - "{ int k = K-1;", - " if (!stack || !stack->lst || !stack->lst->lst)", - " Uerror(\"error: p_q_restor\");", - " /* restore globals */", - " memcpy((char *)&now, stack->body, sizeof(State)-VECTORSZ);", - " stack = stack->lst;", - " memcpy((char *) qptr(k), stack->body, Maxbody);", - " stack = stack->lst;", - "#if SYNC", - " boq = stack->o_boq;", - "#endif", - " memcpy((char *) pptr(h), stack->body, Maxbody);", - " stack = stack->lst;", - "}", - "Stack *", - "p_q_frame(void)", - "{ if (!stack->nxt)", - " { stack->nxt = (Stack *)", - " emalloc(sizeof(Stack));", - " stack->nxt->body = ", - " emalloc(Maxbody*sizeof(char));", - " stack->nxt->lst = stack;", - " smax++;", - " }", - " return stack->nxt;", - "}", - "void", - "p_q_save(int h, int K)", - "{ int k = K-1;", - " stack = p_q_frame();", - " memcpy(stack->body, (char *)pptr(h), Maxbody);", - "#if SYNC", - " stack->o_boq = boq;", - "#endif", - " stack = p_q_frame();", - " memcpy(stack->body, (char *)qptr(k), Maxbody);", - " /* save globals */", - " stack = p_q_frame();", - " memcpy(stack->body, (char *)&now, sizeof(State)-VECTORSZ);", - "}", - "void", - "bup_q(int h, int K)", - "{", - "#if VECTORSZ<=1024", - " sv_save((char *)&now);", - "#else", - " p_q_save(h, K);", - "#endif", - "}", - "void", - "unbup_q(int h, int K)", - "{", - "#if VECTORSZ<=1024", - " sv_restor();", - "#else", - " p_q_restor(h, K);", - "#endif", - "}", -#endif "int", "delproc(int sav, int h)", - "{ int d, i=0, o_vsize = vsize;\n", + "{ int d, i=0;", + "#ifndef NOCOMP", + " int o_vsize = vsize;", + "#endif", " if (h+1 != (int) now._nr_pr) return 0;\n", " while (now._nr_qs", " && q_offset[now._nr_qs-1] > proc_offset[h])", @@ -2841,16 +4239,21 @@ "#if defined(FULLSTACK) && defined(BITSTATE)", "struct H_el *Free_list = (struct H_el *) 0;", "void", - "onstack_init(void)", + "onstack_init(void) /* to store stack states in a bitstate search */", "{ S_Tab = (struct H_el **)", - " emalloc((1<<(ssize-3))*sizeof(struct H_el *));", +#if 0 + " emalloc((1L<<(ssize-3))*sizeof(struct H_el *));", + /* can lead to excessive memory use */ +#else + " emalloc(maxdepth*sizeof(struct H_el *));", +#endif "}", "struct H_el *", "grab_state(int n)", "{ struct H_el *v, *last = 0;", " if (H_tab == S_Tab)", - " { for (v = Free_list; v && v->tagged >= n; v=v->nxt)", - " { if (v->tagged == n)", + " { for (v = Free_list; v && ((int) v->tagged >= n); v=v->nxt)", + " { if ((int) v->tagged == n)", " { if (last)", " last->nxt = v->nxt;", " else", @@ -2866,7 +4269,7 @@ " }", " /* new: second try */", " v = Free_list;", /* try to avoid emalloc */ - " if (v && v->tagged >= n)", + " if (v && ((int) v->tagged >= n))", " goto gotcha;", " ngrabs++;", " }", @@ -2879,17 +4282,10 @@ "#endif", "#ifdef COLLAPSE", "unsigned long", - "#ifdef HYBRID_HASH", - "ordinal(char *v, long N, short tp) /* store components */", - "{ struct H_el *tmp, *ntmp; long n, m;", - " struct H_el *olst = (struct H_el *) 0;", - " n = s_hash((uchar *)v, N);", - "#else", - "ordinal(char *v, long n, short tp)", - "{ struct H_el *tmp, *ntmp; long m;", - " struct H_el *olst = (struct H_el *) 0;", - " s_hash((uchar *)v, n);", - "#endif", + "ordinal(char *v, long n, short tp)", + "{ struct H_el *tmp, *ntmp; long m;", + " struct H_el *olst = (struct H_el *) 0;", + " s_hash((uchar *)v, n);", " tmp = H_tab[j1];", " if (!tmp)", " { tmp = grab_state(n);", @@ -2964,7 +4360,12 @@ "#ifndef JOINPROCS", " for (i = 0; i < (int) now._nr_pr; i++)", " { n = col_p(i, (char *) 0);", + "#ifdef NOFIX", " nbytes[nbytelen] = 0;", + "#else", + " nbytes[nbytelen] = 1;", + " *v++ = ((P0 *) pptr(i))->_t;", + "#endif", " *v++ = n&255;", " if (n >= (1<<8))", " { nbytes[nbytelen]++;", @@ -3044,7 +4445,7 @@ " else", " n = pptr(0) - (uchar *) w;", " j = w - (char *) &now;", - " for (i = 0; i < n; i++, w++)", + " for (i = 0; i < (int) n; i++, w++)", " if (!Mask[j++]) *x++ = *w;", "#ifndef SEPQS", " for (i = 0; i < (int) now._nr_qs; i++)", @@ -3086,9 +4487,9 @@ "int", "compress(char *vin, int n) /* default compression */", "{", - "#ifdef HC", + "#ifdef HC", " int delta = 0;", - " r_hash((uchar *)vin, n); /* sets J3 and J4 */", + " s_hash((uchar *)vin, n); /* sets K1 and K2 */", "#ifndef SAFETY", " if (S_A)", " { delta++; /* _a_t */", @@ -3098,14 +4499,14 @@ "#endif", " }", "#endif", - " memcpy((char *) &comp_now + delta, (char *) &J3, sizeof(long));", - " delta += sizeof(long);", + " memcpy((char *) &comp_now + delta, (char *) &K1, WS);", + " delta += WS;", "#if HC>0", - " memcpy((char *) &comp_now + delta, (char *) &J4, HC);", + " memcpy((char *) &comp_now + delta, (char *) &K2, HC);", " delta += HC;", "#endif", " return delta;", - "#else", + "#else", " char *vv = vin;", " char *v = (char *) &comp_now;", " int i;", @@ -3119,11 +4520,22 @@ " n, v - (char *)&comp_now);", "#endif", " return v - (char *)&comp_now;", - "#endif", + "#endif", "}", "#endif", "#endif", "#if defined(FULLSTACK) && defined(BITSTATE)", +"#if defined(MA)", + "#if !defined(onstack_now)", + "int onstack_now(void) {}", /* to suppress compiler errors */ + "#endif", + "#if !defined(onstack_put)", + "void onstack_put(void) {}", /* for this invalid combination */ + "#endif", + "#if !defined(onstack_zap)", + "void onstack_zap(void) {}", /* of directives */ + "#endif", +"#else", "void", "onstack_zap(void)", "{ struct H_el *v, *w, *last = 0;", @@ -3143,9 +4555,6 @@ "#endif", "#endif", "#if !defined(HC) && !(defined(BITSTATE) && defined(LC))", - "#ifdef HYBRID_HASH", - " n = ", - "#endif", " s_hash((uchar *)nv, n);", "#endif", " H_tab = tmp;", @@ -3156,7 +4565,7 @@ " if (m < 0)", " break;", " }", - "NotFound:", + "/* NotFound: */", " Uerror(\"stack out of wack - zap\");", " return;", "Found:", @@ -3165,13 +4574,13 @@ " last->nxt = v->nxt;", " else", " S_Tab[j1] = v->nxt;", - " v->tagged = n;", + " v->tagged = (unsigned) n;", "#if !defined(NOREDUCE) && !defined(SAFETY)", " v->proviso = 0;", "#endif", " v->nxt = last = (struct H_el *) 0;", " for (w = Free_list; w; Fa++, last=w, w = w->nxt)", - " { if (w->tagged <= n)", + " { if ((int) w->tagged <= n)", " { if (last)", " { v->nxt = w->nxt;", " last->nxt = v;", @@ -3191,7 +4600,7 @@ "onstack_put(void)", "{ struct H_el **tmp = H_tab;", " H_tab = S_Tab;", - " if (hstore((char *)&now, vsize, 3) != 0)", + " if (hstore((char *)&now, vsize) != 0)", "#if defined(BITSTATE) && defined(LC)", " printf(\"pan: warning, double stack entry\\n\");", "#else", @@ -3220,9 +4629,6 @@ " n = compress((char *)&now, vsize);", "#endif", "#if !defined(HC) && !(defined(BITSTATE) && defined(LC))", - "#ifdef HYBRID_HASH", - " n = ", - "#endif", " s_hash((uchar *)v, n);", "#endif", " H_tab = tmp2;", @@ -3236,6 +4642,7 @@ " return (m == 0);", "}", "#endif", +"#endif", "#ifndef BITSTATE", "void", @@ -3247,12 +4654,12 @@ " r_xpoint();", " }", "#else", - " dfa_init(MA+a_cycles);", + " dfa_init((unsigned short) (MA+a_cycles));", "#endif", "#endif", "#if !defined(MA) || defined(COLLAPSE)", " H_tab = (struct H_el **)", - " emalloc((1<= MA)", " { printf(\"pan: error, MA too small, recompile pan.c\");", " printf(\" with -DMA=N with N>%%d\\n\", n);", " Uerror(\"aborting\");", " }", - " if (n > maxgs) maxgs = n;", + " if (n > (int) maxgs) maxgs = (unsigned int) n;", " for (i = 0; i < n; i++)", - " Info[i] = ((uchar *)&comp_now)[i];", + " Info[i] = v[i];", " for ( ; i < MA-1; i++)", " Info[i] = 0;", " Info[MA-1] = pbit;", @@ -3329,7 +4743,9 @@ "#ifdef FULLSTACK", " if (pbit == 0)", " { Info[MA-1] = 1; /* proviso bit */", + "#ifndef BFS", " trpt->proviso = dfa_member(MA-1);", + "#endif", " Info[MA-1] = 4; /* off-stack bit */", " if (dfa_member(MA-1)) {", "#ifdef VERBOSE", @@ -3355,23 +4771,23 @@ "int", "compact_stack(char *vin, int n)", /* special case of HC4 */ "{ int delta = 0;", - " r_hash((uchar *)vin, n); /* sets J3 and J4 */", + " s_hash((uchar *)vin, n); /* sets K1 and K2 */", "#ifndef SAFETY", " delta++; /* room for state[0] |= 128 */", "#endif", - " memcpy((char *) &comp_now + delta, (char *) &J3, sizeof(long));", - " delta += sizeof(long);", - " memcpy((char *) &comp_now + delta, (char *) &J4, sizeof(long));", - " delta += sizeof(long); /* use all available bits */", + " memcpy((char *) &comp_now + delta, (char *) &K1, WS);", + " delta += WS;", + " memcpy((char *) &comp_now + delta, (char *) &K2, WS);", + " delta += WS; /* use all available bits */", " return delta;", "}", "#endif", "int", - "hstore(char *vin, int nin, short xx)", + "hstore(char *vin, int nin) /* hash table storage */", "{ struct H_el *tmp, *ntmp, *olst = (struct H_el *) 0;", " char *v; int n, m=0;", - "#ifdef NOCOMP", + "#ifdef NOCOMP", /* defined by BITSTATE */ "#if defined(BITSTATE) && defined(LC)", " if (S_Tab == H_tab)", " { v = (char *) &comp_now;", @@ -3384,7 +4800,7 @@ "#endif", "#else", " v = (char *) &comp_now;", - " n = compress(vin, nin);", + " n = compress(vin, nin);", /* with HC, this calls s_hash */ "#ifndef SAFETY", " if (S_A)", " { v[0] = 0; /* _a_t */", @@ -3398,9 +4814,6 @@ "#endif", "#endif", "#if !defined(HC) && !(defined(BITSTATE) && defined(LC))", - "#ifdef HYBRID_HASH", - " n = ", - "#endif", " s_hash((uchar *)v, n);", "#endif", " tmp = H_tab[j1];", @@ -3533,9 +4946,25 @@ " printf(\"\t\tReVisiting (from smaller depth)\\n\");", "#endif", " nstates--;", +#if 0 + possible variation of iterative search for shortest counter-example (pan -i + and pan -I) suggested by Pierre Moro (for safety properties): + state revisits on shorter depths do not start until after + the first counter-example is found. this assumes that the max search + depth is set large enough that a first (possibly long) counter-example + can be found + if set too short, this variant can miss the counter-example, even if + it would otherwise be shorter than the depth-limit. + (p.m. unsure if this preserves the guarantee of finding the + shortest counter-example - so not enabled yet) + " if (errors > 0 && iterative)", /* Moro */ +#endif " return 0;", " }", "#endif", + "#if defined(BFS) && defined(QPROVISO)", + " Lstate = tmp;", + "#endif", " return 1; /* match outside stack */", " } else if (m < 0)", " { /* insert state before tmp */", @@ -3549,7 +4978,10 @@ " break;", " } else if (!tmp->nxt)", " { /* append after tmp */", - "Append: tmp->nxt = grab_state(n);", + "#ifdef COLLAPSE", + "Append:", + "#endif", + " tmp->nxt = grab_state(n);", " tmp = tmp->nxt;", " break;", " } }", --- /sys/src/cmd/spin/pangen2.c Wed Aug 31 04:22:24 2005 +++ /sys/src/cmd/spin/pangen2.c Wed Aug 31 04:22:19 2005 @@ -1,14 +1,13 @@ /***** spin: pangen2.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" #include "version.h" @@ -30,17 +29,18 @@ extern ProcList *rdy; extern RunList *run; -extern Symbol *Fname, *oFname, *owner, *context; +extern Symbol *Fname, *oFname, *context; extern char *claimproc, *eventmap; extern int lineno, verbose, Npars, Mpars; -extern int m_loss, Nid, has_remote, merger, rvopt, separate; -extern int Ntimeouts, Etimeouts; -extern int u_sync, u_async, nrRdy, nqs; +extern int m_loss, has_remote, has_remvar, merger, rvopt, separate; +extern int Ntimeouts, Etimeouts, deadvar; +extern int u_sync, u_async, nrRdy; extern int GenCode, IsGuard, Level, TestOnly; +extern short has_stack; extern char *NextLab[]; FILE *tc, *th, *tt, *tm, *tb; -ProcList *cur_proc; + int OkBreak = -1; short nocast=0; /* to turn off casts in lvalues */ short terse=0; /* terse printing of varnames */ @@ -55,7 +55,8 @@ short has_xu=0; /* spec contains xr or xs assertions */ short has_unless=0; /* spec contains unless statements */ short has_provided=0; /* spec contains PROVIDED clauses on procs */ -short _isok=0; /* checks usage of predefined varble _ */ +short has_code=0; /* spec contains c_code, c_expr, c_state */ +short _isok=0; /* checks usage of predefined variable _ */ short evalindex=0; /* evaluate index of var names */ short withprocname=0; /* prefix local varnames with procname */ int mst=0; /* max nr of state/process */ @@ -64,7 +65,6 @@ int Pid; /* proc currently processed */ int multi_oval; /* set in merges, used also in pangen4.c */ - #define MAXMERGE 256 /* max nr of bups per merge sequence */ static short CnT[MAXMERGE]; @@ -88,7 +88,7 @@ static void put_seq(Sequence *, int, int); static void putproc(ProcList *); static void Tpe(Lextok *); -extern void spit_recvs(FILE *, FILE*); +extern void spit_recvs(FILE *, FILE*); static int fproc(char *s) @@ -125,7 +125,7 @@ fprintf(tm, "\t\t\tcontinue;\n"); fprintf(tm, "\t\t/* else fall through */\n"); fprintf(tm, "\tcase _T2:\t/* true */\n"); - fprintf(tm, "\t\tm = 3; goto P999;\n"); + fprintf(tm, "\t\t_m = 3; goto P999;\n"); } static void @@ -135,9 +135,9 @@ fprintf(tt, "\ttrans[_NP_] = "); fprintf(tt, "(Trans **) emalloc(2*sizeof(Trans *));\n"); fprintf(tt, "\tT = trans[_NP_][0] = "); - fprintf(tt, "settr(9997,0,0,_T2,0,\"(1)\", 0,2,0);\n"); + fprintf(tt, "settr(9997,0,1,_T5,0,\"(np_)\", 1,2,0);\n"); fprintf(tt, "\t T->nxt = "); - fprintf(tt, "settr(9998,0,1,_T5,0,\"(np_)\", 1,2,0);\n"); + fprintf(tt, "settr(9998,0,0,_T2,0,\"(1)\", 0,2,0);\n"); fprintf(tt, "\tT = trans[_NP_][1] = "); fprintf(tt, "settr(9999,0,1,_T5,0,\"(np_)\", 1,2,0);\n"); } @@ -145,11 +145,11 @@ static struct { char *nm[3]; } Cfile[] = { - { "pan.c", "pan_s.c", "pan_t.c" }, - { "pan.h", "pan_s.h", "pan_t.h" }, - { "pan.t", "pan_s.t", "pan_t.t" }, - { "pan.m", "pan_s.m", "pan_t.m" }, - { "pan.b", "pan_s.b", "pan_t.b" }, + { { "pan.c", "pan_s.c", "pan_t.c" } }, + { { "pan.h", "pan_s.h", "pan_t.h" } }, + { { "pan.t", "pan_s.t", "pan_t.t" } }, + { { "pan.m", "pan_s.m", "pan_t.m" } }, + { { "pan.b", "pan_s.b", "pan_t.b" } } }; void @@ -164,13 +164,35 @@ { printf("spin: cannot create pan.[chtmfb]\n"); alldone(1); } + fprintf(th, "#define Version \"%s\"\n", Version); fprintf(th, "#define Source \"%s\"\n\n", oFname->name); if (separate != 2) fprintf(th, "char *TrailFile = Source; /* default */\n"); + + fprintf(th, "#if defined(BFS)\n"); + fprintf(th, "#ifndef SAFETY\n"); + fprintf(th, "#define SAFETY\n"); + fprintf(th, "#endif\n"); + fprintf(th, "#ifndef XUSAFE\n"); + fprintf(th, "#define XUSAFE\n"); + fprintf(th, "#endif\n"); + fprintf(th, "#endif\n"); + + fprintf(th, "#ifndef uchar\n"); fprintf(th, "#define uchar unsigned char\n"); + fprintf(th, "#endif\n"); + fprintf(th, "#ifndef uint\n"); + fprintf(th, "#define uint unsigned int\n"); + fprintf(th, "#endif\n"); - if (sizeof(long)==8) + if (sizeof(long) > 4) /* 64 bit machine */ + { fprintf(th, "#ifndef HASH32\n"); + fprintf(th, "#define HASH64\n"); + fprintf(th, "#endif\n"); + } + + if (sizeof(long)==sizeof(int)) fprintf(th, "#define long int\n"); if (separate == 1 && !claimproc) @@ -208,18 +230,23 @@ fprintf(th, "#define NTIM %d\n", Ntimeouts); if (Etimeouts) fprintf(th, "#define ETIM %d\n", Etimeouts); + if (has_remvar) + fprintf(th, "#define REM_VARS 1\n"); if (has_remote) fprintf(th, "#define REM_REFS %d\n", has_remote); /* not yet used */ if (has_last) fprintf(th, "#define HAS_LAST %d\n", has_last); if (has_sorted) fprintf(th, "#define HAS_SORTED %d\n", has_sorted); + if (m_loss) + fprintf(th, "#define M_LOSS\n"); if (has_random) fprintf(th, "#define HAS_RANDOM %d\n", has_random); - if (!has_enabled && !eventmap) - fprintf(th, "#define INLINE 1\n"); + fprintf(th, "#define HAS_CODE\n"); /* doesn't seem to cause measurable overhead */ + if (has_stack) + fprintf(th, "#define HAS_STACK\n"); if (has_enabled) - fprintf(th, "#define HAS_ENABLED 1\n"); + fprintf(th, "#define HAS_ENABLED 1\n"); if (has_unless) fprintf(th, "#define HAS_UNLESS %d\n", has_unless); if (has_provided) @@ -228,6 +255,14 @@ fprintf(th, "#define HAS_PCVALUE %d\n", has_pcvalue); if (has_badelse) fprintf(th, "#define HAS_BADELSE %d\n", has_badelse); + if (has_enabled + || has_pcvalue + || has_badelse + || has_last) + { fprintf(th, "#ifndef NOREDUCE\n"); + fprintf(th, "#define NOREDUCE 1\n"); + fprintf(th, "#endif\n"); + } if (has_np) fprintf(th, "#define HAS_NP %d\n", has_np); if (merger) @@ -252,7 +287,7 @@ { eventmapnr = fproc(eventmap); fprintf(th, "#define EVENT_TRACE %d\n", eventmapnr); fprintf(th, "#define endevent endstate%d\n", eventmapnr); - if (eventmap[2] == 'o') /* ":no_trace:" */ + if (eventmap[2] == 'o') /* ":notrace:" */ fprintf(th, "#define NEGATED_TRACE 1\n"); } @@ -264,11 +299,19 @@ fprintf(tc, "/*** From source: %s ***/\n\n", oFname->name); ntimes(tc, 0, 1, Pre0); + + plunk_c_decls(tc); /* types can be refered to in State */ + switch (separate) { case 0: fprintf(tc, "#include \"pan.h\"\n"); break; case 1: fprintf(tc, "#include \"pan_s.h\"\n"); break; case 2: fprintf(tc, "#include \"pan_t.h\"\n"); break; } + + fprintf(tc, "State A_Root; /* seed-state for cycles */\n"); + fprintf(tc, "State now; /* the full state-vector */\n"); + plunk_c_fcts(tc); /* State can be used in fcts */ + if (separate != 2) ntimes(tc, 0, 1, Preamble); @@ -278,6 +321,8 @@ fprintf(tc, "#define Index(x, y)\tx\n"); fprintf(tc, "#endif\n"); + c_preview(); /* sets hastrack */ + for (p = rdy; p; p = p->nxt) mst = max(p->s->maxel, mst); @@ -310,11 +355,15 @@ if (separate == 1) { fprintf(tm, " if (II == 0)\n"); - fprintf(tm, " { m = step_claim(trpt->o_pm, trpt->tau, tt, ot, t);\n"); - fprintf(tm, " if (m) goto P999; else continue;\n"); + fprintf(tm, " { _m = step_claim(trpt->o_pm, trpt->tau, tt, ot, t);\n"); + fprintf(tm, " if (_m) goto P999; else continue;\n"); fprintf(tm, " } else\n"); } + fprintf(tm, "#define rand pan_rand\n"); + fprintf(tm, "#if defined(HAS_CODE) && defined(VERBOSE)\n"); + fprintf(tm, " printf(\"Pr: %%d Tr: %%d\\n\", II, t->forw);\n"); + fprintf(tm, "#endif\n"); fprintf(tm, " switch (t->forw) {\n"); } else { fprintf(tt, "#ifndef PEG\n"); @@ -325,6 +374,10 @@ fprintf(tt, "\textern Trans *settr(int, int, int, int, int,"); fprintf(tt, " char *, int, int, int);\n\n"); + fprintf(tm, "#define rand pan_rand\n"); + fprintf(tm, "#if defined(HAS_CODE) && defined(VERBOSE)\n"); + fprintf(tm, " printf(\"Pr: %%d Tr: %%d\\n\", II, forw);\n"); + fprintf(tm, "#endif\n"); fprintf(tm, " switch (forw) {\n"); } @@ -334,7 +387,7 @@ fprintf(tm, " case 1: /* generic 'goto' or 'skip' */\n"); if (separate != 2) fprintf(tm, " IfNotBlocked\n"); - fprintf(tm, " m = 3; goto P999;\n"); + fprintf(tm, " _m = 3; goto P999;\n"); fprintf(tm, " case 2: /* generic 'else' */\n"); if (separate == 2) fprintf(tm, " if (o_pm&1) continue;\n"); @@ -342,7 +395,7 @@ { fprintf(tm, " IfNotBlocked\n"); fprintf(tm, " if (trpt->o_pm&1) continue;\n"); } - fprintf(tm, " m = 3; goto P999;\n"); + fprintf(tm, " _m = 3; goto P999;\n"); uniq = 3; if (separate == 1) @@ -353,14 +406,28 @@ fprintf(tb, " case 0: goto R999; /* nothing to undo */\n"); for (p = rdy; p; p = p->nxt) - { cur_proc = p; putproc(p); + + if (separate != 2) + { fprintf(th, "struct {\n"); + fprintf(th, " int tp; short *src;\n"); + fprintf(th, "} src_all[] = {\n"); + for (p = rdy; p; p = p->nxt) + fprintf(th, " { %d, &src_ln%d[0] },\n", + p->tn, p->tn); + fprintf(th, " { 0, (short *) 0 }\n"); + fprintf(th, "};\n"); } + + gencodetable(th); + if (separate != 1) { tm_predef_np(); tt_predef_np(); } fprintf(tt, "}\n\n"); /* end of settable() */ + + fprintf(tm, "#undef rand\n"); fprintf(tm, " }\n\n"); fprintf(tb, " }\n\n"); @@ -370,6 +437,7 @@ if (separate == 1) { fprintf(th, "#define FORWARD_MOVES\t\"pan_s.m\"\n"); fprintf(th, "#define REVERSE_MOVES\t\"pan_s.b\"\n"); + fprintf(th, "#define SEPARATE\n"); fprintf(th, "#define TRANSITIONS\t\"pan_s.t\"\n"); fprintf(th, "extern void ini_claim(int, int);\n"); } else @@ -411,6 +479,7 @@ fprintf(tc, "extern uchar *progstate[];\n"); fprintf(tc, "extern uchar *stopstate[];\n"); fprintf(tc, "extern uchar *visstate[];\n\n"); + fprintf(tc, "extern short *mapstate[];\n"); fprintf(tc, "void\nini_claim(int n, int h)\n{"); fprintf(tc, "\textern State now;\n"); @@ -425,17 +494,22 @@ fprintf(tc, "\t}\n"); fprintf(tc, "\n}\n"); fprintf(tc, "int\nstep_claim(int o_pm, int tau, int tt, int ot, Trans *t)\n"); - fprintf(tc, "{ int forw = t->forw; int m = 0; extern char *noptr; int II=0;\n"); + fprintf(tc, "{ int forw = t->forw; int _m = 0; extern char *noptr; int II=0;\n"); fprintf(tc, " extern State now;\n"); fprintf(tc, "#define continue return 0\n"); fprintf(tc, "#include \"pan_t.m\"\n"); - fprintf(tc, "P999:\n\treturn m;\n}\n"); + fprintf(tc, "P999:\n\treturn _m;\n}\n"); fprintf(tc, "#undef continue\n"); fprintf(tc, "int\nrev_claim(int backw)\n{ return 0; }\n"); fprintf(tc, "#include TRANSITIONS\n"); } if (separate != 1) ntimes(tc, 0, 1, Nvr1); + + if (separate != 2) + { c_wrapper(tc); + c_chandump(tc); + } } static int @@ -651,7 +725,9 @@ } if (Pid != claimnr && separate == 2) + { fprintf(th, "extern short src_ln%d[];\n", Pid); return; + } AllGlobal = (p->prov)?1:0; /* process has provided clause */ @@ -674,6 +750,7 @@ { fprintf(th, "\n#define in_s_scope(x_y3_) 0"); fprintf(tc, "\n#define in_r_scope(x_y3_) 0"); } + put_seq(p->s, 2, 0); if (Pid == eventmapnr) { fprintf(th, "\n\n"); @@ -700,7 +777,7 @@ SeqList *h; if (s) - for (f = s->frst; ; f = f->nxt) + for (f = s->frst; f; f = f->nxt) { Tpe(f->n); /* sets EPT */ addTpe(EPT[0]); addTpe(EPT[1]); @@ -753,7 +830,7 @@ && n->rgt && n->rgt->lft) return getNid(n->rgt->lft); - if (n->sym->Nid == 0) + if (!n->sym || n->sym->Nid == 0) { fatal("bad channel name '%s'", (n->sym)?n->sym->name:"no name"); } @@ -817,9 +894,9 @@ { int n; SeqList *x; - if (e->esc && e->n->ntyp != GOTO && e->n->ntyp != '.') + if (e->esc /* && e->n->ntyp != GOTO */ && e->n->ntyp != '.') { for (x = e->esc, n = 0; x; x = x->nxt, n++) - { int i = huntele(x->this->frst, e->status)->seqno; + { int i = huntele(x->this->frst, e->status, -1)->seqno; fprintf(tt, "\ttrans[%d][%d]->escp[%d] = %d;\n", Pid, e->seqno, n, i); fprintf(tt, "\treached%d[%d] = 1;\n", @@ -827,7 +904,7 @@ } for (x = e->esc, n=0; x; x = x->nxt, n++) { fprintf(tt, " /* escape #%d: %d */\n", n, - huntele(x->this->frst, e->status)->seqno); + huntele(x->this->frst, e->status, -1)->seqno); put_seq(x->this, 2, 0); /* args?? */ } fprintf(tt, " /* end-escapes */\n"); @@ -845,6 +922,8 @@ g = huntstart(s->frst); a = g->seqno; + if (0) printf("put_sub %d -> %d -> %d\n", e->seqno, s->frst->seqno, a); + if ((e->n->ntyp == ATOMIC || e->n->ntyp == D_STEP) && scan_seq(s)) @@ -863,20 +942,28 @@ if (s->last->n->ntyp == BREAK) OkBreak = target(huntele(s->last->nxt, - s->last->status))->Seqno; + s->last->status, -1))->Seqno; else OkBreak = -1; - if (!putcode(tm, s, e->nxt, 0, e->n->ln)) - fprintf(tm, "\t\tm = %d; goto P999;\n\n", - getweight(s->frst->n)); + if (!putcode(tm, s, e->nxt, 0, e->n->ln, e->seqno)) + { + fprintf(tm, "\n#if defined(C_States) && (HAS_TRACK==1)\n"); + fprintf(tm, "\t\tc_update((uchar *) &(now.c_state[0]));\n"); + fprintf(tm, "#endif\n"); + + fprintf(tm, "\t\t_m = %d", getweight(s->frst->n)); + if (m_loss && s->frst->n->ntyp == 's') + fprintf(tm, "+delta_m; delta_m = 0"); + fprintf(tm, "; goto P999;\n\n"); + } fprintf(tb, "\tcase %d: ", uniq-1); fprintf(tb, "/* STATE %d */\n", e->seqno); fprintf(tb, "\t\tsv_restor();\n"); fprintf(tb, "\t\tgoto R999;\n"); if (e->nxt) - a = huntele(e->nxt, e->status)->seqno; + a = huntele(e->nxt, e->status, -1)->seqno; else a = 0; tr_map(uniq-1, e); @@ -892,7 +979,7 @@ { /* ATOMIC or NON_ATOMIC */ fprintf(tt, "\tT = trans[ %d][%d] = ", Pid, e->seqno); fprintf(tt, "settr(%d,%d,0,0,0,\"", - e->Seqno, (e->n->ntyp == ATOMIC)?ATOM:0); + e->Seqno, (e->n->ntyp == ATOMIC)?ATOM:0); comment(tt, e->n, e->seqno); if ((e->status&CHECK2) || (g->status&CHECK2)) @@ -918,7 +1005,7 @@ } typedef struct CaseCache { - int m, b; + int m, b, owner; Element *e; Lextok *n; FSM_use *u; @@ -965,7 +1052,7 @@ if (f->n->ntyp == GOTO) { g = get_lab(f->n, 1); - return huntele(g, f->status); + return huntele(g, f->status, -1); } return f->nxt; } @@ -981,6 +1068,7 @@ case GOTO: case '.': case PRINT: + case PRINTM: break; default: return f; @@ -1022,7 +1110,7 @@ } static CaseCache * -prev_case(Element *e) +prev_case(Element *e, int owner) { int j; CaseCache *nc; switch (e->n->ntyp) { @@ -1036,14 +1124,15 @@ for (nc = casing[j]; nc; nc = nc->nxt) if (identical(nc->n, e->n) && samedeads(nc->u, e->dead) - && equiv_merges(nc->e, e)) + && equiv_merges(nc->e, e) + && nc->owner == owner) return nc; return (CaseCache *) 0; } static void -new_case(Element *e, int m, int b) +new_case(Element *e, int m, int b, int owner) { int j; CaseCache *nc; switch (e->n->ntyp) { @@ -1055,6 +1144,7 @@ default: j = 5; break; } nc = (CaseCache *) emalloc(sizeof(CaseCache)); + nc->owner = owner; nc->m = m; nc->b = b; nc->e = e; @@ -1075,7 +1165,7 @@ nr++; break; case 'r': - if (e->n->val == 1) + if (e->n->val >= 1) nr++; /* random recv */ for (v = e->n->rgt; v; v = v->rgt) { if ((v->lft->ntyp == CONST @@ -1113,26 +1203,32 @@ stopat = e->merge_start; else stopat = e->merge; - +#if 0 + printf("merge: %d merge_start %d - seqno %d\n", + e->merge, e->merge_start, e->seqno); +#endif do { cnt += nr_bup(f); if (f->n->ntyp == GOTO) { g = get_lab(f->n, 1); - f = huntele(g, f->status); + if (g->seqno == stopat) + f = g; + else + f = huntele(g, f->status, stopat); } else + { f = f->nxt; -#if 1 + } + if (f && !f->merge && !f->merge_single && f->seqno != stopat) - { - fprintf(tm, "\n\t\tbad hop %s:%d -- at %d, <", + { fprintf(tm, "\n\t\tbad hop %s:%d -- at %d, <", f->n->fn->name,f->n->ln, f->seqno); comment(tm, f->n, 0); fprintf(tm, "> looking for %d -- merge %d:%d:%d\n\t\t", stopat, f->merge, f->merge_start, f->merge_single); break; } -#endif } while (f && f->seqno != stopat); return cnt; @@ -1159,7 +1255,7 @@ { fprintf(tm, ";\n\t\tif (trpt->o_pm&1)\n\t\t"); fprintf(tm, "\tuerror(\"non-determinism in D_proctype\")"); } - + if (deadvar && !has_code) for (u = e->dead; u; u = u->nxt) { fprintf(tm, ";\n\t\t/* dead %d: %s */ ", u->special, u->var->name); @@ -1173,6 +1269,9 @@ } if (e->n->ntyp != 'r') { XZ.sym = u->var; + fprintf(tm, "\n#ifdef HAS_CODE\n"); + fprintf(tm, "\t\tif (!readtrail)\n"); + fprintf(tm, "#endif\n\t\t\t"); putname(tm, "", &XZ, 0, " = 0"); break; } /* else fall through */ @@ -1186,8 +1285,11 @@ multi_oval++; } else fprintf(tm, "(trpt+1)->bup.oval = "); - putname(tm, "", &YZ[YZmax], 0, ""); - putname(tm, ";\n\t\t", &YZ[YZmax], 0, " = 0"); + putname(tm, "", &YZ[YZmax], 0, ";\n"); + fprintf(tm, "#ifdef HAS_CODE\n"); + fprintf(tm, "\t\tif (!readtrail)\n"); + fprintf(tm, "#endif\n\t\t\t"); + putname(tm, "", &YZ[YZmax], 0, " = 0"); YZmax++; break; } } @@ -1221,6 +1323,7 @@ fprintf(tb, "s[%d]", multi_oval-1); } } + if (e->n->ntyp != '.') { fprintf(tb, ";\n\t\t"); undostmnt(e->n, e->seqno); @@ -1237,11 +1340,15 @@ if (f->n->ntyp == GOTO) { g = get_lab(f->n, 1); - f = huntele(g, f->status); + if (g->seqno == stopat) + f = g; + else + f = huntele(g, f->status, stopat); } else f = f->nxt; - if (!f || f->seqno == stopat) + if (!f || f->seqno == stopat + || (!f->merge && !f->merge_single)) return; lastfirst(stopat, f, casenr); #if 0 @@ -1267,14 +1374,14 @@ if (!s) return; - /* from could have all three labels -- rename + /* "from" could have all three labels -- rename * to prevent jumps to the transfered copies */ oc = context; /* remember */ for (ltp = 1; ltp < 8; ltp *= 2) /* 1, 2, and 4 */ - if (s = has_lab(from, ltp)) + if ((s = has_lab(from, ltp)) != (Symbol *) 0) { ns = (Symbol *) emalloc(sizeof(Symbol)); - ns->name = (char *) emalloc(strlen(s->name) + 4); + ns->name = (char *) emalloc((int) strlen(s->name) + 4); sprintf(ns->name, "%s%d", s->name, modifier); context = s->context; @@ -1300,25 +1407,29 @@ if (e->merge_mark > 0 || (merger && e->merge_in == 0)) - { /* state is unreachable */ -#if 0 - casenr = bupcase = 0; - fromcache = -1; - goto gotit; -#else + { /* state nominally unreachable (part of merge chains) */ + if (e->n->ntyp != '.' + && e->n->ntyp != GOTO) + { fprintf(tt, "\ttrans[%d][%d]\t= ", Pid, e->seqno); + fprintf(tt, "settr(0,0,0,0,0,\""); + comment(tt, e->n, e->seqno); + fprintf(tt, "\",0,0,0);\n"); + } else + { fprintf(tt, "\ttrans[%d][%d]\t= ", Pid, e->seqno); + casenr = 1; /* mhs example */ + j = a; + goto haveit; /* pakula's example */ + } + return -1; -#endif } fprintf(tt, "\ttrans[%d][%d]\t= ", Pid, e->seqno); if (ccache -#if 0 - && !e->merge - && !e->merge_start -#endif && Pid != claimnr - && (Cached = prev_case(e))) + && Pid != eventmapnr + && (Cached = prev_case(e, Pid))) { bupcase = Cached->b; casenr = Cached->m; fromcache = 1; @@ -1344,7 +1455,7 @@ if (nrbups > MAXMERGE-1) fatal("merge requires more than 256 bups", (char *)0); - if (e->n->ntyp != 'r' && Pid != claimnr) + if (e->n->ntyp != 'r' && Pid != claimnr && Pid != eventmapnr) fprintf(tm, "IfNotBlocked\n\t\t"); if (multi_needed != 0 || multi_undo != 0) @@ -1358,6 +1469,10 @@ memset(CnT, 0, sizeof(CnT)); YZmax = YZcnt = 0; + + /* the src xrefs have the numbers in e->seqno builtin */ + fprintf(tm, "reached[%d][%d] = 1;\n\t\t", Pid, e->seqno); + doforward(tm, e); if (e->merge_start) @@ -1370,17 +1485,24 @@ more: if (f->n->ntyp == GOTO) { g = get_lab(f->n, 1); - f = huntele(g, f->status); + if (g->seqno == target) + f = g; + else + f = huntele(g, f->status, target); } else f = f->nxt; + if (f && f->seqno != target) - { + { if (!f->merge && !f->merge_single) + { fprintf(tm, "/* stop at bad hop %d, %d */\n\t\t", + f->seqno, target); + goto out; + } fprintf(tm, "/* merge: "); comment(tm, f->n, 0); fprintf(tm, "(%d, %d, %d) */\n\t\t", f->merge, f->seqno, target); - fprintf(tm, "reached[ot][%d] = 1;\n\t\t", f->seqno); - + fprintf(tm, "reached[%d][%d] = 1;\n\t\t", Pid, f->seqno); YZcnt++; lab_transfer(e, f); mark = f->status&(ATOM|L_ATOM); /* last step wins */ @@ -1389,7 +1511,10 @@ goto more; } } - fprintf(tm, "m = %d; goto P999; /* %d */\n", getweight(e->n), YZcnt); +out: + fprintf(tm, "_m = %d", getweight(e->n)); + if (m_loss && e->n->ntyp == 's') fprintf(tm, "+delta_m; delta_m = 0"); + fprintf(tm, "; goto P999; /* %d */\n", YZcnt); multi_needed = 0; didcase = 0; @@ -1423,7 +1548,7 @@ } if (!e->merge && !e->merge_start) - new_case(e, casenr, bupcase); + new_case(e, casenr, bupcase, Pid); gotit: j = a; @@ -1431,7 +1556,7 @@ j = e->merge_start; else if (e->merge) j = e->merge; - +haveit: fprintf(tt, "%ssettr(%d,%d,%d,%d,%d,\"", fromcache?"/* c */ ":"", e->Seqno, mark, j, casenr, bupcase); @@ -1445,11 +1570,11 @@ if (e->n->ntyp == GOTO) { g = get_lab(e->n, 1); - g = huntele(g, e->status); + g = huntele(g, e->status, -1); cross_dsteps(e->n, g->n); a = g->seqno; } else if (e->nxt) - { g = huntele(e->nxt, e->status); + { g = huntele(e->nxt, e->status, -1); a = g->seqno; } else a = 0; @@ -1459,7 +1584,6 @@ e->status |= I_GLOB; /* don't remove dead edges in here, to preserve structure of fsm */ - if (e->merge_start || e->merge) goto non_generic; @@ -1467,8 +1591,9 @@ switch (e->n->ntyp) { case ELSE: casenr = 2; /* standard else */ + putskip(e->seqno); goto generic_case; - break; + /* break; */ case '.': case GOTO: case BREAK: @@ -1480,16 +1605,15 @@ break; #ifndef PRINTF case PRINT: - if (e->n->lft == ZN) - { casenr = 1; - goto generic_case; - } + goto non_generic; + case PRINTM: goto non_generic; #endif case 'c': if (e->n->lft->ntyp == CONST && e->n->lft->val == 1) /* skip or true */ { casenr = 1; + putskip(e->seqno); goto generic_case; } goto non_generic; @@ -1497,9 +1621,7 @@ default: non_generic: casenr = case_cache(e, a); - if (casenr < 0) return; /* unreachable state */ - break; } /* tailend of settr(...); */ @@ -1514,9 +1636,13 @@ } if ((e->merge_start && e->merge_start != a) || (e->merge && e->merge != a)) - fprintf(tt, " /* m: %d -> %d,%d */", + { fprintf(tt, " /* m: %d -> %d,%d */\n", a, e->merge_start, e->merge); + fprintf(tt, " reached%d[%d] = 1;", + Pid, a); /* Sheinman's example */ + } fprintf(tt, "\n"); + if (casenr > 2) tr_map(casenr, e); put_escp(e); @@ -1558,18 +1684,29 @@ Element *e, *g; int a, deadlink; + if (0) printf("put_seq %d\n", s->frst->seqno); + for (e = s->frst; e; e = e->nxt) - { if (e->status & DONE) + { + if (0) printf(" step %d\n", e->seqno); + if (e->status & DONE) + { + if (0) printf(" done before\n"); goto checklast; + } e->status |= DONE; if (e->n->ln) putsrc(e); if (e->n->ntyp == UNLESS) - { put_seq(e->sub->this, Tt0, Tt1); + { + if (0) printf(" an unless\n"); + put_seq(e->sub->this, Tt0, Tt1); } else if (e->sub) - { fprintf(tt, "\tT = trans[%d][%d] = ", + { + if (0) printf(" has sub\n"); + fprintf(tt, "\tT = trans[%d][%d] = ", Pid, e->seqno); fprintf(tt, "settr(%d,%d,0,0,0,\"", e->Seqno, e->status&ATOM); @@ -1597,7 +1734,7 @@ g->n->ln, g->n->fn?g->n->fn->name:""); } else deadlink = 0; - + if (0) printf(" settr %d %d\n", a, 0); if (h->nxt) fprintf(tt, "\tT = T->nxt\t= "); else @@ -1617,16 +1754,22 @@ for (h = e->sub; h; h = h->nxt) put_seq(h->this, Tt0, Tt1); } else - { if (e->n->ntyp == ATOMIC + { + if (0) printf(" [non]atomic %d\n", e->n->ntyp); + if (e->n->ntyp == ATOMIC || e->n->ntyp == D_STEP || e->n->ntyp == NON_ATOMIC) put_sub(e, Tt0, Tt1); else + { + if (0) printf(" put_el %d\n", e->seqno); put_el(e, Tt0, Tt1); + } } checklast: if (e == s->last) break; } + if (0) printf("put_seq done\n"); } static void @@ -1634,8 +1777,9 @@ { Element *f, *g; SeqList *h; - for (f = s->frst; ; f = f->nxt) - { if (f->n && f->n->ntyp == GOTO) + for (f = s->frst; f ; f = f->nxt) + { + if (f->n && f->n->ntyp == GOTO) { g = get_lab(f->n,1); cross_dsteps(f->n, g->n); if ((f->status & (ATOM|L_ATOM)) @@ -1643,13 +1787,12 @@ { f->status &= ~ATOM; f->status |= L_ATOM; } -/* new - bridges atomics */ + /* bridge atomics */ if ((f->status & L_ATOM) && (g->status & (ATOM|L_ATOM))) { f->status &= ~L_ATOM; f->status |= ATOM; } -/* end */ } else for (h = f->sub; h; h = h->nxt) patch_atomic(h->this); @@ -1663,8 +1806,14 @@ { Element *f; SeqList *h; - for (f = s->frst; ; f = f->nxt) + for (f = s->frst; f; f = f->nxt) { f->status |= I_GLOB; + + if (f->n->ntyp == ATOMIC + || f->n->ntyp == NON_ATOMIC + || f->n->ntyp == D_STEP) + mark_seq(f->n->sl->this); + for (h = f->sub; h; h = h->nxt) mark_seq(h->this); if (f == s->last) @@ -1689,7 +1838,7 @@ break; case BREAK: if (e->nxt) - f = find_target(huntele(e->nxt, e->status)); + f = find_target(huntele(e->nxt, e->status, -1)); /* else fall through */ default: f = e; @@ -1713,7 +1862,7 @@ { Element *f, *g; SeqList *h; - for (f = s->frst; ; f = f->nxt) + for (f = s->frst; f; f = f->nxt) { if ((f->status&CHECK2) || has_global(f->n)) return 1; @@ -1760,12 +1909,19 @@ if (AllGlobal) return 1; /* global provided clause */ switch (n->ntyp) { - case '.': case BREAK: case GOTO: case CONST: + case ATOMIC: + case D_STEP: + case NON_ATOMIC: + return scan_seq(n->sl->this); + + case '.': + case BREAK: + case GOTO: + case CONST: return 0; case ELSE: return n->val; /* true if combined with chan refs */ - case NAME: return (n->sym->context || (n->sym->hidden&64))?0:1; case 's': return glob_args(n)!=0 || ((n->sym->xu&(XS|XX)) != XS); case 'r': return glob_args(n)!=0 || ((n->sym->xu&(XR|XX)) != XR); case 'R': return glob_args(n)!=0 || (((n->sym->xu)&(XR|XS|XX)) != (XR|XS)); @@ -1775,8 +1931,19 @@ case EMPTY: return ((n->sym->xu&(XS|XX)) != XS); case LEN: return (((n->sym->xu)&(XR|XS|XX)) != (XR|XS)); + case NAME: + if (n->sym->context + || (n->sym->hidden&64) + || strcmp(n->sym->name, "_pid") == 0 + || strcmp(n->sym->name, "_") == 0) + return 0; + return 1; + case RUN: return 1-runsafe; + case C_CODE: case C_EXPR: + return glob_inline(n->sym->name); + case ENABLED: case PC_VAL: case NONPROGRESS: case 'p': case 'q': case TIMEOUT: @@ -1804,6 +1971,8 @@ for (v = n->lft; v; v = v->rgt) if (has_global(v->lft)) return 1; return 0; + case PRINTM: + return has_global(n->lft); } return 0; } @@ -1888,9 +2057,10 @@ } if (i > Npars) + { printf(" %d parameters used, %d expected\n", i, Npars); fatal("too many parameters in run %s(...)", now->sym->name); - + } for ( ; i < Npars; i++) fprintf(fd, ", 0"); fprintf(fd, ")"); @@ -1973,7 +2143,7 @@ case 's': if (Pid == eventmapnr) - { fprintf(fd, "if (_tp != 's' "); + { fprintf(fd, "if ((ot == EVENT_TRACE && _tp != 's') "); putname(fd, "|| _qid+1 != ", now->lft, m, ""); for (v = now->rgt, i=0; v; v = v->rgt, i++) { if (v->lft->ntyp != CONST @@ -2011,21 +2181,31 @@ putname(fd, "(", now->lft, m, "))\n"); if (m_loss) - { if (!GenCode) - fprintf(fd, "\t\t{ nlost++; m=3; goto P999; }\n"); - else - fprintf(fd, "\t\t\tnlost++;\n\t\telse {"); - } else + fprintf(fd, "\t\t{ nlost++; delta_m = 1; } else {"); + else { fprintf(fd, "\t\t\t"); Bailout(fd, ";"); } if (has_enabled) fprintf(fd, "\n\t\tif (TstOnly) return 1;"); -#if 1 + if (u_sync && !u_async && rvopt) fprintf(fd, "\n\n\t\tif (no_recvs(II)) continue;\n"); -#endif + + fprintf(fd, "\n#ifdef HAS_CODE\n"); + fprintf(fd, "\t\tif (readtrail && gui) {\n"); + fprintf(fd, "\t\t\tchar simtmp[32];\n"); + putname(fd, "\t\t\tsprintf(simvals, \"%%d!\", ", now->lft, m, ");\n"); + _isok++; + for (v = now->rgt, i = 0; v; v = v->rgt, i++) + { cat3("\t\tsprintf(simtmp, \"%%d\", ", v->lft, "); strcat(simvals, simtmp);"); + if (v->rgt) + fprintf(fd, "\t\tstrcat(simvals, \",\");\n"); + } + _isok--; + fprintf(fd, "\t\t}\n"); + fprintf(fd, "#endif\n\t\t"); putname(fd, "\n\t\tqsend(", now->lft, m, ""); fprintf(fd, ", %d", now->val); @@ -2033,8 +2213,10 @@ { cat2(", ", v->lft); } if (i > Mpars) - { putname(stdout, "channel name: ", now->lft, m, "\n"); - printf(" %d msg parameters\n", i); + { terse++; + putname(stdout, "channel name: ", now->lft, m, "\n"); + terse--; + printf(" %d msg parameters sent, %d expected\n", i, Mpars); fatal("too many pars in send", ""); } for ( ; i < Mpars; i++) @@ -2049,13 +2231,13 @@ fprintf(fd, "; Uerror(\"rv-attempt in d_step\")"); fprintf(fd, "; }"); } - if (m_loss && GenCode) - fprintf(fd, ";\n\t\t}\n\t\t"); + if (m_loss) + fprintf(fd, ";\n\t\t}\n\t\t"); /* end of m_loss else */ break; case 'r': if (Pid == eventmapnr) - { fprintf(fd, "if (_tp != 'r' "); + { fprintf(fd, "if ((ot == EVENT_TRACE && _tp != 'r') "); putname(fd, "|| _qid+1 != ", now->lft, m, ""); for (v = now->rgt, i=0; v; v = v->rgt, i++) { if (v->lft->ntyp != CONST @@ -2078,13 +2260,15 @@ } if (TestOnly) { fprintf(fd, "(("); - if (u_sync) - fprintf(fd, "(boq == -1 && "); + if (u_sync) fprintf(fd, "(boq == -1 && "); + putname(fd, "q_len(", now->lft, m, ")"); + if (u_sync && now->val <= 1) { putname(fd, ") || (boq == ", now->lft,m," && "); putname(fd, "q_zero(", now->lft,m,"))"); } + fprintf(fd, ")"); if (now->val == 0 || now->val == 2) { for (v = now->rgt, i=j=0; v; v = v->rgt, i++) @@ -2100,7 +2284,6 @@ { j++; continue; } } - fprintf(fd, ")"); } else { fprintf(fd, "\n\t\t&& Q_has("); putname(fd, "", now->lft, m, ""); @@ -2116,8 +2299,9 @@ } } for ( ; i < Mpars; i++) fprintf(fd, ", 0, 0"); - fprintf(fd, "))"); + fprintf(fd, ")"); } + fprintf(fd, ")"); break; } if (has_xu) @@ -2194,7 +2378,6 @@ fprintf(fd, ", 0, 0"); fprintf(fd, "))) "); Bailout(fd, ""); -/* new */ fprintf(fd, ";\n\t\t"); if (multi_oval) { check_needed(); @@ -2204,7 +2387,6 @@ } else fprintf(fd, "(trpt+1)->bup.oval = "); fprintf(fd, "XX"); -/* end */ } if (has_enabled) @@ -2225,9 +2407,7 @@ fprintf(fd, " != %d)\n\t", i); fprintf(fd, "\t\tUerror(\"wrong nr of msg fields in rcv\");\n\t\t"); } -#if 0 - putname(fd, "bup_q(II, ", now->lft, m, ");\n\t\t"); -#else + for (v = now->rgt; v; v = v->rgt) if ((v->lft->ntyp != CONST && v->lft->ntyp != EVAL)) @@ -2259,9 +2439,23 @@ _isok--; } } -#endif - } + if (jj) /* check for double entries q?x,x */ + { Lextok *w; + + for (v = now->rgt; v; v = v->rgt) + { if (v->lft->ntyp != CONST + && v->lft->ntyp != EVAL + && v->lft->sym + && v->lft->sym->type != STRUCT /* not a struct */ + && v->lft->sym->nel == 1 /* not an array */ + && strcmp(v->lft->sym->name, "_") != 0) + for (w = v->rgt; w; w = w->rgt) + if (v->lft->sym == w->lft->sym) + { fatal("cannot use var ('%s') in multiple msg fields", + v->lft->sym->name); + } } } + } /* set */ for (v = now->rgt, i = 0; v; v = v->rgt, i++) { if ((v->lft->ntyp == CONST || v->lft->ntyp == EVAL) && v->rgt) @@ -2301,6 +2495,25 @@ } } fprintf(fd, ";\n\t\t"); + + fprintf(fd, "\n#ifdef HAS_CODE\n"); + fprintf(fd, "\t\tif (readtrail && gui) {\n"); + fprintf(fd, "\t\t\tchar simtmp[32];\n"); + putname(fd, "\t\t\tsprintf(simvals, \"%%d?\", ", now->lft, m, ");\n"); + _isok++; + for (v = now->rgt, i = 0; v; v = v->rgt, i++) + { if (v->lft->ntyp != EVAL) + { cat3("\t\tsprintf(simtmp, \"%%d\", ", v->lft, "); strcat(simvals, simtmp);"); + } else + { cat3("\t\tsprintf(simtmp, \"%%d\", ", v->lft->lft, "); strcat(simvals, simtmp);"); + } + if (v->rgt) + fprintf(fd, "\t\tstrcat(simvals, \",\");\n"); + } + _isok--; + fprintf(fd, "\t\t}\n"); + fprintf(fd, "#endif\n\t\t"); + if (u_sync) { putname(fd, "if (q_zero(", now->lft, m, "))"); fprintf(fd, "\n\t\t{ boq = -1;\n"); @@ -2380,6 +2593,7 @@ break; case 'c': + preruse(fd, now->lft); /* preconditions */ cat3("if (!(", now->lft, "))\n\t\t\t"); Bailout(fd, ""); break; @@ -2397,9 +2611,13 @@ break; case '?': - cat3("( (", now->lft, ") ? "); - cat3("(", now->rgt->lft, ") : "); - cat3("(", now->rgt->rgt, ") )"); + if (now->lft) + { cat3("( (", now->lft, ") ? "); + } + if (now->rgt) + { cat3("(", now->rgt->lft, ") : "); + cat3("(", now->rgt->rgt, ") )"); + } break; case ASGN: @@ -2453,6 +2671,17 @@ fprintf(fd, ")"); break; + case PRINTM: + if (has_enabled) + fprintf(fd, "if (TstOnly) return 1;\n\t\t"); + fprintf(fd, "printm("); + if (now->lft && now->lft->ismtyp) + fprintf(fd, "%d", now->lft->val); + else + putstmnt(fd, now->lft, m); + fprintf(fd, ")"); + break; + case NAME: if (!nocast && now->sym && Sym_typ(now) < SHORT) putname(fd, "((int)", now, m, ")"); @@ -2471,6 +2700,29 @@ fprintf(fd, "%d", remotelab(now)); break; + case C_EXPR: + fprintf(fd, "("); + plunk_expr(fd, now->sym->name); + fprintf(fd, ") /* %s */ ", now->sym->name); + break; + + case C_CODE: + fprintf(fd, "/* %s */\n\t\t", now->sym->name); + if (has_enabled) + fprintf(fd, "if (TstOnly) return 1;\n\t\t"); + if (!GenCode) /* not in d_step */ + { fprintf(fd, "sv_save();\n\t\t"); + /* store the old values for reverse moves */ + } + plunk_inline(fd, now->sym->name, 1); + if (!GenCode) + { fprintf(fd, "\n"); /* state changed, capture it */ + fprintf(fd, "#if defined(C_States) && (HAS_TRACK==1)\n"); + fprintf(fd, "\t\tc_update((uchar *) &(now.c_state[0]));\n"); + fprintf(fd, "#endif\n"); + } + break; + case ASSERT: if (has_enabled) fprintf(fd, "if (TstOnly) return 1;\n\t\t"); @@ -2506,6 +2758,7 @@ default: printf("spin: bad node type %d (.m) - line %d\n", now->ntyp, now->ln); + fflush(tm); alldone(1); } } @@ -2580,7 +2833,8 @@ { fprintf(fd, "[%%d]"); } else if (evalindex == 1) { evalindex = 0; /* no good if index is indexed array */ - cat3(", ", n->lft, ""); + fprintf(fd, ", "); + putstmnt(fd, n->lft, m); evalindex = 1; } else { if (terse @@ -2604,25 +2858,34 @@ void putremote(FILE *fd, Lextok *n, int m) /* remote reference */ { int promoted = 0; + int pt; if (terse) - { fprintf(fd, "%s[", n->lft->sym->name); - putstmnt(fd, n->lft->lft, m); - fprintf(fd, "].%s", n->sym->name); + { fprintf(fd, "%s", n->lft->sym->name); /* proctype name */ + if (n->lft->lft) + { fprintf(fd, "["); + putstmnt(fd, n->lft->lft, m); /* pid */ + fprintf(fd, "]"); + } + fprintf(fd, ".%s", n->sym->name); } else { if (Sym_typ(n) < SHORT) { promoted = 1; fprintf(fd, "((int)"); } - fprintf(fd, "((P%d *)Pptr(", - fproc(n->lft->sym->name)); - fprintf(fd, "BASE+"); - putstmnt(fd, n->lft->lft, m); + + pt = fproc(n->lft->sym->name); + fprintf(fd, "((P%d *)Pptr(", pt); + if (n->lft->lft) + { fprintf(fd, "BASE+"); + putstmnt(fd, n->lft->lft, m); + } else + fprintf(fd, "f_pid(%d)", pt); fprintf(fd, "))->%s", n->sym->name); } if (n->rgt) { fprintf(fd, "["); - putstmnt(fd, n->rgt, m); + putstmnt(fd, n->rgt, m); /* array var ref */ fprintf(fd, "]"); } if (promoted) fprintf(fd, ")"); @@ -2650,4 +2913,34 @@ if (!n) return 0; if (n->ntyp == m) return 1; return (has_typ(n->lft, m) || has_typ(n->rgt, m)); +} + +static int runcount, opcount; + +static void +do_count(Lextok *n, int checkop) +{ + if (!n) return; + + switch (n->ntyp) { + case RUN: + runcount++; + break; + default: + if (checkop) opcount++; + break; + } + do_count(n->lft, checkop && (n->ntyp != RUN)); + do_count(n->rgt, checkop); +} + +void +count_runs(Lextok *n) +{ + runcount = opcount = 0; + do_count(n, 1); + if (runcount > 1) + fatal("more than one run operator in expression", ""); + if (runcount == 1 && opcount > 1) + fatal("use of run operator in compound expression", ""); } --- /sys/src/cmd/spin/pangen2.h Wed Aug 31 04:22:38 2005 +++ /sys/src/cmd/spin/pangen2.h Wed Aug 31 04:22:35 2005 @@ -1,14 +1,13 @@ /***** spin: pangen2.h *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ static char *Nvr1[] = { /* allow separate compilation */ "#ifdef VERI", @@ -18,20 +17,31 @@ " if (st == endclaim)", " uerror(\"claim violated!\");", " if (stopstate[VERI][st])", - " uerror(\"endstate in claim reached\");", + " uerror(\"end state in claim reached\");", "}", "#endif", 0, }; static char *Pre0[] = { +"#ifdef SC", + "#define _FILE_OFFSET_BITS 64", /* to allow file sizes greater than 2Gb */ +"#endif", "#include ", "#include ", "#include ", - "#include ", /* was strings.h -- string.h is ANSI */ -/* new */ + "#include ", + "#include ", + "#include ", "#include ", -/* end */ +"#ifdef SC", + "#include ", /* defines off_t */ + "#include ", + "#include ", + #ifndef PC + "#include ", + #endif +"#endif", "#define Offsetof(X, Y) ((unsigned long)(&(((X *)0)->Y)))", "#ifndef max", "#define max(a,b) (((a)<(b)) ? (b) : (a))", @@ -64,6 +74,9 @@ "#endif", "#ifdef MA", + "#undef onstack_now", + "#undef onstack_put", + "#undef onstack_zap", "#define onstack_put() ;", "#define onstack_zap() gstore((char *) &now, vsize, 4)", "#else", @@ -102,7 +115,7 @@ "} **H_tab, **S_Tab;\n", "typedef struct Trail {", - " short st; /* current state */", + " int st; /* current state */", " uchar pr; /* process id */", " uchar tau; /* 8 bit-flags */", " uchar o_pm; /* 8 more bit-flags */", @@ -126,10 +139,13 @@ " o_pm&64 -> the current proc applied rule2", " o_pm&128 -> a fairness, dummy move - all procs blocked", "#endif", - "#if defined(FULLSTACK) && defined(MA)", + "#if defined(FULLSTACK) && defined(MA) && !defined(BFS)", " uchar proviso;", "#endif", - " char o_n, o_ot, o_m; /* to save locals */", + "#ifndef BFS", + " uchar o_n, o_ot; /* to save locals */", + "#endif", + " uchar o_m;", "#ifdef EVENT_TRACE", "#if nstates_event<256", " uchar o_event;", @@ -137,17 +153,27 @@ " unsigned short o_event;", "#endif", "#endif", - " short o_tt, o_To;", /* used in new_state() */ - "#ifdef HAS_UNLESS", - " short e_state; /* if escape trans - state of origin */", + " int o_tt;", + "#ifndef BFS", + " short o_To;", + "#ifdef RANDOMIZE", + " short oo_i;", + "#endif", + "#endif", + "#if defined(HAS_UNLESS) && !defined(BFS)", + " int e_state; /* if escape trans - state of origin */", "#endif", - "#if defined(FULLSTACK) && !defined(MA)", + "#if (defined(FULLSTACK) && !defined(MA)) || defined(BFS)", " struct H_el *ostate; /* pointer to stored state */", "#endif", - "#ifdef CNTRSTACK", + /* CNTRSTACK when !NOREDUCE && BITSTATE && SAFETY, uses LL[] */ + "#if defined(CNTRSTACK) && !defined(BFS)", " long j6, j7;", "#endif", " Trans *o_t;", /* transition fct, next state */ + "#ifdef HAS_SORTED", + " short ipt;", /* insertion slot in q */ + "#endif", " union {", " int oval;", /* single backup value of variable */ " int *ovals;", /* ptr to multiple values */ @@ -158,18 +184,16 @@ "FILE *efd;", "uchar *this;", "long maxdepth=10000;", + "long omaxdepth=10000;", "#ifdef SC", /* stack cycling */ - "long omaxdepth;", "char *stackfile;", "#endif", "uchar *SS, *LL;", "uchar HASH_NR = 0;", "", - "#ifdef MEMCNT", "double memcnt = (double) 0;", - "double overhead = (double) 0;", "double memlim = (double) (1<<30);", - "#endif", + "", "/* for emalloc: */", "static char *have;", "static long left = 0L;", @@ -197,29 +221,34 @@ " 0x273d1aa5, 0x8923b1dd,", " 0", "};", - "int mreached=0, done=0, errors=0, Nrun=1, single=0;", + "int mreached=0, done=0, errors=0, Nrun=1;", "double nstates=0, nlinks=0, truncs=0, truncs2=0;", "double nlost=0, nShadow=0, hcmp=0, ngrabs=0;", + "#ifdef BFS", + "double midrv=0, failedrv=0, revrv=0;", + "#endif", "unsigned long nr_states=0; /* nodes in DFA */", "long Fa=0, Fh=0, Zh=0, Zn=0;", "long PUT=0, PROBE=0, ZAPS=0;", "long Ccheck=0, Cholds=0;", - "unsigned long mask;", - "int a_cycles=0, upto=1, strict=0, verbose = 0;", + "int a_cycles=0, upto=1, strict=0, verbose = 0, signoff = 0;", + "#ifdef HAS_CODE", + "int gui = 0, coltrace = 0, readtrail = 0, whichtrail = 0, onlyproc = -1;", + "#endif", "int state_tables=0, fairness=0, no_rck=0, Nr_Trails=0;", + "char simvals[128];", "#ifndef INLINE", "int TstOnly=0;", "#endif", + "unsigned long mask, nmask;", "#ifdef BITSTATE", - "int ssize=22;", + "int ssize=23; /* 1 Mb */", "#else", - "int ssize=18;", + "int ssize=19; /* 512K slots */", "#endif", "int hmax=0, svmax=0, smax=0;", "int Maxbody=0, XX;", "uchar *noptr; /* used by macro Pptr(x) */", - "State A_Root; /* root of acceptance cycles */", - "State now; /* the full state vector */", "#ifdef VAR_RANGES", "void logval(char *, int);", "void dumpranges(void);", @@ -228,27 +257,35 @@ "#ifdef MA", "#define INLINE_REV", "extern void dfa_init(unsigned short);", - "extern int dfa_member(unsigned short);", - "extern int dfa_store(unsigned char *);", + "extern int dfa_member(unsigned long);", + "extern int dfa_store(uchar *);", "unsigned int maxgs = 0;", "#endif", - "#if !defined(NOCOMP) || defined(BITSTATE)", "State comp_now; /* compressed state vector */", "State comp_msk;", "uchar *Mask = (uchar *) &comp_msk;", - "#endif", "#ifdef COLLAPSE", "State comp_tmp;", - "char *scratch = (char *) &comp_tmp;", + "static char *scratch = (char *) &comp_tmp;", "#endif", "Stack *stack; /* for queues, processes */", "Svtack *svtack; /* for old state vectors */", - "long J1, J2, J3, J4, j1, j2, j3, j4;", - "long A_depth = 0, depth = 0;", - "uchar warned = 0, iterative = 0, like_java = 0, every_error = 0;", - "uchar noasserts = 0, noends = 0;", + "#ifdef BITSTATE", + "static unsigned hfns = 3; /* new default */", + "#endif", + "static unsigned long j1;", + "static unsigned long K1, K2;", + "static unsigned long j2, j3, j4;", + "#ifdef BITSTATE", +#ifndef POWOW + "static long udmem;", +#endif + "#endif", + "static long A_depth = 0, depth = 0;", + "static uchar warned = 0, iterative = 0, like_java = 0, every_error = 0;", + "static uchar noasserts = 0, noends = 0, bounded = 0;", "#if SYNC>0 && ASYNC==0", "void set_recvs(void);", "int no_recvs(int);", @@ -260,6 +297,13 @@ "#define IfNotBlocked /* cannot block */", "#define UnBlock /* don't bother */", "#endif\n", + "#ifdef BITSTATE", + "int (*bstore)(char *, int);", + "int bstore_reg(char *, int);", +#ifndef POWOW + "int bstore_mod(char *, int);", +#endif + "#endif", "void active_procs(void);", "void cleanup(void);", "void do_the_search(void);", @@ -267,10 +311,6 @@ "void iniglobals(void);", "void stopped(int);", "void wrapup(void);", -#if 0 - "void bup_q(int, int);", - "void unbup_q(int, int);", -#endif "int *grab_ints(int);", "void ungrab_ints(int *, int);", 0, @@ -344,45 +384,8 @@ " return 0;", "}", "#endif", -/* new */ - "uchar *visited;", - "void", - "dovisit(int n, int m, int is, uchar reach[])", - "{ Trans *z;", - " if (is >= m || !trans[n][is]", - " || is <= 0 || visited[is])", - " return;", - " visited[is] = 1;", - " for (z = trans[n][is]; z; z = z->nxt)", - " { int i, j;", - " dovisit(n, m, z->st, reach);", - "#ifdef HAS_UNLESS", - " for (i = 0; i < HAS_UNLESS; i++)", - " { j = trans[n][is]->escp[i];", - " if (!j) break;", - " dovisit(n, m, j, reach);", - " }", - "#endif", - " }", - "}", - "void", - "check_unreachable(int n, int m, int is, short srcln[], uchar reach[])", - "{ int i; static int oldm=0;", - " if (m > oldm) /* not much memory */", - " { visited = (uchar *) emalloc(m * sizeof(uchar));", - " oldm = m;", - " } else", - " memset(visited, 0, m);", - " dovisit(n, m, is, reach);", - " for (i = 1; i < m; i++)", - " if (!visited[i] && reach[i] == 0)", - " { if (0) printf(\"%%s: merged state %%d, line %%d\\n\",", - " procname[n], i, srcln[i]);", - " reach[i] = 1;", - " }", - "}", - "int cnt;", + "#ifdef HAS_UNLESS", "int", "isthere(Trans *a, int b)", /* is b already in a's list? */ "{ Trans *t;", @@ -391,10 +394,11 @@ " return 1;", " return 0;", "}", + "#endif", "#ifndef NOREDUCE", "int", "mark_safety(Trans *t) /* for conditional safety */", - "{ int g = 0, h, i, j, k;", + "{ int g = 0, i, j, k;", "", " if (!t) return 0;", " if (t->qu[0])", @@ -402,7 +406,7 @@ "", " for (i = 0; i < 2; i++)", " { j = srinc_set(t->tpe[i]);", - " if (j >= GLOBAL)", + " if (j >= GLOBAL && j != ALPHA_F)", " return -1;", " if (j != LOCAL)", " { k = srunc(t->tpe[i], j);", @@ -420,7 +424,13 @@ "retrans(int n, int m, int is, short srcln[], uchar reach[])", " /* process n, with m states, is=initial state */", "{ Trans *T0, *T1, *T2, *T3;", - " int i, j, k, p, h, g, aa;", + " int i, k;", + "#ifndef NOREDUCE", + " int g, h, j, aa;", + "#endif", + "#ifdef HAS_UNLESS", + " int p;", + "#endif", " if (state_tables >= 4)", " { printf(\"STEP 1 proctype %%s\\n\", ", " procname[n]);", @@ -449,13 +459,13 @@ " if (!T3->nxt)", " { T2->nxt = cpytr(T0);", " T2 = T2->nxt;", - " imed(T2, T0->st, n);", + " imed(T2, T0->st, n, i);", " continue;", " }", " do { T3 = T3->nxt;", " T2->nxt = cpytr(T3);", " T2 = T2->nxt;", - " imed(T2, T0->st, n);", + " imed(T2, T0->st, n, i);", " } while (T3->nxt);", " cnt++;", " }", @@ -481,7 +491,7 @@ " T0 = cpytr(trans[n][T1->st]);", " trans[n][i] = T0;", " reach[T1->st] = 1;", - " imed(T0, T1->st, n);", + " imed(T0, T1->st, n, i);", " for (T1 = T1->nxt; T1; T1 = T1->nxt)", " {", "#if 0", @@ -492,7 +502,7 @@ " T0->nxt = cpytr(trans[n][T1->st]);", " T0 = T0->nxt;", " reach[T1->st] = 1;", - " imed(T0, T1->st, n);", + " imed(T0, T1->st, n, i);", " } } }", " if (state_tables >= 2)", " { printf(\"STEP 3 proctype %%s\\n\", ", @@ -576,8 +586,8 @@ " { if (!(T0->atom&8))", " goto degrade;", " for (aa = 0; aa < 2; aa++)", - " { if (srinc_set(T0->tpe[aa])", - " >= GLOBAL)", + " { j = srinc_set(T0->tpe[aa]);", + " if (j >= GLOBAL && j != ALPHA_F)", " goto degrade;", " if (T0->tpe[aa]", " && T0->tpe[aa]", @@ -602,13 +612,11 @@ " } } }", " if (g > 6)", " { T1->qu[0] = 0; /* turn it off */", - "#if 1", " printf(\"pan: warning, line %%d, \",", " srcln[i]);", " printf(\"too many stmnt types (%%d)\",", " g);", " printf(\" in selection\\n\");", - "#endif", " goto degrade;", " }", " }", @@ -628,27 +636,21 @@ " j = T1->tpe[0];", " if (T1->nxt && T1->atom&8)", " { if (j == 5*DELTA)", - " {", - "#if 1", - " printf(\"warning: line %%d \", srcln[i]);", + " { printf(\"warning: line %%d \", srcln[i]);", " printf(\"mixed condition \");", " printf(\"(defeats reduction)\\n\");", - "#endif", " goto degrade;", " }", " for (T0 = T1; T0; T0 = T0->nxt)", " for (aa = 0; aa < 2; aa++)", " if (T0->tpe[aa] && T0->tpe[aa] != j)", - " {", - "#if 1", - " printf(\"warning: line %%d \", srcln[i]);", + " { printf(\"warning: line %%d \", srcln[i]);", " printf(\"[%%d-%%d] mixed %%stion \",", " T0->tpe[aa], j, ", " (j==5*DELTA)?\"condi\":\"selec\");", " printf(\"(defeats reduction)\\n\");", " printf(\" '%%s' <-> '%%s'\\n\",", " T1->tp, T0->tp);", - "#endif", " goto degrade;", " } }", " }", @@ -683,7 +685,7 @@ " printf(\"line %%d, state %%d: has un\",", " srcln[i], i);", " printf(\"conditional self-loop\\n\");", - " exit(1);", + " pan_exit(1);", " } }", " nrelse = 0;", " for (T0 = trans[n][i]; T0; T0 = T0->nxt)", @@ -695,16 +697,16 @@ " procname[n]);", " printf(\" %%d, inherits %%d\", i, nrelse);", " printf(\" 'else' stmnts\\n\");", - " exit(1);", + " pan_exit(1);", " } }", - " check_unreachable(n, m, is, srcln, reach);", - "}\n", + "}", "void", - "imed(Trans *T, int v, int n) /* set intermediate state */", + "imed(Trans *T, int v, int n, int j) /* set intermediate state */", "{ progstate[n][T->st] |= progstate[n][v];", " accpstate[n][T->st] |= accpstate[n][v];", " stopstate[n][T->st] |= stopstate[n][v];", - "}\n", + " mapstate[n][j] = T->st;", + "}", "void", "tagtable(int n, int m, int is, short srcln[], uchar reach[])", "{ Trans *z;\n", @@ -716,7 +718,10 @@ " for (z = trans[n][is]; z; z = z->nxt)", " crack(n, is, z, srcln);", " for (z = trans[n][is]; z; z = z->nxt)", - " { int i, j;", + " {", + "#ifdef HAS_UNLESS", + " int i, j;", + "#endif", " tagtable(n, m, z->st, srcln, reach);", "#ifdef HAS_UNLESS", " for (i = 0; i < HAS_UNLESS; i++)", @@ -726,7 +731,7 @@ " }", "#endif", " }", - "}\n", + "}", "void", "crack(int n, int j, Trans *z, short srcln[])", "{ int i;\n", @@ -757,9 +762,6 @@ " printf(\"\\\\n\");", " else", " putchar(z->tp[i]);", - "#if 0", - " printf(\"\\n\");", - "#else", " if (z->qu[0])", " { printf(\"\\t[\");", " for (i = 0; i < 6; i++)", @@ -769,7 +771,6 @@ " printf(\"]\");", " }", " printf(\"\\n\");", - "#endif", " fflush(stdout);", "}", "", @@ -778,7 +779,7 @@ "", "typedef struct Vr_Ptr {", " char *nm;", - " unsigned char vals[BYTESIZE];", + " uchar vals[BYTESIZE];", " struct Vr_Ptr *nxt;", "} Vr_Ptr;", "Vr_Ptr *ranges = (Vr_Ptr *) 0;", @@ -800,7 +801,7 @@ "}", "", "void", - "dumpval(unsigned char X[], int range)", + "dumpval(uchar X[], int range)", "{ int w, x, i, j = -1;", "", " for (w = i = 0; w < range; w++)", --- /sys/src/cmd/spin/pangen3.c Wed Aug 31 04:22:52 2005 +++ /sys/src/cmd/spin/pangen3.c Wed Aug 31 04:22:51 2005 @@ -1,14 +1,13 @@ /***** spin: pangen3.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" #ifdef PC @@ -109,7 +108,7 @@ if (tmp->st == m) { if (tmp->ln != n || tmp->fn != e->n->fn) printf("putsrc mismatch %d - %d, file %s\n", n, - tmp->ln, tmp->fn); + tmp->ln, tmp->fn->name); return; } tmp = (SRC *) emalloc(sizeof(SRC)); @@ -160,12 +159,6 @@ for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt) if (tmp->st == j) { putnr(tmp->ln); -#if 0 - if (lst) - lst->nxt = tmp->nxt; - else - frst = tmp->nxt; -#endif break; } if (!tmp) @@ -321,9 +314,13 @@ case 'c': Cat3("(", now->lft, ")"); break; - case '?': Cat3("( (", now->lft, ") -> "); - Cat3("(", now->rgt->lft, ") : "); - Cat3("(", now->rgt->rgt, ") )"); + case '?': if (now->lft) + { Cat3("( (", now->lft, ") -> "); + } + if (now->rgt) + { Cat3("(", now->rgt->lft, ") : "); + Cat3("(", now->rgt->rgt, ") )"); + } break; case ASGN: comwork(fd,now->lft,m); @@ -351,11 +348,18 @@ } fprintf(fd, ")"); break; + case PRINTM: fprintf(fd, "printm("); + comwork(fd, now->lft, m); + fprintf(fd, ")"); + break; case NAME: putname(fd, "", now, m, ""); break; case 'p': putremote(fd, now, m); break; case 'q': fprintf(fd, "%s", now->sym->name); + break; + case C_EXPR: + case C_CODE: fprintf(fd, "{%s}", now->sym->name); break; case ASSERT: Cat3("assert(", now->lft, ")"); break; --- /sys/src/cmd/spin/pangen3.h Wed Aug 31 04:23:08 2005 +++ /sys/src/cmd/spin/pangen3.h Wed Aug 31 04:23:05 2005 @@ -1,16 +1,18 @@ /***** spin: pangen3.h *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ static char *Head0[] = { + "#if defined(BFS) && defined(REACH)", + "#undef REACH", /* redundant with bfs */ + "#endif", "#ifdef VERI", "#define BASE 1", "#else", @@ -18,7 +20,6 @@ "#endif", "typedef struct Trans {", " short atom; /* if &2 = atomic trans; if &8 local */", - " short st; /* the nextstate */", "#ifdef HAS_UNLESS", " short escp[HAS_UNLESS]; /* lists the escape states */", " short e_trans; /* if set, this is an escp-trans */", @@ -30,6 +31,7 @@ " short om; /* completion status of preselects */", "#endif", " char *tp; /* src txt of statement */", + " int st; /* the nextstate */", " int t_id; /* transition id, unique within proc */", " int forw; /* index forward transition */", " int back; /* index return transition */", @@ -49,8 +51,12 @@ static char *Header[] = { "#ifdef VERBOSE", + "#ifndef CHECK", "#define CHECK", + "#endif", + "#ifndef DEBUG", "#define DEBUG", + "#endif", "#endif", "#ifdef SAFETY", "#ifndef NOFAIR", @@ -58,7 +64,9 @@ "#endif", "#endif", "#ifdef NOREDUCE", + "#ifndef XUSAFE", "#define XUSAFE", + "#endif", "#if !defined(SAFETY) && !defined(MA)", "#define FULLSTACK", "#endif", @@ -74,25 +82,20 @@ "#endif", "#endif", "#ifdef BITSTATE", + "#ifndef NOCOMP", "#define NOCOMP", + "#endif", "#if !defined(LC) && defined(SC)", "#define LC", "#endif", "#endif", - "#ifndef MEMCNT", - "#ifdef PC", - "#define MEMCNT 25 /* 32 Mb */", - "#else", - "#define MEMCNT 28", - "#endif", - "#endif", - "#if defined(COLLAPSE2) || defined(COLLAPSE3) || defined(COLLAPSE4)", "/* accept the above for backward compatibility */", "#define COLLAPSE", "#endif", "#ifdef HC", - "#define HC2", + "#undef HC", + "#define HC4", "#endif", "#ifdef HC0", /* 32 bits */ "#define HC 0", @@ -147,12 +150,16 @@ "#if SYNC", " short o_boq;", "#endif", + 0, +}; + +static char *Header0[] = { " char *body;", " struct Svtack *nxt;", " struct Svtack *lst;", "} Svtack;\n", "Trans ***trans; /* 1 ptr per state per proctype */\n", - "#if defined(FULLSTACK)", + "#if defined(FULLSTACK) || defined(BFS)", "struct H_el *Lstate;", "#endif", "int depthfound = -1; /* loop detection */", @@ -216,7 +223,10 @@ static char *Addp0[] = { /* addproc(....parlist... */ ")", - "{ int k, j, h = now._nr_pr;", + "{ int j, h = now._nr_pr;", + "#ifndef NOCOMP", + " int k;", + "#endif", " uchar *o_this = this;\n", "#ifndef INLINE", " if (TstOnly) return (h < MAXPROC);", @@ -258,12 +268,12 @@ "#endif", " now._nr_pr += 1;", " if (fairness && ((int) now._nr_pr + 1 >= (8*NFAIR)/2))", - " { printf(\"Error: too many processes -- current\");", + " { printf(\"pan: error: too many processes -- current\");", " printf(\" max is %%d procs (-DNFAIR=%%d)\\n\",", " (8*NFAIR)/2 - 2, NFAIR);", " printf(\"\\trecompile with -DNFAIR=%%d\\n\",", " NFAIR+1);", - " exit(1);", + " pan_exit(1);", " }", " vsize += j;", @@ -294,7 +304,10 @@ static char *Addq0[] = { "int", "addqueue(int n, int is_rv)", - "{ int j=0, i = now._nr_qs, k;\n", + "{ int j=0, i = now._nr_qs;", + "#ifndef NOCOMP", + " int k;", + "#endif", " if (i >= MAXQ)", " Uerror(\"too many queues\");", " switch (n) {", @@ -309,9 +322,12 @@ " else", " q_skip[i] = 0;", "#ifndef NOCOMP", - " k = vsize; if (is_rv) k += j;", + " k = vsize;", + "#ifndef BFS", + " if (is_rv) k += j;", + "#endif", " for (k += q_skip[i]; k > vsize; k--)", - " Mask[k-1] = 1; /* align */", + " Mask[k-1] = 1;", "#endif", " vsize += q_skip[i];", " q_offset[i] = vsize;", @@ -331,7 +347,10 @@ }; static char *Addq11[] = { - "{ int j, k; uchar *z;\n", + "{ int j; uchar *z;\n", + "#ifdef HAS_SORTED", + " int k;", + "#endif", " if (!into--)", " uerror(\"ref to uninitialized chan name (sending)\");", " if (into >= (int) now._nr_qs || into < 0)", @@ -350,12 +369,15 @@ " if (in_s_scope(into+1))", " require('s', into);", "#endif", - "}\n", + "}", + "#endif\n", "#if SYNC", "int", "q_zero(int from)", "{ if (!from--)", - " uerror(\"ref to uninitialized chan name (q_zero)\");", + " { uerror(\"ref to uninitialized chan name (q_zero)\");", + " return 0;", + " }", " switch(((Q0 *)qptr(from))->_t) {", 0, }; @@ -364,6 +386,7 @@ " case 0: printf(\"queue %%d was deleted\\n\", from+1);", " }", " Uerror(\"bad queue q-zero\");", + " return -1;", "}", "int", "not_RV(int from)", @@ -407,8 +430,10 @@ " { printf(\"pan: xs assertion violated: \");", " printf(\"access to chan <%%s> (%%d)\\npan: by \",", " q_name[x], x-1);", - " printf(\"%%s (proc %%d) and by %%s (proc %%d)\\n\",", - " p_name[q_sender[x]-1], q_sender[x]-1,", + " if (q_sender[x] > 0 && p_name[q_sender[x]-1])", + " printf(\"%%s (proc %%d) and by \",", + " p_name[q_sender[x]-1], q_sender[x]-1);", + " printf(\"%%s (proc %%d)\\n\",", " p_name[who], who);", " uerror(\"error, partial order reduction invalid\");", " }", @@ -431,11 +456,12 @@ " } else", " if (q_recver[x] != who+1)", " { printf(\"pan: xr assertion violated: \");", - " printf(\"access to chan %%s (%%d)\\n\",", + " printf(\"access to chan %%s (%%d)\\npan: \",", " q_name[x], x-1);", - " printf(\"pan: by %%s (proc %%d) \",", + " if (q_recver[x] > 0 && p_name[q_recver[x]-1])", + " printf(\"by %%s (proc %%d) and \",", " p_name[q_recver[x]-1], q_recver[x]-1);", - " printf(\"and by %%s (proc %%d)\\n\",", + " printf(\"by %%s (proc %%d)\\n\",", " p_name[who], who);", " uerror(\"error, partial order reduction invalid\");", " }", @@ -469,6 +495,7 @@ " return !q_len(from) || q_full(from);", "}", "#endif", + "#if NQS>0", "int", "qrecv(int from, int slot, int fld, int done)", "{ uchar *z;", @@ -491,12 +518,13 @@ " default: Uerror(\"bad queue - qrecv\");", " }", " return r;", - "}\n", + "}", + "#endif\n", "#ifndef BITSTATE", "#ifdef COLLAPSE", "long", "col_q(int i, char *z)", - "{ int j, k;", + "{ int j=0, k;", " char *x, *y;", " Q0 *ptr = (Q0 *) qptr(i);", " switch (ptr->_t) {", @@ -506,7 +534,7 @@ static char *Code0[] = { "void", "run(void)", - "{ int i;", + "{ /* int i; */", " memset((char *)&now, 0, sizeof(State));", " vsize = sizeof(State) - VECTORSZ;", "#ifndef NOVSZ", @@ -528,6 +556,10 @@ " progstate[%d] = (uchar *) emalloc(nstates%d);", " stopstate[%d] = (uchar *) emalloc(nstates%d);", " visstate[%d] = (uchar *) emalloc(nstates%d);", + " mapstate[%d] = (short *) emalloc(nstates%d * sizeof(short));", + "#ifdef HAS_CODE", + " NrStates[%d] = nstates%d;", + "#endif", " stopstate[%d][endstate%d] = 1;", 0, }; @@ -547,7 +579,7 @@ " printf(\" stmnt executed in each merge sequence is shown\\n\");", " printf(\" (use spin -a -o3 to disable statement merging)\\n\");", "#endif", - " exit(0);", + " pan_exit(0);", " }", 0, }; @@ -572,6 +604,10 @@ "uchar *reached[%d];", "uchar *stopstate[%d];", "uchar *visstate[%d];", + "short *mapstate[%d];", + "#ifdef HAS_CODE", + "int NrStates[%d];", + "#endif", 0, }; static char *R3[] = { @@ -619,13 +655,12 @@ " for ( ; j > 0; j--, y++)", " if (!Mask[k++]) *x++ = *y;", - " if (z) return (long) (x - z);", " for (j = 0; j < WS-1; j++)", " *x++ = 0;", " x -= j;", - - " return ordinal(scratch, x-scratch, 2+ptr->_t);", + " if (z) return (long) (x - z);", + " return ordinal(scratch, x-scratch, (short) (2+ptr->_t));", "}", "#endif", "#endif", @@ -642,30 +677,18 @@ " for ( ; j > 0; j--, y++)", " if (!Mask[k++]) *x++ = *y;", - " if (z) return (long) (x - z);", " for (j = 0; j < WS-1; j++)", " *x++ = 0;", " x -= j;", + " if (z) return (long) (x - z);", " return ordinal(scratch, x-scratch, 1); /* chan */", "}", "#endif", "#endif", 0, }; -static char *R9[] = { - "typedef struct Q%d {", - " uchar Qlen; /* q_size */", - " uchar _t; /* q_type */", - " struct {", - 0, -}; -static char *R10[] = { - "typedef struct Q0 {\t/* generic q */", - " uchar Qlen, _t;", - "} Q0;", - 0, -}; + static char *R12[] = { "\t\tcase %d: r = ((Q%d *)z)->contents[slot].fld%d; break;", 0, @@ -673,7 +696,10 @@ char *R13[] = { "int ", "unsend(int into)", - "{ int m=0, j, k; uchar *z;\n", + "{ int _m=0, j; uchar *z;\n", + "#ifdef HAS_SORTED", + " int k;", + "#endif", " if (!into--)", " uerror(\"ref to uninitialized chan (unsend)\");", " z = qptr(into);", @@ -685,7 +711,7 @@ char *R14[] = { " default: Uerror(\"bad queue - unsend\");", " }", - " return m;", + " return _m;", "}\n", "void", "unrecv(int from, int slot, int fld, int fldvar, int strt)", @@ -714,13 +740,13 @@ "int addqueue(int, int);", "/* int atoi(char *); */", "int close(int);", -#ifndef PC +"#ifndef SC", "int creat(char *, unsigned short);", "int write(int, void *, unsigned);", -#endif +"#endif", "int delproc(int, int);", "int endstate(void);", - "int hstore(char *, int, short);", + "int hstore(char *, int);", "#ifdef MA", "int gstore(char *, int, uchar);", "#endif", @@ -730,17 +756,23 @@ "int q_zero(int);", "int qrecv(int, int, int, int);", "int unsend(int);", - "void *sbrk(int);", + "/* void *sbrk(int); */", "void Uerror(char *);", "void assert(int, char *, int, int, Trans *);", + "void c_chandump(int);", + "void c_globals(void);", + "void c_locals(int, int);", "void checkcycles(void);", "void crack(int, int, Trans *, short *);", "void d_hash(uchar *, int);", + "void s_hash(uchar *, int);", + "void r_hash(uchar *, int);", "void delq(int);", "void do_reach(void);", + "void pan_exit(int);", "void exit(int);", "void hinit(void);", - "void imed(Trans *, int, int);", + "void imed(Trans *, int, int, int);", "void new_state(void);", "void p_restor(int);", "void putpeg(int, int);", @@ -750,13 +782,12 @@ "void settable(void);", "void setq_claim(int, int, char *, int, char *);", "void sv_restor(void);", - "void sv_save(char *);", + "void sv_save(void);", "void tagtable(int, int, int, short *, uchar *);", "void uerror(char *);", "void unrecv(int, int, int, int, int);", "void usage(FILE *);", "void wrap_stats(void);", - "void xrefsrc(int, S_F_MAP *, int, int);", "#if defined(FULLSTACK) && defined(BITSTATE)", "int onstack_now(void);", "void onstack_init(void);", @@ -776,32 +807,23 @@ static char *SvMap[] = { "void", "to_compile(void)", - "{ char ctd[1024], carg[64]; int n;", + "{ char ctd[1024], carg[64];", "#ifdef BITSTATE", " strcpy(ctd, \"-DBITSTATE \");", "#else", " strcpy(ctd, \"\");", "#endif", - "#ifdef PC", - " strcat(ctd, \"-DPC \");", - "#endif", "#ifdef NOVSZ", " strcat(ctd, \"-DNOVSZ \");", "#endif", - "#ifdef MEMCNT", - "#ifdef PC", - " n = 25;", - "#else", - " n = 28;", - "#endif", - " if (MEMCNT != n)", - " { sprintf(carg, \"-DMEMCNT=%%d \", MEMCNT);", - " strcat(ctd, carg);", - " }", - "#endif", "#ifdef MEMLIM", " sprintf(carg, \"-DMEMLIM=%%d \", MEMLIM);", " strcat(ctd, carg);", + "#else", + "#ifdef MEMCNT", + " sprintf(carg, \"-DMEMCNT=%%d \", MEMCNT);", + " strcat(ctd, carg);", + "#endif", "#endif", "#ifdef NOCLAIM", " strcat(ctd, \"-DNOCLAIM \");", @@ -878,6 +900,10 @@ "#ifdef COLLAPSE", " strcat(ctd, \"-DCOLLAPSE \");", "#endif", + "#ifdef MA", + " sprintf(carg, \"-DMA=%%d \", MA);", + " strcat(ctd, carg);", + "#endif", "#ifdef SVDUMP", " strcat(ctd, \"-DSVDUMP \");", "#endif", @@ -897,14 +923,9 @@ " strcat(ctd, \"-DSDUMP \");", "#endif", "#ifdef COVEST", - " strcat(ctd, \"-DCOVEST \");", - "#endif", - " printf(\"Compiled as: cc -o pan %%span.c\", ctd);", - "#if defined(COVEST) && defined(BITSTATE)", - " printf(\" -lm\\n\");", - "#else", - " printf(\"\\n\");", + " strcat(ctd, \"-DCOVEST \");", "#endif", + " printf(\"Compiled as: cc -o pan %%span.c\\n\", ctd);", "}", 0, }; --- /sys/src/cmd/spin/pangen4.c Wed Aug 31 04:23:23 2005 +++ /sys/src/cmd/spin/pangen4.c Wed Aug 31 04:23:22 2005 @@ -1,14 +1,13 @@ /***** spin: pangen4.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" #ifdef PC @@ -18,16 +17,13 @@ #endif extern FILE *tc, *tb; -extern ProcList *cur_proc; extern Queue *qtab; extern Symbol *Fname; -extern int lineno, m_loss, Pid, eventmapnr, verbose, multi_oval; -extern short terse, nocast, has_provided, has_sorted; -extern short evalindex, withprocname, _isok; +extern int lineno, m_loss, Pid, eventmapnr, multi_oval; +extern short nocast, has_provided, has_sorted; extern char *R13[], *R14[], *R15[]; static void check_proc(Lextok *, int); -extern int dolocal(FILE *, char *, int, int, char *, char *); void undostmnt(Lextok *now, int m) @@ -52,9 +48,10 @@ case FULL: case EMPTY: case 'R': case NFULL: case NEMPTY: case ENABLED: case '?': case PC_VAL: case '^': + case C_EXPR: case NONPROGRESS: - putstmnt(tb, now, m); - break; + putstmnt(tb, now, m); + break; case RUN: fprintf(tb, "delproc(0, now._nr_pr-1)"); @@ -64,12 +61,8 @@ if (Pid == eventmapnr) break; if (m_loss) - { fprintf(tb, "if (m == 2) m = unsend"); - putname(tb, "(", now->lft, m, ")"); - } else - { fprintf(tb, "m = unsend"); - putname(tb, "(", now->lft, m, ")"); - } + fprintf(tb, "if (_m == 2) "); + putname(tb, "_m = unsend(", now->lft, m, ")"); break; case 'r': @@ -133,8 +126,11 @@ jj++; break; } } - jj = multi_oval - ii - 1; + + if (now->val == 1 && multi_oval > 0) + jj++; /* new 3.4.0 */ + for (v = now->rgt, i = 0; v; v = v->rgt, i++) { switch(v->lft->ntyp) { case CONST: @@ -181,10 +177,16 @@ case BREAK: break; + case C_CODE: + fprintf(tb, "sv_restor();\n"); + break; + case ASSERT: case PRINT: check_proc(now, m); break; + case PRINTM: + break; default: printf("spin: bad node type %d (.b)\n", now->ntyp); @@ -201,6 +203,7 @@ case ASSERT: case PRINT: return any_oper(now, RUN); + case PRINTM: case '.': case GOTO: case ELSE: @@ -240,29 +243,31 @@ for (q = qtab; q; q = q->nxt) { fprintf(tc, "\tcase %d:\n", q->qid); - if (has_sorted) - { sprintf(buf1, "((Q%d *)z)->contents", q->qid); - fprintf(tc, "\t\tj = trpt->bup.oval;\n"); - fprintf(tc, "\t\tfor (k = j; k < ((Q%d *)z)->Qlen; k++)\n", - q->qid); - fprintf(tc, "\t\t{\n"); - for (i = 0; i < q->nflds; i++) - fprintf(tc, "\t\t\t%s[k].fld%d = %s[k+1].fld%d;\n", - buf1, i, buf1, i); - fprintf(tc, "\t\t}\n"); - fprintf(tc, "\t\tj = ((Q0 *)z)->Qlen;\n"); - } + if (has_sorted) + { sprintf(buf1, "((Q%d *)z)->contents", q->qid); + fprintf(tc, "#ifdef HAS_SORTED\n"); + fprintf(tc, "\t\tj = trpt->ipt;\n"); /* ipt was bup.oval */ + fprintf(tc, "#endif\n"); + fprintf(tc, "\t\tfor (k = j; k < ((Q%d *)z)->Qlen; k++)\n", + q->qid); + fprintf(tc, "\t\t{\n"); + for (i = 0; i < q->nflds; i++) + fprintf(tc, "\t\t\t%s[k].fld%d = %s[k+1].fld%d;\n", + buf1, i, buf1, i); + fprintf(tc, "\t\t}\n"); + fprintf(tc, "\t\tj = ((Q0 *)z)->Qlen;\n"); + } sprintf(buf1, "((Q%d *)z)->contents[j].fld", q->qid); for (i = 0; i < q->nflds; i++) fprintf(tc, "\t\t%s%d = 0;\n", buf1, i); if (q->nslots==0) { /* check if rendezvous succeeded, 1 level down */ - fprintf(tc, "\t\tm = (trpt+1)->o_m;\n"); - fprintf(tc, "\t\tif (m) (trpt-1)->o_pm |= 1;\n"); + fprintf(tc, "\t\t_m = (trpt+1)->o_m;\n"); + fprintf(tc, "\t\tif (_m) (trpt-1)->o_pm |= 1;\n"); fprintf(tc, "\t\tUnBlock;\n"); } else - fprintf(tc, "\t\tm = trpt->o_m;\n"); + fprintf(tc, "\t\t_m = trpt->o_m;\n"); fprintf(tc, "\t\tbreak;\n"); } --- /sys/src/cmd/spin/pangen4.h Wed Aug 31 04:23:41 2005 +++ /sys/src/cmd/spin/pangen4.h Wed Aug 31 04:23:39 2005 @@ -1,10 +1,13 @@ /***** spin: pangen4.h *****/ -/* Copyright (c) 1997-2000 by Lucent Technologies - Bell Laboratories. */ +/* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ /* The DFA code below was written by Anuj Puri and Gerard J. Holzmann in */ /* May 1997, and was inspired by earlier work on data compression using */ @@ -29,7 +32,7 @@ "", "extern char *emalloc(unsigned long); /* imported routine */", "extern void dfa_init(ushort); /* 4 exported routines */", - "extern int dfa_member(ushort);", + "extern int dfa_member(ulong);", "extern int dfa_store(uchar *);", "extern void dfa_stats(void);", "", @@ -53,9 +56,6 @@ "static Vertex **layers; /* one splay tree of nodes per layer */", "static Vertex **path; /* run of word in the DFA */", "static Vertex *R, *F, *NF; /* Root, Final, Not-Final */", -#if 0 - "/* extern ulong nr_states=0; /* number of nodes in the DFA */", -#endif "static uchar *word, *lastword;/* string, and last string inserted */", "static int dfa_depth, iv=0, nv=0, pfrst=0, Tally;", "", @@ -204,7 +204,7 @@ "", "static Vertex *", "Delta(Vertex *v, int h) /* v->delta[h] */", - "{ register Edge *e;", + "{ Edge *e;", "", " if (v->dst[0] && h >= v->from[0] && h <= v->to[0])", " return v->dst[0]; /* oldest edge */", @@ -219,8 +219,8 @@ "", "static void", "numDelta(Vertex *v, int d)", - "{ register Edge *e;", - " register ulong cnt;", + "{ Edge *e;", + " ulong cnt;", " int i;", "", " for (i = 0; i < 2; i++)", @@ -367,8 +367,8 @@ "", "static ulong", "mk_key(Vertex *v) /* not sensitive to order */", - "{ register ulong m = 0, vk2 = 0;", - " register Edge *e;", + "{ ulong m = 0, vk2 = 0;", + " Edge *e;", "", " if (v->dst[0])", " { m += HASH(v->dst[0], v->to[0] - v->from[0] + 1);", @@ -388,8 +388,8 @@ "", "static ulong", "mk_special(int sigma, Vertex *n, Vertex *v)", - "{ register ulong m = 0, vk2 = 0;", - " register Edge *f; Vertex *last = (Vertex *) 0;", + "{ ulong m = 0, vk2 = 0;", + " Edge *f;", " int i;", "", " for (i = 0; i < 2; i++)", @@ -471,7 +471,7 @@ "}", "", "int", - "dfa_member(ushort n)", + "dfa_member(ulong n)", "{ Vertex **p, **q;", " uchar *w = &word[n];", " int i;", @@ -495,20 +495,20 @@ " memcpy(&lastword[pfrst], &sv[pfrst], dfa_depth-pfrst);", " if (pfrst > iv) pfrst = iv;", " if (pfrst > nv) pfrst = nv;", - "phase1:", + "/* phase1: */", " p = &path[pfrst]; q = (p+1); w = &word[pfrst];", " for (i = pfrst; i < dfa_depth; i++)", " *q++ = Delta(*p++, *w++); /* (*p)->delta[*w++]; */", "", " if (*p == F) return 1; /* it's already there */", - "phase2:", + "/* phase2: */", " iv = dfa_depth;", " do { iv--;", " old = new;", " new = find_it(path[iv], old, word[iv], iv);", " } while (new && iv > 0);", "", - "phase3:", + "/* phase3: */", " nv = k = 0; s = path[0];", " for (j = 1; j <= iv; ++j) ", " if (path[j]->num > 1)", --- /sys/src/cmd/spin/pangen5.c Wed Aug 31 04:23:59 2005 +++ /sys/src/cmd/spin/pangen5.c Wed Aug 31 04:23:57 2005 @@ -1,14 +1,15 @@ /***** spin: pangen5.c *****/ -/* Copyright (c) 1999-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1999-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Written by Gerard J. Holzmann. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" -#include "version.h" #ifdef PC #include "y_tab.h" #else @@ -21,24 +22,28 @@ } BuildStack; extern ProcList *rdy; -extern int verbose, eventmapnr, claimnr, rvopt, xspin; +extern int verbose, eventmapnr, claimnr, rvopt, export_ast, u_sync; extern Element *Al_El; -static FSM_state *fsm; static FSM_state *fsm_free; static FSM_trans *trans_free; -static FSM_use *use_free; static BuildStack *bs, *bf; -static FSM_state **fsm_tbl; static int max_st_id; static int cur_st_id; -static int o_max; +int o_max; +FSM_state *fsm; +FSM_state **fsm_tbl; +FSM_use *use_free; static void ana_seq(Sequence *); static void ana_stmnt(FSM_trans *, Lextok *, int); -extern int has_global(Lextok *); -void +extern void AST_slice(void); +extern void AST_store(ProcList *, int); +extern int has_global(Lextok *); +extern void exit(int); + +static void fsm_table(void) { FSM_state *f; max_st_id += 2; @@ -118,28 +123,8 @@ } #if 0 -static int -badjump(Element *e) -{ Element *g; - - /* e->n->ntyp == GOTO */ - g = get_lab(e->n, 1); - g = huntele(g, e->status); - if (g && g->n) - { switch (g->n->ntyp) { - case ATOMIC: - case NON_ATOMIC: - case D_STEP: - case IF: - case DO: - case UNLESS: - case ELSE: - return 1; - } } - return 0; -} -#endif static int howdeep = 0; +#endif static int eligible(FSM_trans *v) @@ -155,9 +140,9 @@ || (el->status&CHECK2) /* remotely referenced */ || lt->ntyp == ATOMIC || lt->ntyp == NON_ATOMIC /* used for inlines -- should be able to handle this */ -#if 1 || lt->ntyp == IF -#endif + || lt->ntyp == C_CODE + || lt->ntyp == C_EXPR || has_lab(el, 0) /* any label at all */ || lt->ntyp == DO @@ -169,48 +154,13 @@ || lt->ntyp == 'r' || lt->ntyp == 's') return 0; -#if 0 - if (lt && lt->ntyp == GOTO && badjump(el)) - return 0; -#endif + if (!(el->status&(2|4))) /* not atomic */ { int unsafe = (el->status&I_GLOB)?1:has_global(el->n); if (unsafe) return 0; } -#if 0 - if (lt->ntyp == IF) - { SeqList *h; - Element *g; - int cnt=0, has_else=0; - - /* is it clearly deterministic? */ - - for (h = v->step->sub; h; h = h->nxt, cnt++) - { g = huntstart(h->this->frst); - if (!g || g->esc || !g->n) - return 0; - switch (g->n->ntyp) { - case ELSE: - has_else=1; - /* fall through */ - case 'c': - break; - default: - return 0; - } - } - if (cnt != 2 || !has_else) - return 0; - -/* should also be no GOTO, BREAK, or ineligible stmnts in either sequence */ -printf("spin: %s:%d: may have handled if\n", - lt->fn?lt->fn->name:"", lt->ln); - - return 0; - } -#endif return 1; } @@ -266,14 +216,14 @@ build_step(FSM_trans *v) { FSM_state *f; Element *el = v->step; +#if 0 Lextok *lt = ZN; +#endif int st = v->to; int r; if (!el) return -1; - lt = v->step->n; - if (v->step->merge) return v->step->merge; /* already done */ @@ -285,6 +235,7 @@ f = fsm_tbl[st]; #if 0 + lt = v->step->n; if (verbose&32) { if (++howdeep == 1) printf("spin: %s, line %3d, merge:\n", @@ -299,7 +250,10 @@ v->step->merge = (r == -1) ? st : r; #if 0 if (verbose&32) + { printf(" merge value: %d (st=%d,r=%d, line %d)\n", + v->step->merge, st, r, el->n->ln); howdeep--; + } #endif popbuild(); @@ -307,7 +261,7 @@ } static void -FSM_MERGER(char *pname) /* find candidates for safely merging steps */ +FSM_MERGER(char *pname_unused) /* find candidates for safely merging steps */ { FSM_state *f, *g; FSM_trans *t; Lextok *lt; @@ -369,11 +323,19 @@ continue; lt = t->step->n; +#if 0 + 4.1.3: + an rv send operation inside an atomic, *loses* atomicity + when executed + and should therefore never be merged with a subsequent + statement within the atomic sequence + the same is not true for non-rv send operations +#endif - if (lt->ntyp == 'c' + if (lt->ntyp == 'c' /* potentially blocking stmnts */ || lt->ntyp == 'r' - || lt->ntyp == 's') /* blocking stmnts */ - { if (!canfill_in(t)) + || (lt->ntyp == 's' && u_sync == 0)) /* added !u_sync in 4.1.3 */ + { if (!canfill_in(t)) /* atomic, non-global, etc. */ continue; g = fsm_tbl[t->to]; @@ -420,6 +382,7 @@ u->special = n+1; /* means, reset to 0 after use */ } + if (!export_ast) for (f = fsm; f; f = f->nxt) for (t = f->t; t; t = t->nxt) for (n = 0; n < 2; n++) @@ -430,7 +393,7 @@ t->Val[n] = v; else w->nxt = v; -#if 0 +#if q if (verbose&32) { printf("%s : %3d: %d -> %d \t", t->step->n->fn->name, @@ -453,7 +416,7 @@ } } } -static void +void rel_use(FSM_use *u) { if (!u) return; @@ -519,12 +482,9 @@ return f; } -static void -FSM_EDGE(int from, int to, Element *e) -{ FSM_state *f; - FSM_trans *t; - - f = mkstate(from); /* find it or else make it */ +static FSM_trans * +get_trans(int to) +{ FSM_trans *t; if (trans_free) { t = trans_free; @@ -532,7 +492,19 @@ trans_free = trans_free->nxt; } else t = (FSM_trans *) emalloc(sizeof(FSM_trans)); + t->to = to; + return t; +} + +static void +FSM_EDGE(int from, int to, Element *e) +{ FSM_state *f; + FSM_trans *t; + + f = mkstate(from); /* find it or else make it */ + t = get_trans(to); + t->step = e; t->nxt = f->t; f->t = t; @@ -540,6 +512,13 @@ f = mkstate(to); f->in++; + if (export_ast) + { t = get_trans(from); + t->step = e; + t->nxt = f->p; /* from is a predecessor of to */ + f->p = t; + } + if (t->step) ana_stmnt(t, t->step->n, 0); } @@ -551,10 +530,13 @@ ana_var(FSM_trans *t, Lextok *now, int usage) { FSM_use *u, *v; - if (!t - || !now - || !now->sym - || now->sym->name[0] == '_') + if (!t || !now || !now->sym) + return; + + if (now->sym->name[0] == '_' + && (strcmp(now->sym->name, "_") == 0 + || strcmp(now->sym->name, "_pid") == 0 + || strcmp(now->sym->name, "_last") == 0)) return; v = t->Val[usage]; @@ -606,6 +588,8 @@ case ATOMIC: case NON_ATOMIC: case D_STEP: + case C_CODE: + case C_EXPR: break; case '!': @@ -641,8 +625,8 @@ case AND: case LSHIFT: case RSHIFT: - ana_stmnt(t,now->lft, RVAL); - ana_stmnt(t,now->rgt, RVAL); + ana_stmnt(t, now->lft, RVAL); + ana_stmnt(t, now->rgt, RVAL); break; case ASGN: @@ -656,6 +640,11 @@ ana_stmnt(t, v->lft, RVAL); break; + case PRINTM: + if (now->lft && !now->lft->ismtyp) + ana_stmnt(t, now->lft, RVAL); + break; + case 's': ana_stmnt(t, now->lft, RVAL); for (v = now->rgt; v; v = v->rgt) @@ -677,8 +666,10 @@ case '?': ana_stmnt(t, now->lft, RVAL); - ana_stmnt(t, now->rgt->lft, RVAL); - ana_stmnt(t, now->rgt->rgt, RVAL); + if (now->rgt) + { ana_stmnt(t, now->rgt->lft, RVAL); + ana_stmnt(t, now->rgt->rgt, RVAL); + } break; case NAME: @@ -692,17 +683,18 @@ break; default: - printf("spin: bad node type %d (ana_stmnt)\n", now->ntyp); + printf("spin: bad node type %d line %d (ana_stmnt)\n", now->ntyp, now->ln); fatal("aborting", (char *) 0); } } void -ana_src(int dataflow, int merger) +ana_src(int dataflow, int merger) /* called from main.c and guided.c */ { ProcList *p; Element *e; +#if 0 int counter = 1; - +#endif for (p = rdy; p; p = p->nxt) { if (p->tn == eventmapnr || p->tn == claimnr) @@ -724,11 +716,14 @@ } if (merger) { FSM_MERGER(p->n->name); - huntele(e, e->status)->merge_in = 1; /* start-state */ + huntele(e, e->status, -1)->merge_in = 1; /* start-state */ #if 0 printf("\n"); #endif } + if (export_ast) + AST_store(p, huntele(e, e->status, -1)->seqno); + FSM_DEL(); } for (e = Al_El; e; e = e->Nxt) @@ -742,24 +737,14 @@ } e->status &= ~DONE; } + if (export_ast) + { AST_slice(); + exit(0); + } } -#if 0 -void -whichnodeis(int s) -{ Element *e; - for (e = Al_El; e; e = e->Nxt) - if (e->seqno == s) - { printf("\n\tnode %s:%d: ", - e->n->fn->name, e->n->ln); - comment(stdout, e->n, 0); - printf("\n"); - } -} -#endif - void -spit_recvs(FILE *f1, FILE *f2) +spit_recvs(FILE *f1, FILE *f2) /* called from pangen2.c */ { Element *e; Sequence *s; extern int Unique; @@ -849,10 +834,10 @@ } else { if (e->n->ntyp == GOTO) { g = get_lab(e->n, 1); - g = huntele(g, e->status); + g = huntele(g, e->status, -1); To = g->seqno; } else if (e->nxt) - { g = huntele(e->nxt, e->status); + { g = huntele(e->nxt, e->status, -1); To = g->seqno; } else To = 0; --- /sys/src/cmd/spin/pangen5.h Wed Aug 31 04:24:16 2005 +++ /sys/src/cmd/spin/pangen5.h Wed Aug 31 04:24:15 2005 @@ -1,14 +1,16 @@ /***** spin: pangen5.h *****/ -/* Copyright (c) 1997-2000 by Lucent Technologies - Bell Laboratories. */ +/* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* The checkpointing code below was written by Gerard J. Holzmann */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ static char *Xpt[] = { - "#if defined(W_XPT) || defined(R_XPT)", + "#if defined(MA) && (defined(W_XPT) || defined(R_XPT))", "static Vertex **temptree;", "static char wbuf[4096];", "static int WCNT = 4096, wcnt=0;", @@ -129,7 +131,6 @@ "static void", "x_remove(void)", "{ Vertex *tmp; int i, s;", - "#if 1", " int r, j;", " /* double-check: */", " stacker[dfa_depth-1] = 0; r = dfa_store(stacker);", @@ -141,7 +142,6 @@ " printf(\" -- not a stackstate \\n\", r, j);", " return;", " }", - "#endif", " stacker[dfa_depth-1] = 1;", " s = dfa_member(dfa_depth-1);", "", @@ -291,7 +291,9 @@ " yes = no = 0;", " for (i = 0; i < 2; i++)", " if ((ulong) t->dst[i] == want)", - " { if (t->from[i] <= 0 && t->to[i] >= 0)", + " { /* was t->from[i] <= 0 && t->to[i] >= 0 */", + " /* but from and to are uchar */", + " if (t->from[i] == 0)", " yes = 1;", " else", " if (t->from[i] <= 4 && t->to[i] >= 4)", @@ -300,7 +302,8 @@ "", " for (e = t->Succ; e; e = e->Nxt)", " if ((ulong) e->Dst == want)", - " { if (INRANGE(e, 0))", + " { /* was INRANGE(e,0) but From and To are uchar */", + " if ((e->From == 0) || (e->s==1 && e->S==0))", " yes = 1;", " else if (INRANGE(e, 4))", " no = 1;", @@ -348,9 +351,7 @@ "", "static Vertex *", "x_cpy_rev(void)", - "{ Vertex *c, *v;", - "", - " /* find 0 and !4 predecessor of F */", + "{ Vertex *c, *v; /* find 0 and !4 predecessor of F */", "", " v = x_tail(temptree[dfa_depth-1], F->key);", " if (!v) return (Vertex *) 0;", --- /sys/src/cmd/spin/pangen6.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/spin/pangen6.c Wed Aug 31 04:24:34 2005 @@ -0,0 +1,2357 @@ +/***** spin: pangen6.c *****/ + +/* Copyright (c) 2000-2003 by Lucent Technologies, Bell Laboratories. */ +/* All Rights Reserved. This software is for educational purposes only. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + +/* Abstract syntax tree analysis / slicing (spin option -A) */ +/* AST_store stores the fsms's for each proctype */ +/* AST_track keeps track of variables used in properties */ +/* AST_slice starts the slicing algorithm */ +/* it first collects more info and then calls */ +/* AST_criteria to process the slice criteria */ + +#include "spin.h" +#ifdef PC +#include "y_tab.h" +#else +#include "y.tab.h" +#endif + +extern Ordered *all_names; +extern FSM_use *use_free; +extern FSM_state **fsm_tbl; +extern FSM_state *fsm; +extern int verbose, o_max; + +static FSM_trans *cur_t; +static FSM_trans *expl_par; +static FSM_trans *expl_var; +static FSM_trans *explicit; + +extern void rel_use(FSM_use *); + +#define ulong unsigned long + +typedef struct Pair { + FSM_state *h; + int b; + struct Pair *nxt; +} Pair; + +typedef struct AST { + ProcList *p; /* proctype decl */ + int i_st; /* start state */ + int nstates, nwords; + int relevant; + Pair *pairs; /* entry and exit nodes of proper subgraphs */ + FSM_state *fsm; /* proctype body */ + struct AST *nxt; /* linked list */ +} AST; + +typedef struct RPN { /* relevant proctype names */ + Symbol *rn; + struct RPN *nxt; +} RPN; + +typedef struct ALIAS { /* channel aliasing info */ + Lextok *cnm; /* this chan */ + int origin; /* debugging - origin of the alias */ + struct ALIAS *alias; /* can be an alias for these other chans */ + struct ALIAS *nxt; /* linked list */ +} ALIAS; + +typedef struct ChanList { + Lextok *s; /* containing stmnt */ + Lextok *n; /* point of reference - could be struct */ + struct ChanList *nxt; /* linked list */ +} ChanList; + +/* a chan alias can be created in one of three ways: + assignement to chan name + a = b -- a is now an alias for b + passing chan name as parameter in run + run x(b) -- proctype x(chan a) + passing chan name through channel + x!b -- x?a + */ + +#define USE 1 +#define DEF 2 +#define DEREF_DEF 4 +#define DEREF_USE 8 + +static AST *ast; +static ALIAS *chalcur; +static ALIAS *chalias; +static ChanList *chanlist; +static Slicer *slicer; +static Slicer *rel_vars; /* all relevant variables */ +static int AST_Changes; +static int AST_Round; +static FSM_state no_state; +static RPN *rpn; +static int in_recv = 0; + +static int AST_mutual(Lextok *, Lextok *, int); +static void AST_dominant(void); +static void AST_hidden(void); +static void AST_setcur(Lextok *); +static void check_slice(Lextok *, int); +static void curtail(AST *); +static void def_use(Lextok *, int); +static void name_AST_track(Lextok *, int); +static void show_expl(void); + +static int +AST_isini(Lextok *n) /* is this an initialized channel */ +{ Symbol *s; + + if (!n || !n->sym) return 0; + + s = n->sym; + + if (s->type == CHAN) + return (s->ini->ntyp == CHAN); /* freshly instantiated */ + + if (s->type == STRUCT && n->rgt) + return AST_isini(n->rgt->lft); + + return 0; +} + +static void +AST_var(Lextok *n, Symbol *s, int toplevel) +{ + if (!s) return; + + if (toplevel) + { if (s->context && s->type) + printf(":%s:L:", s->context->name); + else + printf("G:"); + } + printf("%s", s->name); /* array indices ignored */ + + if (s->type == STRUCT && n && n->rgt && n->rgt->lft) + { printf(":"); + AST_var(n->rgt->lft, n->rgt->lft->sym, 0); + } +} + +static void +name_def_indices(Lextok *n, int code) +{ + if (!n || !n->sym) return; + + if (n->sym->nel != 1) + def_use(n->lft, code); /* process the index */ + + if (n->sym->type == STRUCT /* and possible deeper ones */ + && n->rgt) + name_def_indices(n->rgt->lft, code); +} + +static void +name_def_use(Lextok *n, int code) +{ FSM_use *u; + + if (!n) return; + + if ((code&USE) + && cur_t->step + && cur_t->step->n) + { switch (cur_t->step->n->ntyp) { + case 'c': /* possible predicate abstraction? */ + n->sym->colnr |= 2; /* yes */ + break; + default: + n->sym->colnr |= 1; /* no */ + break; + } + } + + for (u = cur_t->Val[0]; u; u = u->nxt) + if (AST_mutual(n, u->n, 1) + && u->special == code) + return; + + if (use_free) + { u = use_free; + use_free = use_free->nxt; + } else + u = (FSM_use *) emalloc(sizeof(FSM_use)); + + u->n = n; + u->special = code; + u->nxt = cur_t->Val[0]; + cur_t->Val[0] = u; + + name_def_indices(n, USE|(code&(~DEF))); /* not def, but perhaps deref */ +} + +static void +def_use(Lextok *now, int code) +{ Lextok *v; + + if (now) + switch (now->ntyp) { + case '!': + case UMIN: + case '~': + case 'c': + case ENABLED: + case ASSERT: + case EVAL: + def_use(now->lft, USE|code); + break; + + case LEN: + case FULL: + case EMPTY: + case NFULL: + case NEMPTY: + def_use(now->lft, DEREF_USE|USE|code); + break; + + case '/': + case '*': + case '-': + case '+': + case '%': + case '&': + case '^': + case '|': + case LE: + case GE: + case GT: + case LT: + case NE: + case EQ: + case OR: + case AND: + case LSHIFT: + case RSHIFT: + def_use(now->lft, USE|code); + def_use(now->rgt, USE|code); + break; + + case ASGN: + def_use(now->lft, DEF|code); + def_use(now->rgt, USE|code); + break; + + case TYPE: /* name in parameter list */ + name_def_use(now, code); + break; + + case NAME: + name_def_use(now, code); + break; + + case RUN: + name_def_use(now, USE); /* procname - not really needed */ + for (v = now->lft; v; v = v->rgt) + def_use(v->lft, USE); /* params */ + break; + + case 's': + def_use(now->lft, DEREF_DEF|DEREF_USE|USE|code); + for (v = now->rgt; v; v = v->rgt) + def_use(v->lft, USE|code); + break; + + case 'r': + def_use(now->lft, DEREF_DEF|DEREF_USE|USE|code); + for (v = now->rgt; v; v = v->rgt) + { if (v->lft->ntyp == EVAL) + def_use(v->lft, code); /* will add USE */ + else if (v->lft->ntyp != CONST) + def_use(v->lft, DEF|code); + } + break; + + case 'R': + def_use(now->lft, DEREF_USE|USE|code); + for (v = now->rgt; v; v = v->rgt) + { if (v->lft->ntyp == EVAL) + def_use(v->lft, code); /* will add USE */ + } + break; + + case '?': + def_use(now->lft, USE|code); + if (now->rgt) + { def_use(now->rgt->lft, code); + def_use(now->rgt->rgt, code); + } + break; + + case PRINT: + for (v = now->lft; v; v = v->rgt) + def_use(v->lft, USE|code); + break; + + case PRINTM: + def_use(now->lft, USE); + break; + + case CONST: + case ELSE: /* ? */ + case NONPROGRESS: + case PC_VAL: + case 'p': + case 'q': + break; + + case '.': + case GOTO: + case BREAK: + case '@': + case D_STEP: + case ATOMIC: + case NON_ATOMIC: + case IF: + case DO: + case UNLESS: + case TIMEOUT: + case C_CODE: + case C_EXPR: + default: + break; + } +} + +static int +AST_add_alias(Lextok *n, int nr) +{ ALIAS *ca; + int res; + + for (ca = chalcur->alias; ca; ca = ca->nxt) + if (AST_mutual(ca->cnm, n, 1)) + { res = (ca->origin&nr); + ca->origin |= nr; /* 1, 2, or 4 - run, asgn, or rcv */ + return (res == 0); /* 0 if already there with same origin */ + } + + ca = (ALIAS *) emalloc(sizeof(ALIAS)); + ca->cnm = n; + ca->origin = nr; + ca->nxt = chalcur->alias; + chalcur->alias = ca; + return 1; +} + +static void +AST_run_alias(char *pn, char *s, Lextok *t, int parno) +{ Lextok *v; + int cnt; + + if (!t) return; + + if (t->ntyp == RUN) + { if (strcmp(t->sym->name, s) == 0) + for (v = t->lft, cnt = 1; v; v = v->rgt, cnt++) + if (cnt == parno) + { AST_add_alias(v->lft, 1); /* RUN */ + break; + } + } else + { AST_run_alias(pn, s, t->lft, parno); + AST_run_alias(pn, s, t->rgt, parno); + } +} + +static void +AST_findrun(char *s, int parno) +{ FSM_state *f; + FSM_trans *t; + AST *a; + + for (a = ast; a; a = a->nxt) /* automata */ + for (f = a->fsm; f; f = f->nxt) /* control states */ + for (t = f->t; t; t = t->nxt) /* transitions */ + { if (t->step) + AST_run_alias(a->p->n->name, s, t->step->n, parno); + } +} + +static void +AST_par_chans(ProcList *p) /* find local chan's init'd to chan passed as param */ +{ Ordered *walk; + Symbol *sp; + + for (walk = all_names; walk; walk = walk->next) + { sp = walk->entry; + if (sp + && sp->context + && strcmp(sp->context->name, p->n->name) == 0 + && sp->Nid >= 0 /* not itself a param */ + && sp->type == CHAN + && sp->ini->ntyp == NAME) /* != CONST and != CHAN */ + { Lextok *x = nn(ZN, 0, ZN, ZN); + x->sym = sp; + AST_setcur(x); + AST_add_alias(sp->ini, 2); /* ASGN */ + } } +} + +static void +AST_para(ProcList *p) +{ Lextok *f, *t, *c; + int cnt = 0; + + AST_par_chans(p); + + for (f = p->p; f; f = f->rgt) /* list of types */ + for (t = f->lft; t; t = t->rgt) + { if (t->ntyp != ',') + c = t; + else + c = t->lft; /* expanded struct */ + + cnt++; + if (Sym_typ(c) == CHAN) + { ALIAS *na = (ALIAS *) emalloc(sizeof(ALIAS)); + + na->cnm = c; + na->nxt = chalias; + chalcur = chalias = na; +#if 0 + printf("%s -- (par) -- ", p->n->name); + AST_var(c, c->sym, 1); + printf(" => <<"); +#endif + AST_findrun(p->n->name, cnt); +#if 0 + printf(">>\n"); +#endif + } + } +} + +static void +AST_haschan(Lextok *c) +{ + if (!c) return; + if (Sym_typ(c) == CHAN) + { AST_add_alias(c, 2); /* ASGN */ +#if 0 + printf("<<"); + AST_var(c, c->sym, 1); + printf(">>\n"); +#endif + } else + { AST_haschan(c->rgt); + AST_haschan(c->lft); + } +} + +static int +AST_nrpar(Lextok *n) /* 's' or 'r' */ +{ Lextok *m; + int j = 0; + + for (m = n->rgt; m; m = m->rgt) + j++; + return j; +} + +static int +AST_ord(Lextok *n, Lextok *s) +{ Lextok *m; + int j = 0; + + for (m = n->rgt; m; m = m->rgt) + { j++; + if (s->sym == m->lft->sym) + return j; + } + return 0; +} + +#if 0 +static void +AST_ownership(Symbol *s) +{ + if (!s) return; + printf("%s:", s->name); + AST_ownership(s->owner); +} +#endif + +static int +AST_mutual(Lextok *a, Lextok *b, int toplevel) +{ Symbol *as, *bs; + + if (!a && !b) return 1; + + if (!a || !b) return 0; + + as = a->sym; + bs = b->sym; + + if (!as || !bs) return 0; + + if (toplevel && as->context != bs->context) + return 0; + + if (as->type != bs->type) + return 0; + + if (strcmp(as->name, bs->name) != 0) + return 0; + + if (as->type == STRUCT + && a && a->rgt && b && b->rgt) + return AST_mutual(a->rgt->lft, b->rgt->lft, 0); + + return 1; +} + +static void +AST_setcur(Lextok *n) /* set chalcur */ +{ ALIAS *ca; + + for (ca = chalias; ca; ca = ca->nxt) + if (AST_mutual(ca->cnm, n, 1)) /* if same chan */ + { chalcur = ca; + return; + } + + ca = (ALIAS *) emalloc(sizeof(ALIAS)); + ca->cnm = n; + ca->nxt = chalias; + chalcur = chalias = ca; +} + +static void +AST_other(AST *a) /* check chan params in asgns and recvs */ +{ FSM_state *f; + FSM_trans *t; + FSM_use *u; + ChanList *cl; + + for (f = a->fsm; f; f = f->nxt) /* control states */ + for (t = f->t; t; t = t->nxt) /* transitions */ + for (u = t->Val[0]; u; u = u->nxt) /* def/use info */ + if (Sym_typ(u->n) == CHAN + && (u->special&DEF)) /* def of chan-name */ + { AST_setcur(u->n); + switch (t->step->n->ntyp) { + case ASGN: + AST_haschan(t->step->n->rgt); + break; + case 'r': + /* guess sends where name may originate */ + for (cl = chanlist; cl; cl = cl->nxt) /* all sends */ + { int a = AST_nrpar(cl->s); + int b = AST_nrpar(t->step->n); + if (a != b) /* matching nrs of params */ + continue; + + a = AST_ord(cl->s, cl->n); + b = AST_ord(t->step->n, u->n); + if (a != b) /* same position in parlist */ + continue; + + AST_add_alias(cl->n, 4); /* RCV assume possible match */ + } + break; + default: + printf("type = %d\n", t->step->n->ntyp); + non_fatal("unexpected chan def type", (char *) 0); + break; + } } +} + +static void +AST_aliases(void) +{ ALIAS *na, *ca; + + for (na = chalias; na; na = na->nxt) + { printf("\npossible aliases of "); + AST_var(na->cnm, na->cnm->sym, 1); + printf("\n\t"); + for (ca = na->alias; ca; ca = ca->nxt) + { if (!ca->cnm->sym) + printf("no valid name "); + else + AST_var(ca->cnm, ca->cnm->sym, 1); + printf("<"); + if (ca->origin & 1) printf("RUN "); + if (ca->origin & 2) printf("ASGN "); + if (ca->origin & 4) printf("RCV "); + printf("[%s]", AST_isini(ca->cnm)?"Initzd":"Name"); + printf(">"); + if (ca->nxt) printf(", "); + } + printf("\n"); + } + printf("\n"); +} + +static void +AST_indirect(FSM_use *uin, FSM_trans *t, char *cause, char *pn) +{ FSM_use *u; + + /* this is a newly discovered relevant statement */ + /* all vars it uses to contribute to its DEF are new criteria */ + + if (!(t->relevant&1)) AST_Changes++; + + t->round = AST_Round; + t->relevant = 1; + + if ((verbose&32) && t->step) + { printf("\tDR %s [[ ", pn); + comment(stdout, t->step->n, 0); + printf("]]\n\t\tfully relevant %s", cause); + if (uin) { printf(" due to "); AST_var(uin->n, uin->n->sym, 1); } + printf("\n"); + } + for (u = t->Val[0]; u; u = u->nxt) + if (u != uin + && (u->special&(USE|DEREF_USE))) + { if (verbose&32) + { printf("\t\t\tuses(%d): ", u->special); + AST_var(u->n, u->n->sym, 1); + printf("\n"); + } + name_AST_track(u->n, u->special); /* add to slice criteria */ + } +} + +static void +def_relevant(char *pn, FSM_trans *t, Lextok *n, int ischan) +{ FSM_use *u; + ALIAS *na, *ca; + int chanref; + + /* look for all DEF's of n + * mark those stmnts relevant + * mark all var USEs in those stmnts as criteria + */ + + if (n->ntyp != ELSE) + for (u = t->Val[0]; u; u = u->nxt) + { chanref = (Sym_typ(u->n) == CHAN); + + if (ischan != chanref /* no possible match */ + || !(u->special&(DEF|DEREF_DEF))) /* not a def */ + continue; + + if (AST_mutual(u->n, n, 1)) + { AST_indirect(u, t, "(exact match)", pn); + continue; + } + + if (chanref) + for (na = chalias; na; na = na->nxt) + { if (!AST_mutual(u->n, na->cnm, 1)) + continue; + for (ca = na->alias; ca; ca = ca->nxt) + if (AST_mutual(ca->cnm, n, 1) + && AST_isini(ca->cnm)) + { AST_indirect(u, t, "(alias match)", pn); + break; + } + if (ca) break; + } } +} + +static void +AST_relevant(Lextok *n) +{ AST *a; + FSM_state *f; + FSM_trans *t; + int ischan; + + /* look for all DEF's of n + * mark those stmnts relevant + * mark all var USEs in those stmnts as criteria + */ + + if (!n) return; + ischan = (Sym_typ(n) == CHAN); + + if (verbose&32) + { printf("<ntyp); + AST_var(n, n->sym, 1); + printf(">>\n"); + } + + for (t = expl_par; t; t = t->nxt) /* param assignments */ + { if (!(t->relevant&1)) + def_relevant(":params:", t, n, ischan); + } + + for (t = expl_var; t; t = t->nxt) + { if (!(t->relevant&1)) /* var inits */ + def_relevant(":vars:", t, n, ischan); + } + + for (a = ast; a; a = a->nxt) /* all other stmnts */ + { if (strcmp(a->p->n->name, ":never:") != 0 + && strcmp(a->p->n->name, ":trace:") != 0 + && strcmp(a->p->n->name, ":notrace:") != 0) + for (f = a->fsm; f; f = f->nxt) + for (t = f->t; t; t = t->nxt) + { if (!(t->relevant&1)) + def_relevant(a->p->n->name, t, n, ischan); + } } +} + +static int +AST_relpar(char *s) +{ FSM_trans *t, *T; + FSM_use *u; + + for (T = expl_par; T; T = (T == expl_par)?expl_var: (FSM_trans *) 0) + for (t = T; t; t = t->nxt) + { if (t->relevant&1) + for (u = t->Val[0]; u; u = u->nxt) + { if (u->n->sym->type + && u->n->sym->context + && strcmp(u->n->sym->context->name, s) == 0) + { + if (verbose&32) + { printf("proctype %s relevant, due to symbol ", s); + AST_var(u->n, u->n->sym, 1); + printf("\n"); + } + return 1; + } } } + return 0; +} + +static void +AST_dorelevant(void) +{ AST *a; + RPN *r; + + for (r = rpn; r; r = r->nxt) + { for (a = ast; a; a = a->nxt) + if (strcmp(a->p->n->name, r->rn->name) == 0) + { a->relevant |= 1; + break; + } + if (!a) + fatal("cannot find proctype %s", r->rn->name); + } +} + +static void +AST_procisrelevant(Symbol *s) +{ RPN *r; + for (r = rpn; r; r = r->nxt) + if (strcmp(r->rn->name, s->name) == 0) + return; + r = (RPN *) emalloc(sizeof(RPN)); + r->rn = s; + r->nxt = rpn; + rpn = r; +} + +static int +AST_proc_isrel(char *s) +{ AST *a; + + for (a = ast; a; a = a->nxt) + if (strcmp(a->p->n->name, s) == 0) + return (a->relevant&1); + non_fatal("cannot happen, missing proc in ast", (char *) 0); + return 0; +} + +static int +AST_scoutrun(Lextok *t) +{ + if (!t) return 0; + + if (t->ntyp == RUN) + return AST_proc_isrel(t->sym->name); + return (AST_scoutrun(t->lft) || AST_scoutrun(t->rgt)); +} + +static void +AST_tagruns(void) +{ AST *a; + FSM_state *f; + FSM_trans *t; + + /* if any stmnt inside a proctype is relevant + * or any parameter passed in a run + * then so are all the run statements on that proctype + */ + + for (a = ast; a; a = a->nxt) + { if (strcmp(a->p->n->name, ":never:") == 0 + || strcmp(a->p->n->name, ":trace:") == 0 + || strcmp(a->p->n->name, ":notrace:") == 0 + || strcmp(a->p->n->name, ":init:") == 0) + { a->relevant |= 1; /* the proctype is relevant */ + continue; + } + if (AST_relpar(a->p->n->name)) + a->relevant |= 1; + else + { for (f = a->fsm; f; f = f->nxt) + for (t = f->t; t; t = t->nxt) + if (t->relevant) + goto yes; +yes: if (f) + a->relevant |= 1; + } + } + + for (a = ast; a; a = a->nxt) + for (f = a->fsm; f; f = f->nxt) + for (t = f->t; t; t = t->nxt) + if (t->step + && AST_scoutrun(t->step->n)) + { AST_indirect((FSM_use *)0, t, ":run:", a->p->n->name); + /* BUT, not all actual params are relevant */ + } +} + +static void +AST_report(AST *a, Element *e) /* ALSO deduce irrelevant vars */ +{ + if (!(a->relevant&2)) + { a->relevant |= 2; + printf("spin: redundant in proctype %s (for given property):\n", + a->p->n->name); + } + printf(" line %3d %s (state %d)", + e->n?e->n->ln:-1, + e->n?e->n->fn->name:"-", + e->seqno); + printf(" ["); + comment(stdout, e->n, 0); + printf("]\n"); +} + +static int +AST_always(Lextok *n) +{ + if (!n) return 0; + + if (n->ntyp == '@' /* -end */ + || n->ntyp == 'p') /* remote reference */ + return 1; + return AST_always(n->lft) || AST_always(n->rgt); +} + +static void +AST_edge_dump(AST *a, FSM_state *f) +{ FSM_trans *t; + FSM_use *u; + + for (t = f->t; t; t = t->nxt) /* edges */ + { + if (t->step && AST_always(t->step->n)) + t->relevant |= 1; /* always relevant */ + + if (verbose&32) + { switch (t->relevant) { + case 0: printf(" "); break; + case 1: printf("*%3d ", t->round); break; + case 2: printf("+%3d ", t->round); break; + case 3: printf("#%3d ", t->round); break; + default: printf("? "); break; + } + + printf("%d\t->\t%d\t", f->from, t->to); + if (t->step) + comment(stdout, t->step->n, 0); + else + printf("Unless"); + + for (u = t->Val[0]; u; u = u->nxt) + { printf(" <"); + AST_var(u->n, u->n->sym, 1); + printf(":%d>", u->special); + } + printf("\n"); + } else + { if (t->relevant) + continue; + + if (t->step) + switch(t->step->n->ntyp) { + case ASGN: + case 's': + case 'r': + case 'c': + if (t->step->n->lft->ntyp != CONST) + AST_report(a, t->step); + break; + + case PRINT: /* don't report */ + case PRINTM: + case ASSERT: + case C_CODE: + case C_EXPR: + default: + break; + } } } +} + +static void +AST_dfs(AST *a, int s, int vis) +{ FSM_state *f; + FSM_trans *t; + + f = fsm_tbl[s]; + if (f->seen) return; + + f->seen = 1; + if (vis) AST_edge_dump(a, f); + + for (t = f->t; t; t = t->nxt) + AST_dfs(a, t->to, vis); +} + +static void +AST_dump(AST *a) +{ FSM_state *f; + + for (f = a->fsm; f; f = f->nxt) + { f->seen = 0; + fsm_tbl[f->from] = f; + } + + if (verbose&32) + printf("AST_START %s from %d\n", a->p->n->name, a->i_st); + + AST_dfs(a, a->i_st, 1); +} + +static void +AST_sends(AST *a) +{ FSM_state *f; + FSM_trans *t; + FSM_use *u; + ChanList *cl; + + for (f = a->fsm; f; f = f->nxt) /* control states */ + for (t = f->t; t; t = t->nxt) /* transitions */ + { if (t->step + && t->step->n + && t->step->n->ntyp == 's') + for (u = t->Val[0]; u; u = u->nxt) + { if (Sym_typ(u->n) == CHAN + && ((u->special&USE) && !(u->special&DEREF_USE))) + { +#if 0 + printf("%s -- (%d->%d) -- ", + a->p->n->name, f->from, t->to); + AST_var(u->n, u->n->sym, 1); + printf(" -> chanlist\n"); +#endif + cl = (ChanList *) emalloc(sizeof(ChanList)); + cl->s = t->step->n; + cl->n = u->n; + cl->nxt = chanlist; + chanlist = cl; +} } } } + +static ALIAS * +AST_alfind(Lextok *n) +{ ALIAS *na; + + for (na = chalias; na; na = na->nxt) + if (AST_mutual(na->cnm, n, 1)) + return na; + return (ALIAS *) 0; +} + +static void +AST_trans(void) +{ ALIAS *na, *ca, *da, *ea; + int nchanges; + + do { + nchanges = 0; + for (na = chalias; na; na = na->nxt) + { chalcur = na; + for (ca = na->alias; ca; ca = ca->nxt) + { da = AST_alfind(ca->cnm); + if (da) + for (ea = da->alias; ea; ea = ea->nxt) + { nchanges += AST_add_alias(ea->cnm, + ea->origin|ca->origin); + } } } + } while (nchanges > 0); + + chalcur = (ALIAS *) 0; +} + +static void +AST_def_use(AST *a) +{ FSM_state *f; + FSM_trans *t; + + for (f = a->fsm; f; f = f->nxt) /* control states */ + for (t = f->t; t; t = t->nxt) /* all edges */ + { cur_t = t; + rel_use(t->Val[0]); /* redo Val; doesn't cover structs */ + rel_use(t->Val[1]); + t->Val[0] = t->Val[1] = (FSM_use *) 0; + + if (!t->step) continue; + + def_use(t->step->n, 0); /* def/use info, including structs */ + } + cur_t = (FSM_trans *) 0; +} + +static void +name_AST_track(Lextok *n, int code) +{ extern int nr_errs; +#if 0 + printf("AST_name: "); + AST_var(n, n->sym, 1); + printf(" -- %d\n", code); +#endif + if (in_recv && (code&DEF) && (code&USE)) + { printf("spin: error: DEF and USE of same var in rcv stmnt: "); + AST_var(n, n->sym, 1); + printf(" -- %d\n", code); + nr_errs++; + } + check_slice(n, code); +} + +void +AST_track(Lextok *now, int code) /* called from main.c */ +{ Lextok *v; extern int export_ast; + + if (!export_ast) return; + + if (now) + switch (now->ntyp) { + case LEN: + case FULL: + case EMPTY: + case NFULL: + case NEMPTY: + AST_track(now->lft, DEREF_USE|USE|code); + break; + + case '/': + case '*': + case '-': + case '+': + case '%': + case '&': + case '^': + case '|': + case LE: + case GE: + case GT: + case LT: + case NE: + case EQ: + case OR: + case AND: + case LSHIFT: + case RSHIFT: + AST_track(now->rgt, USE|code); + /* fall through */ + case '!': + case UMIN: + case '~': + case 'c': + case ENABLED: + case ASSERT: + AST_track(now->lft, USE|code); + break; + + case EVAL: + AST_track(now->lft, USE|(code&(~DEF))); + break; + + case NAME: + name_AST_track(now, code); + if (now->sym->nel != 1) + AST_track(now->lft, USE|code); /* index */ + break; + + case 'R': + AST_track(now->lft, DEREF_USE|USE|code); + for (v = now->rgt; v; v = v->rgt) + AST_track(v->lft, code); /* a deeper eval can add USE */ + break; + + case '?': + AST_track(now->lft, USE|code); + if (now->rgt) + { AST_track(now->rgt->lft, code); + AST_track(now->rgt->rgt, code); + } + break; + +/* added for control deps: */ + case TYPE: + name_AST_track(now, code); + break; + case ASGN: + AST_track(now->lft, DEF|code); + AST_track(now->rgt, USE|code); + break; + case RUN: + name_AST_track(now, USE); + for (v = now->lft; v; v = v->rgt) + AST_track(v->lft, USE|code); + break; + case 's': + AST_track(now->lft, DEREF_DEF|DEREF_USE|USE|code); + for (v = now->rgt; v; v = v->rgt) + AST_track(v->lft, USE|code); + break; + case 'r': + AST_track(now->lft, DEREF_DEF|DEREF_USE|USE|code); + for (v = now->rgt; v; v = v->rgt) + { in_recv++; + AST_track(v->lft, DEF|code); + in_recv--; + } + break; + case PRINT: + for (v = now->lft; v; v = v->rgt) + AST_track(v->lft, USE|code); + break; + case PRINTM: + AST_track(now->lft, USE); + break; +/* end add */ + case 'p': +#if 0 + 'p' -sym-> _p + / + '?' -sym-> a (proctype) + / + b (pid expr) +#endif + AST_track(now->lft->lft, USE|code); + AST_procisrelevant(now->lft->sym); + break; + + case CONST: + case ELSE: + case NONPROGRESS: + case PC_VAL: + case 'q': + break; + + case '.': + case GOTO: + case BREAK: + case '@': + case D_STEP: + case ATOMIC: + case NON_ATOMIC: + case IF: + case DO: + case UNLESS: + case TIMEOUT: + case C_CODE: + case C_EXPR: + break; + + default: + printf("AST_track, NOT EXPECTED ntyp: %d\n", now->ntyp); + break; + } +} + +static int +AST_dump_rel(void) +{ Slicer *rv; + Ordered *walk; + char buf[64]; + int banner=0; + + if (verbose&32) + { printf("Relevant variables:\n"); + for (rv = rel_vars; rv; rv = rv->nxt) + { printf("\t"); + AST_var(rv->n, rv->n->sym, 1); + printf("\n"); + } + return 1; + } + for (rv = rel_vars; rv; rv = rv->nxt) + rv->n->sym->setat = 1; /* mark it */ + + for (walk = all_names; walk; walk = walk->next) + { Symbol *s; + s = walk->entry; + if (!s->setat + && (s->type != MTYPE || s->ini->ntyp != CONST) + && s->type != STRUCT /* report only fields */ + && s->type != PROCTYPE + && !s->owner + && sputtype(buf, s->type)) + { if (!banner) + { banner = 1; + printf("spin: redundant vars (for given property):\n"); + } + printf("\t"); + symvar(s); + } } + return banner; +} + +static void +AST_suggestions(void) +{ Symbol *s; + Ordered *walk; + FSM_state *f; + FSM_trans *t; + AST *a; + int banner=0; + int talked=0; + + for (walk = all_names; walk; walk = walk->next) + { s = walk->entry; + if (s->colnr == 2 /* only used in conditionals */ + && (s->type == BYTE + || s->type == SHORT + || s->type == INT + || s->type == MTYPE)) + { if (!banner) + { banner = 1; + printf("spin: consider using predicate"); + printf(" abstraction to replace:\n"); + } + printf("\t"); + symvar(s); + } } + + /* look for source and sink processes */ + + for (a = ast; a; a = a->nxt) /* automata */ + { banner = 0; + for (f = a->fsm; f; f = f->nxt) /* control states */ + for (t = f->t; t; t = t->nxt) /* transitions */ + { if (t->step) + switch (t->step->n->ntyp) { + case 's': + banner |= 1; + break; + case 'r': + banner |= 2; + break; + case '.': + case D_STEP: + case ATOMIC: + case NON_ATOMIC: + case IF: + case DO: + case UNLESS: + case '@': + case GOTO: + case BREAK: + case PRINT: + case PRINTM: + case ASSERT: + case C_CODE: + case C_EXPR: + break; + default: + banner |= 4; + goto no_good; + } + } +no_good: if (banner == 1 || banner == 2) + { printf("spin: proctype %s defines a %s process\n", + a->p->n->name, + banner==1?"source":"sink"); + talked |= banner; + } else if (banner == 3) + { printf("spin: proctype %s mimics a buffer\n", + a->p->n->name); + talked |= 4; + } + } + if (talked&1) + { printf("\tto reduce complexity, consider merging the code of\n"); + printf("\teach source process into the code of its target\n"); + } + if (talked&2) + { printf("\tto reduce complexity, consider merging the code of\n"); + printf("\teach sink process into the code of its source\n"); + } + if (talked&4) + printf("\tto reduce complexity, avoid buffer processes\n"); +} + +static void +AST_preserve(void) +{ Slicer *sc, *nx, *rv; + + for (sc = slicer; sc; sc = nx) + { if (!sc->used) + break; /* done */ + + nx = sc->nxt; + + for (rv = rel_vars; rv; rv = rv->nxt) + if (AST_mutual(sc->n, rv->n, 1)) + break; + + if (!rv) /* not already there */ + { sc->nxt = rel_vars; + rel_vars = sc; + } } + slicer = sc; +} + +static void +check_slice(Lextok *n, int code) +{ Slicer *sc; + + for (sc = slicer; sc; sc = sc->nxt) + if (AST_mutual(sc->n, n, 1) + && sc->code == code) + return; /* already there */ + + sc = (Slicer *) emalloc(sizeof(Slicer)); + sc->n = n; + + sc->code = code; + sc->used = 0; + sc->nxt = slicer; + slicer = sc; +} + +static void +AST_data_dep(void) +{ Slicer *sc; + + /* mark all def-relevant transitions */ + for (sc = slicer; sc; sc = sc->nxt) + { sc->used = 1; + if (verbose&32) + { printf("spin: slice criterion "); + AST_var(sc->n, sc->n->sym, 1); + printf(" type=%d\n", Sym_typ(sc->n)); + } + AST_relevant(sc->n); + } + AST_tagruns(); /* mark 'run's relevant if target proctype is relevant */ +} + +static int +AST_blockable(AST *a, int s) +{ FSM_state *f; + FSM_trans *t; + + f = fsm_tbl[s]; + + for (t = f->t; t; t = t->nxt) + { if (t->relevant&2) + return 1; + + if (t->step && t->step->n) + switch (t->step->n->ntyp) { + case IF: + case DO: + case ATOMIC: + case NON_ATOMIC: + case D_STEP: + if (AST_blockable(a, t->to)) + { t->round = AST_Round; + t->relevant |= 2; + return 1; + } + /* else fall through */ + default: + break; + } + else if (AST_blockable(a, t->to)) /* Unless */ + { t->round = AST_Round; + t->relevant |= 2; + return 1; + } + } + return 0; +} + +static void +AST_spread(AST *a, int s) +{ FSM_state *f; + FSM_trans *t; + + f = fsm_tbl[s]; + + for (t = f->t; t; t = t->nxt) + { if (t->relevant&2) + continue; + + if (t->step && t->step->n) + switch (t->step->n->ntyp) { + case IF: + case DO: + case ATOMIC: + case NON_ATOMIC: + case D_STEP: + AST_spread(a, t->to); + /* fall thru */ + default: + t->round = AST_Round; + t->relevant |= 2; + break; + } + else /* Unless */ + { AST_spread(a, t->to); + t->round = AST_Round; + t->relevant |= 2; + } + } +} + +static int +AST_notrelevant(Lextok *n) +{ Slicer *s; + + for (s = rel_vars; s; s = s->nxt) + if (AST_mutual(s->n, n, 1)) + return 0; + for (s = slicer; s; s = s->nxt) + if (AST_mutual(s->n, n, 1)) + return 0; + return 1; +} + +static int +AST_withchan(Lextok *n) +{ + if (!n) return 0; + if (Sym_typ(n) == CHAN) + return 1; + return AST_withchan(n->lft) || AST_withchan(n->rgt); +} + +static int +AST_suspect(FSM_trans *t) +{ FSM_use *u; + /* check for possible overkill */ + if (!t || !t->step || !AST_withchan(t->step->n)) + return 0; + for (u = t->Val[0]; u; u = u->nxt) + if (AST_notrelevant(u->n)) + return 1; + return 0; +} + +static void +AST_shouldconsider(AST *a, int s) +{ FSM_state *f; + FSM_trans *t; + + f = fsm_tbl[s]; + for (t = f->t; t; t = t->nxt) + { if (t->step && t->step->n) + switch (t->step->n->ntyp) { + case IF: + case DO: + case ATOMIC: + case NON_ATOMIC: + case D_STEP: + AST_shouldconsider(a, t->to); + break; + default: + AST_track(t->step->n, 0); +/* + AST_track is called here for a blockable stmnt from which + a relevant stmnmt was shown to be reachable + for a condition this makes all USEs relevant + but for a channel operation it only makes the executability + relevant -- in those cases, parameters that aren't already + relevant may be replaceable with arbitrary tokens + */ + if (AST_suspect(t)) + { printf("spin: possibly redundant parameters in: "); + comment(stdout, t->step->n, 0); + printf("\n"); + } + break; + } + else /* an Unless */ + AST_shouldconsider(a, t->to); + } +} + +static int +FSM_critical(AST *a, int s) +{ FSM_state *f; + FSM_trans *t; + + /* is a 1-relevant stmnt reachable from this state? */ + + f = fsm_tbl[s]; + if (f->seen) + goto done; + f->seen = 1; + f->cr = 0; + for (t = f->t; t; t = t->nxt) + if ((t->relevant&1) + || FSM_critical(a, t->to)) + { f->cr = 1; + + if (verbose&32) + { printf("\t\t\t\tcritical(%d) ", t->relevant); + comment(stdout, t->step->n, 0); + printf("\n"); + } + break; + } +#if 0 + else { + if (verbose&32) + { printf("\t\t\t\tnot-crit "); + comment(stdout, t->step->n, 0); + printf("\n"); + } + } +#endif +done: + return f->cr; +} + +static void +AST_ctrl(AST *a) +{ FSM_state *f; + FSM_trans *t; + int hit; + + /* add all blockable transitions + * from which relevant transitions can be reached + */ + if (verbose&32) + printf("CTL -- %s\n", a->p->n->name); + + /* 1 : mark all blockable edges */ + for (f = a->fsm; f; f = f->nxt) + { if (!(f->scratch&2)) /* not part of irrelevant subgraph */ + for (t = f->t; t; t = t->nxt) + { if (t->step && t->step->n) + switch (t->step->n->ntyp) { + case 'r': + case 's': + case 'c': + case ELSE: + t->round = AST_Round; + t->relevant |= 2; /* mark for next phases */ + if (verbose&32) + { printf("\tpremark "); + comment(stdout, t->step->n, 0); + printf("\n"); + } + break; + default: + break; + } } } + + /* 2: keep only 2-marked stmnts from which 1-marked stmnts can be reached */ + for (f = a->fsm; f; f = f->nxt) + { fsm_tbl[f->from] = f; + f->seen = 0; /* used in dfs from FSM_critical */ + } + for (f = a->fsm; f; f = f->nxt) + { if (!FSM_critical(a, f->from)) + for (t = f->t; t; t = t->nxt) + if (t->relevant&2) + { t->relevant &= ~2; /* clear mark */ + if (verbose&32) + { printf("\t\tnomark "); + comment(stdout, t->step->n, 0); + printf("\n"); + } } } + + /* 3 : lift marks across IF/DO etc. */ + for (f = a->fsm; f; f = f->nxt) + { hit = 0; + for (t = f->t; t; t = t->nxt) + { if (t->step && t->step->n) + switch (t->step->n->ntyp) { + case IF: + case DO: + case ATOMIC: + case NON_ATOMIC: + case D_STEP: + if (AST_blockable(a, t->to)) + hit = 1; + break; + default: + break; + } + else if (AST_blockable(a, t->to)) /* Unless */ + hit = 1; + + if (hit) break; + } + if (hit) /* at least one outgoing trans can block */ + for (t = f->t; t; t = t->nxt) + { t->round = AST_Round; + t->relevant |= 2; /* lift */ + if (verbose&32) + { printf("\t\t\tliftmark "); + comment(stdout, t->step->n, 0); + printf("\n"); + } + AST_spread(a, t->to); /* and spread to all guards */ + } } + + /* 4: nodes with 2-marked out-edges contribute new slice criteria */ + for (f = a->fsm; f; f = f->nxt) + for (t = f->t; t; t = t->nxt) + if (t->relevant&2) + { AST_shouldconsider(a, f->from); + break; /* inner loop */ + } +} + +static void +AST_control_dep(void) +{ AST *a; + + for (a = ast; a; a = a->nxt) + if (strcmp(a->p->n->name, ":never:") != 0 + && strcmp(a->p->n->name, ":trace:") != 0 + && strcmp(a->p->n->name, ":notrace:") != 0) + AST_ctrl(a); +} + +static void +AST_prelabel(void) +{ AST *a; + FSM_state *f; + FSM_trans *t; + + for (a = ast; a; a = a->nxt) + { if (strcmp(a->p->n->name, ":never:") != 0 + && strcmp(a->p->n->name, ":trace:") != 0 + && strcmp(a->p->n->name, ":notrace:") != 0) + for (f = a->fsm; f; f = f->nxt) + for (t = f->t; t; t = t->nxt) + { if (t->step + && t->step->n + && t->step->n->ntyp == ASSERT + ) + { t->relevant |= 1; + } } } +} + +static void +AST_criteria(void) +{ /* + * remote labels are handled separately -- by making + * sure they are not pruned away during optimization + */ + AST_Changes = 1; /* to get started */ + for (AST_Round = 1; slicer && AST_Changes; AST_Round++) + { AST_Changes = 0; + AST_data_dep(); + AST_preserve(); /* moves processed vars from slicer to rel_vars */ + AST_dominant(); /* mark data-irrelevant subgraphs */ + AST_control_dep(); /* can add data deps, which add control deps */ + + if (verbose&32) + printf("\n\nROUND %d -- changes %d\n", + AST_Round, AST_Changes); + } +} + +static void +AST_alias_analysis(void) /* aliasing of promela channels */ +{ AST *a; + + for (a = ast; a; a = a->nxt) + AST_sends(a); /* collect chan-names that are send across chans */ + + for (a = ast; a; a = a->nxt) + AST_para(a->p); /* aliasing of chans thru proctype parameters */ + + for (a = ast; a; a = a->nxt) + AST_other(a); /* chan params in asgns and recvs */ + + AST_trans(); /* transitive closure of alias table */ + + if (verbose&32) + AST_aliases(); /* show channel aliasing info */ +} + +void +AST_slice(void) +{ AST *a; + int spurious = 0; + + if (!slicer) + { non_fatal("no slice criteria (or no claim) specified", + (char *) 0); + spurious = 1; + } + AST_dorelevant(); /* mark procs refered to in remote refs */ + + for (a = ast; a; a = a->nxt) + AST_def_use(a); /* compute standard def/use information */ + + AST_hidden(); /* parameter passing and local var inits */ + + AST_alias_analysis(); /* channel alias analysis */ + + AST_prelabel(); /* mark all 'assert(...)' stmnts as relevant */ + AST_criteria(); /* process the slice criteria from + * asserts and from the never claim + */ + if (!spurious || (verbose&32)) + { spurious = 1; + for (a = ast; a; a = a->nxt) + { AST_dump(a); /* marked up result */ + if (a->relevant&2) /* it printed something */ + spurious = 0; + } + if (!AST_dump_rel() /* relevant variables */ + && spurious) + printf("spin: no redundancies found (for given property)\n"); + } + AST_suggestions(); + + if (verbose&32) + show_expl(); +} + +void +AST_store(ProcList *p, int start_state) +{ AST *n_ast; + + if (strcmp(p->n->name, ":never:") != 0 + && strcmp(p->n->name, ":trace:") != 0 + && strcmp(p->n->name, ":notrace:") != 0) + { n_ast = (AST *) emalloc(sizeof(AST)); + n_ast->p = p; + n_ast->i_st = start_state; + n_ast->relevant = 0; + n_ast->fsm = fsm; + n_ast->nxt = ast; + ast = n_ast; + } + fsm = (FSM_state *) 0; /* hide it from FSM_DEL */ +} + +static void +AST_add_explicit(Lextok *d, Lextok *u) +{ FSM_trans *e = (FSM_trans *) emalloc(sizeof(FSM_trans)); + + e->to = 0; /* or start_state ? */ + e->relevant = 0; /* to be determined */ + e->step = (Element *) 0; /* left blank */ + e->Val[0] = e->Val[1] = (FSM_use *) 0; + + cur_t = e; + + def_use(u, USE); + def_use(d, DEF); + + cur_t = (FSM_trans *) 0; + + e->nxt = explicit; + explicit = e; +} + +static void +AST_fp1(char *s, Lextok *t, Lextok *f, int parno) +{ Lextok *v; + int cnt; + + if (!t) return; + + if (t->ntyp == RUN) + { if (strcmp(t->sym->name, s) == 0) + for (v = t->lft, cnt = 1; v; v = v->rgt, cnt++) + if (cnt == parno) + { AST_add_explicit(f, v->lft); + break; + } + } else + { AST_fp1(s, t->lft, f, parno); + AST_fp1(s, t->rgt, f, parno); + } +} + +static void +AST_mk1(char *s, Lextok *c, int parno) +{ AST *a; + FSM_state *f; + FSM_trans *t; + + /* concoct an extra FSM_trans *t with the asgn of + * formal par c to matching actual pars made explicit + */ + + for (a = ast; a; a = a->nxt) /* automata */ + for (f = a->fsm; f; f = f->nxt) /* control states */ + for (t = f->t; t; t = t->nxt) /* transitions */ + { if (t->step) + AST_fp1(s, t->step->n, c, parno); + } +} + +static void +AST_par_init(void) /* parameter passing -- hidden assignments */ +{ AST *a; + Lextok *f, *t, *c; + int cnt; + + for (a = ast; a; a = a->nxt) + { if (strcmp(a->p->n->name, ":never:") == 0 + || strcmp(a->p->n->name, ":trace:") == 0 + || strcmp(a->p->n->name, ":notrace:") == 0 + || strcmp(a->p->n->name, ":init:") == 0) + continue; /* have no params */ + + cnt = 0; + for (f = a->p->p; f; f = f->rgt) /* types */ + for (t = f->lft; t; t = t->rgt) /* formals */ + { cnt++; /* formal par count */ + c = (t->ntyp != ',')? t : t->lft; /* the formal parameter */ + AST_mk1(a->p->n->name, c, cnt); /* all matching run statements */ + } } +} + +static void +AST_var_init(void) /* initialized vars (not chans) - hidden assignments */ +{ Ordered *walk; + Lextok *x; + Symbol *sp; + AST *a; + + for (walk = all_names; walk; walk = walk->next) + { sp = walk->entry; + if (sp + && !sp->context /* globals */ + && sp->type != PROCTYPE + && sp->ini + && (sp->type != MTYPE || sp->ini->ntyp != CONST) /* not mtype defs */ + && sp->ini->ntyp != CHAN) + { x = nn(ZN, TYPE, ZN, ZN); + x->sym = sp; + AST_add_explicit(x, sp->ini); + } } + + for (a = ast; a; a = a->nxt) + { if (strcmp(a->p->n->name, ":never:") != 0 + && strcmp(a->p->n->name, ":trace:") != 0 + && strcmp(a->p->n->name, ":notrace:") != 0) /* claim has no locals */ + for (walk = all_names; walk; walk = walk->next) + { sp = walk->entry; + if (sp + && sp->context + && strcmp(sp->context->name, a->p->n->name) == 0 + && sp->Nid >= 0 /* not a param */ + && sp->type != LABEL + && sp->ini + && sp->ini->ntyp != CHAN) + { x = nn(ZN, TYPE, ZN, ZN); + x->sym = sp; + AST_add_explicit(x, sp->ini); + } } } +} + +static void +show_expl(void) +{ FSM_trans *t, *T; + FSM_use *u; + + printf("\nExplicit List:\n"); + for (T = expl_par; T; T = (T == expl_par)?expl_var: (FSM_trans *) 0) + { for (t = T; t; t = t->nxt) + { if (!t->Val[0]) continue; + printf("%s", t->relevant?"*":" "); + printf("%3d", t->round); + for (u = t->Val[0]; u; u = u->nxt) + { printf("\t<"); + AST_var(u->n, u->n->sym, 1); + printf(":%d>, ", u->special); + } + printf("\n"); + } + printf("==\n"); + } + printf("End\n"); +} + +static void +AST_hidden(void) /* reveal all hidden assignments */ +{ + AST_par_init(); + expl_par = explicit; + explicit = (FSM_trans *) 0; + + AST_var_init(); + expl_var = explicit; + explicit = (FSM_trans *) 0; +} + +#define BPW (8*sizeof(ulong)) /* bits per word */ + +static int +bad_scratch(FSM_state *f, int upto) +{ FSM_trans *t; +#if 0 + 1. all internal branch-points have else-s + 2. all non-branchpoints have non-blocking out-edge + 3. all internal edges are non-relevant + subgraphs like this need NOT contribute control-dependencies +#endif + + if (!f->seen + || (f->scratch&4)) + return 0; + + if (f->scratch&8) + return 1; + + f->scratch |= 4; + + if (verbose&32) printf("X[%d:%d:%d] ", f->from, upto, f->scratch); + + if (f->scratch&1) + { if (verbose&32) + printf("\tbad scratch: %d\n", f->from); +bad: f->scratch &= ~4; + /* f->scratch |= 8; wrong */ + return 1; + } + + if (f->from != upto) + for (t = f->t; t; t = t->nxt) + if (bad_scratch(fsm_tbl[t->to], upto)) + goto bad; + + return 0; +} + +static void +mark_subgraph(FSM_state *f, int upto) +{ FSM_trans *t; + + if (f->from == upto + || !f->seen + || (f->scratch&2)) + return; + + f->scratch |= 2; + + for (t = f->t; t; t = t->nxt) + mark_subgraph(fsm_tbl[t->to], upto); +} + +static void +AST_pair(AST *a, FSM_state *h, int y) +{ Pair *p; + + for (p = a->pairs; p; p = p->nxt) + if (p->h == h + && p->b == y) + return; + + p = (Pair *) emalloc(sizeof(Pair)); + p->h = h; + p->b = y; + p->nxt = a->pairs; + a->pairs = p; +} + +static void +AST_checkpairs(AST *a) +{ Pair *p; + + for (p = a->pairs; p; p = p->nxt) + { if (verbose&32) + printf(" inspect pair %d %d\n", p->b, p->h->from); + if (!bad_scratch(p->h, p->b)) /* subgraph is clean */ + { if (verbose&32) + printf("subgraph: %d .. %d\n", p->b, p->h->from); + mark_subgraph(p->h, p->b); + } + } +} + +static void +subgraph(AST *a, FSM_state *f, int out) +{ FSM_state *h; + int i, j; + ulong *g; +#if 0 + reverse dominance suggests that this is a possible + entry and exit node for a proper subgraph +#endif + h = fsm_tbl[out]; + + i = f->from / BPW; + j = f->from % BPW; + g = h->mod; + + if (verbose&32) + printf("possible pair %d %d -- %d\n", + f->from, h->from, (g[i]&(1<from); /* record this pair */ +} + +static void +act_dom(AST *a) +{ FSM_state *f; + FSM_trans *t; + int i, j, cnt; + + for (f = a->fsm; f; f = f->nxt) + { if (!f->seen) continue; +#if 0 + f->from is the exit-node of a proper subgraph, with + the dominator its entry-node, if: + a. this node has more than 1 reachable predecessor + b. the dominator has more than 1 reachable successor + (need reachability - in case of reverse dominance) + d. the dominator is reachable, and not equal to this node +#endif + for (t = f->p, i = 0; t; t = t->nxt) + i += fsm_tbl[t->to]->seen; + if (i <= 1) continue; /* a. */ + + for (cnt = 1; cnt < a->nstates; cnt++) /* 0 is endstate */ + { if (cnt == f->from + || !fsm_tbl[cnt]->seen) + continue; /* c. */ + + i = cnt / BPW; + j = cnt % BPW; + if (!(f->dom[i]&(1<t, i = 0; t; t = t->nxt) + i += fsm_tbl[t->to]->seen; + if (i <= 1) + continue; /* b. */ + + if (f->mod) /* final check in 2nd phase */ + subgraph(a, f, cnt); /* possible entry-exit pair */ + } + } +} + +static void +reachability(AST *a) +{ FSM_state *f; + + for (f = a->fsm; f; f = f->nxt) + f->seen = 0; /* clear */ + AST_dfs(a, a->i_st, 0); /* mark 'seen' */ +} + +static int +see_else(FSM_state *f) +{ FSM_trans *t; + + for (t = f->t; t; t = t->nxt) + { if (t->step + && t->step->n) + switch (t->step->n->ntyp) { + case ELSE: + return 1; + case IF: + case DO: + case ATOMIC: + case NON_ATOMIC: + case D_STEP: + if (see_else(fsm_tbl[t->to])) + return 1; + default: + break; + } + } + return 0; +} + +static int +is_guard(FSM_state *f) +{ FSM_state *g; + FSM_trans *t; + + for (t = f->p; t; t = t->nxt) + { g = fsm_tbl[t->to]; + if (!g->seen) + continue; + + if (t->step + && t->step->n) + switch(t->step->n->ntyp) { + case IF: + case DO: + return 1; + case ATOMIC: + case NON_ATOMIC: + case D_STEP: + if (is_guard(g)) + return 1; + default: + break; + } + } + return 0; +} + +static void +curtail(AST *a) +{ FSM_state *f, *g; + FSM_trans *t; + int i, haselse, isrel, blocking; +#if 0 + mark nodes that do not satisfy these requirements: + 1. all internal branch-points have else-s + 2. all non-branchpoints have non-blocking out-edge + 3. all internal edges are non-data-relevant +#endif + if (verbose&32) + printf("Curtail %s:\n", a->p->n->name); + + for (f = a->fsm; f; f = f->nxt) + { if (!f->seen + || (f->scratch&(1|2))) + continue; + + isrel = haselse = i = blocking = 0; + + for (t = f->t; t; t = t->nxt) + { g = fsm_tbl[t->to]; + + isrel |= (t->relevant&1); /* data relevant */ + i += g->seen; + + if (t->step + && t->step->n) + { switch (t->step->n->ntyp) { + case IF: + case DO: + haselse |= see_else(g); + break; + case 'c': + case 's': + case 'r': + blocking = 1; + break; + } } } +#if 0 + if (verbose&32) + printf("prescratch %d -- %d %d %d %d -- %d\n", + f->from, i, isrel, blocking, haselse, is_guard(f)); +#endif + if (isrel /* 3. */ + || (i == 1 && blocking) /* 2. */ + || (i > 1 && !haselse)) /* 1. */ + { if (!is_guard(f)) + { f->scratch |= 1; + if (verbose&32) + printf("scratch %d -- %d %d %d %d\n", + f->from, i, isrel, blocking, haselse); + } + } + } +} + +static void +init_dom(AST *a) +{ FSM_state *f; + int i, j, cnt; +#if 0 + (1) D(s0) = {s0} + (2) for s in S - {s0} do D(s) = S +#endif + + for (f = a->fsm; f; f = f->nxt) + { if (!f->seen) continue; + + f->dom = (ulong *) + emalloc(a->nwords * sizeof(ulong)); + + if (f->from == a->i_st) + { i = a->i_st / BPW; + j = a->i_st % BPW; + f->dom[i] = (1<nwords; i++) + f->dom[i] = (ulong) ~0; /* all 1's */ + + if (a->nstates % BPW) + for (i = a->nstates % BPW; i < BPW; i++) + f->dom[a->nwords-1] &= ~(1<nstates; cnt++) + if (!fsm_tbl[cnt]->seen) + { i = cnt / BPW; + j = cnt % BPW; + f->dom[i] &= ~(1<nwords) + { on = a->nwords; + ndom = (ulong *) + emalloc(on * sizeof(ulong)); + } + + for (i = 0; i < a->nwords; i++) + ndom[i] = (ulong) ~0; + + for (t = f->p; t; t = t->nxt) /* all reachable predecessors */ + { g = fsm_tbl[t->to]; + if (g->seen) + for (i = 0; i < a->nwords; i++) + ndom[i] &= g->dom[i]; /* (5b) */ + } + + i = f->from / BPW; + j = f->from % BPW; + ndom[i] |= (1<nwords; i++) + if (f->dom[i] != ndom[i]) + { cnt++; + f->dom[i] = ndom[i]; + } + + return cnt; +} + +static void +dom_forward(AST *a) +{ FSM_state *f; + int cnt; + + init_dom(a); /* (1,2) */ + do { + cnt = 0; + for (f = a->fsm; f; f = f->nxt) + { if (f->seen + && f->from != a->i_st) /* (4) */ + cnt += dom_perculate(a, f); /* (5) */ + } + } while (cnt); /* (3) */ + dom_perculate(a, fsm_tbl[a->i_st]); +} + +static void +AST_dominant(void) +{ FSM_state *f; + FSM_trans *t; + AST *a; + int oi; +#if 0 + find dominators + Aho, Sethi, & Ullman, Compilers - principles, techniques, and tools + Addison-Wesley, 1986, p.671. + + (1) D(s0) = {s0} + (2) for s in S - {s0} do D(s) = S + + (3) while any D(s) changes do + (4) for s in S - {s0} do + (5) D(s) = {s} union with intersection of all D(p) + where p are the immediate predecessors of s + + the purpose is to find proper subgraphs + (one entry node, one exit node) +#endif + if (AST_Round == 1) /* computed once, reused in every round */ + for (a = ast; a; a = a->nxt) + { a->nstates = 0; + for (f = a->fsm; f; f = f->nxt) + { a->nstates++; /* count */ + fsm_tbl[f->from] = f; /* fast lookup */ + f->scratch = 0; /* clear scratch marks */ + } + for (oi = 0; oi < a->nstates; oi++) + if (!fsm_tbl[oi]) + fsm_tbl[oi] = &no_state; + + a->nwords = (a->nstates + BPW - 1) / BPW; /* round up */ + + if (verbose&32) + { printf("%s (%d): ", a->p->n->name, a->i_st); + printf("states=%d (max %d), words = %d, bpw %d, overflow %d\n", + a->nstates, o_max, a->nwords, + (int) BPW, (int) (a->nstates % BPW)); + } + + reachability(a); + dom_forward(a); /* forward dominance relation */ + + curtail(a); /* mark ineligible edges */ + for (f = a->fsm; f; f = f->nxt) + { t = f->p; + f->p = f->t; + f->t = t; /* invert edges */ + + f->mod = f->dom; + f->dom = (ulong *) 0; + } + oi = a->i_st; + if (fsm_tbl[0]->seen) /* end-state reachable - else leave it */ + a->i_st = 0; /* becomes initial state */ + + dom_forward(a); /* reverse dominance -- don't redo reachability! */ + act_dom(a); /* mark proper subgraphs, if any */ + AST_checkpairs(a); /* selectively place 2 scratch-marks */ + + for (f = a->fsm; f; f = f->nxt) + { t = f->p; + f->p = f->t; + f->t = t; /* restore */ + } + a->i_st = oi; /* restore */ + } else + for (a = ast; a; a = a->nxt) + { for (f = a->fsm; f; f = f->nxt) + { fsm_tbl[f->from] = f; + f->scratch &= 1; /* preserve 1-marks */ + } + for (oi = 0; oi < a->nstates; oi++) + if (!fsm_tbl[oi]) + fsm_tbl[oi] = &no_state; + + curtail(a); /* mark ineligible edges */ + + for (f = a->fsm; f; f = f->nxt) + { t = f->p; + f->p = f->t; + f->t = t; /* invert edges */ + } + + AST_checkpairs(a); /* recompute 2-marks */ + + for (f = a->fsm; f; f = f->nxt) + { t = f->p; + f->p = f->t; + f->t = t; /* restore */ + } } +} --- /sys/src/cmd/spin/pc_zpp.c Wed Aug 31 04:24:53 2005 +++ /sys/src/cmd/spin/pc_zpp.c Wed Aug 31 04:24:52 2005 @@ -1,13 +1,16 @@ /***** spin: pc_zpp.c *****/ -/* Copyright (c) 1997-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann, gerard@research.bell-labs.com */ -/* pc_zpp.c is only used in the PC version of Spin, to avoid too great a */ -/* reliance on the cpp command. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + +/* pc_zpp.c is only used in the PC version of Spin */ +/* it is included to avoid too great a reliance on an external cpp */ #include #include @@ -20,16 +23,17 @@ #define MAXNEST 32 #define MAXDEF 128 #define MAXLINE 512 +#define GENEROUS 4096 #define debug(x,y) if (verbose) printf(x,y) -static FILE *outpp = stdout; +static FILE *outpp /* = stdout */; static int if_truth[MAXNEST]; static int printing[MAXNEST]; static int if_depth, nr_defs, verbose = 0; static enum cstate state = PLAIN; -static char Out1[4096], Out2[4096]; +static char Out1[GENEROUS], Out2[GENEROUS]; static struct Defines { int exists; @@ -39,6 +43,8 @@ static int process(char *, int, char *); static int zpp_do(char *); +extern char *emalloc(int); /* main.c */ + static int do_define(char *p) { char *q, *r, *s; @@ -73,8 +79,8 @@ adddef: for (j = 0; j < nr_defs; j++) if (!strcmp(d[j].src, q)) d[j].exists = 0; - d[nr_defs].src = malloc(strlen(q)+1); - d[nr_defs].trg = malloc(strlen(s)+1); + d[nr_defs].src = emalloc(strlen(q)+1); + d[nr_defs].trg = emalloc(strlen(s)+1); strcpy(d[nr_defs].src, q); strcpy(d[nr_defs].trg, s); d[nr_defs++].exists = 1; @@ -98,7 +104,7 @@ for (i = nr_defs-1; i >= 0; i--) { if (!d[i].exists) continue; - j = strlen(d[i].src); + j = (int) strlen(d[i].src); more: in2 = strstr(startat, d[i].src); if (!in2) /* no more matches */ { startat = in1; @@ -107,6 +113,13 @@ if ((in2 == in1 || !isvalid(*(in2-1))) && (in2+j == '\0' || !isvalid(*(in2+j)))) { *in2 = '\0'; + + if (strlen(in1)+strlen(d[i].trg)+strlen(in2+j) >= GENEROUS) + { + printf("spin: circular macro expansion %s -> %s ?\n", + d[i].src, d[i].trg); + return in1; + } strcat(out, in1); strcat(out, d[i].trg); strcat(out, in2+j); @@ -217,7 +230,7 @@ } static int -do_else(char *p) +do_else(char *unused) { if_truth[if_depth] = 1-if_truth[if_depth]; printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth]; @@ -304,13 +317,13 @@ FILE *inp; int lno = 0, nw_lno = 0; if ((inp = fopen(fnm, "r")) == NULL) - { debug("error: cannot open %s\n", fnm); - return 0; + { fprintf(stdout, "spin: error, '%s': No such file\n", fnm); + return 0; /* 4.1.2 was stderr */ } printing[0] = if_truth[0] = 1; fprintf(outpp, "#line %d \"%s\"\n", lno+1, fnm); while (fgets(buf, MAXLINE, inp)) - { lno++; n = strlen(buf); + { lno++; n = (int) strlen(buf); on = 0; nw_lno = 0; while (n > 2 && buf[n-2] == '\\') { buf[n-2] = '\0'; @@ -324,7 +337,7 @@ return 0; } strcat(buf, buf2); - n = strlen(buf); + n = (int) strlen(buf); } if (in_comment(&buf[on])) { buf[n-1] = '\0'; /* eat newline */ @@ -348,8 +361,8 @@ try_zpp(char *fnm, char *onm) { int r; if ((outpp = fopen(onm, "w")) == NULL) - return 0; - r = zpp_do(fnm); + return 0; + r = zpp_do(fnm); fclose(outpp); return r; /* 1 = ok; 0 = use cpp */ } --- /sys/src/cmd/spin/ps_msc.c Wed Aug 31 04:25:13 2005 +++ /sys/src/cmd/spin/ps_msc.c Wed Aug 31 04:25:12 2005 @@ -1,10 +1,13 @@ /***** spin: ps_msc.c *****/ -/* Copyright (c) 1997-2000 by Lucent Technologies - Bell Laboratories. */ +/* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ /* The Postscript generation code below was written by Gerard J. Holzmann */ /* in June 1997. Parts of the prolog template are based on similar boiler */ @@ -14,6 +17,10 @@ #include "spin.h" #include "version.h" +#ifdef PC +extern void free(void *); +#endif + static char *PsPre[] = { "%%%%Pages: (atend)", "%%%%PageOrder: Ascend", @@ -121,10 +128,10 @@ static char *ProcLine; /* active processes */ static int pspno = 0; /* postscript page */ static int ldepth = 1; -static int maxx, TotSteps = 4096; /* max nr of steps, about 40 pages */ +static int maxx, TotSteps = 2*4096; /* max nr of steps, about 40 pages */ static float Scaler = (float) 1.0; -extern int nproc, nstop, ntrail, s_trail, pno, depth; +extern int ntrail, s_trail, pno, depth; extern Symbol *oFname; extern void exit(int); void putpages(void); @@ -151,7 +158,7 @@ fprintf(pfd, "%%%%Page: %d %d\n", pspno, pspno); putlegend(); - for (i = 255; i >= 0; i--) + for (i = TotSteps-1; i >= 0; i--) { if (!I[i]) continue; spitbox(i, RH, -PH, I[i]); } @@ -161,11 +168,7 @@ fprintf(pfd, "%d %d lineto\n", RH+MW, LH+oMH+5); fprintf(pfd, "%d %d lineto\n", RH+MW, LH); fprintf(pfd, "10 %d lineto\n", LH); -#if 0 - fprintf(pfd, "closepath\n"); -#else fprintf(pfd, "closepath clip newpath\n"); -#endif fprintf(pfd, "%f %f translate\n", (float) RH, (float) LH); memset(ProcLine, 0, 256*sizeof(char)); @@ -189,9 +192,9 @@ if (s_trail) { if (ntrail) - sprintf(snap, "%s%d.trail", oFname->name, ntrail); + sprintf(snap, "%s%d.trail", oFname?oFname->name:"msc", ntrail); else - sprintf(snap, "%s.trail", oFname->name); + sprintf(snap, "%s.trail", oFname?oFname->name:"msc"); if (!(fd = fopen(snap, "r"))) { snap[strlen(snap)-2] = '\0'; if (!(fd = fopen(snap, "r"))) @@ -206,8 +209,8 @@ M = (short *) emalloc(TotSteps * sizeof(short)); T = (short *) emalloc(TotSteps * sizeof(short)); L = (char **) emalloc(TotSteps * sizeof(char *)); - I = (char **) emalloc(256 * sizeof(char *)); - ProcLine = (char *) emalloc(256 * sizeof(char)); + I = (char **) emalloc(TotSteps * sizeof(char *)); + ProcLine = (char *) emalloc(1024 * sizeof(char)); startpage(); } @@ -226,13 +229,10 @@ } void psline(int x0, int iy0, int x1, int iy1, float r, float g, float b, int w) -{ - int y0 = MH-iy0; +{ int y0 = MH-iy0; int y1 = MH-iy1; - int dx = 5; if (y1 > y0) y1 -= MH; - if (x0 > x1) dx = -5; fprintf(pfd, "gsave\n"); fprintf(pfd, "%d %d moveto\n", x0*WW, y0); @@ -268,13 +268,15 @@ } void -putarrow(int from, int to) { T[D[from]] = D[to]; } +putarrow(int from, int to) +{ + T[D[from]] = D[to]; +} void stepnumber(int i) { int y = MH-(i*HH)%MH; -/* if (y == MH) y -= 5; */ fprintf(pfd, "gsave\n"); fprintf(pfd, "/Courier-Bold findfont 6 scalefont "); fprintf(pfd, "ISOEncode setfont\n"); @@ -318,11 +320,11 @@ } else { r = (float) 1.; g = (float) 1.; b = (float) 0.; if (!dx - && sscanf(s, "%d:%s", &a, &d) == 2 - && a >= 0 && a <= 255) + && sscanf(s, "%d:%s", &a, d) == 2 /* was &d */ + && a >= 0 && a < TotSteps) { if (!I[a] || strlen(I[a]) <= strlen(s)) - I[a] = emalloc(strlen(s)+1); + I[a] = emalloc((int) strlen(s)+1); strcpy(I[a], s); } } colbox(x*WW+dx, MH-(y*HH)%MH, (int) bw, 4, r,g,b); @@ -338,7 +340,6 @@ void putpages(void) { int i, lasti=0; float nmh; -/* extern int free(void *); */ if (maxx*WW > MW-RH/2) { Scaler = (float) (MW-RH/2) / (float) (maxx*WW); @@ -346,7 +347,7 @@ nmh = (float) MH; nmh /= Scaler; MH = (int) nmh; } - for (i = 255; i >= 0; i--) + for (i = TotSteps-1; i >= 0; i--) { if (!I[i]) continue; spitbox(i, 0, 0, I[i]); } @@ -397,7 +398,7 @@ { if (ldepth >= TotSteps) { putpostlude(); - fprintf(stderr, "max length of %d steps exceeded", + fprintf(stderr, "max length of %d steps exceeded\n", TotSteps); fatal("postscript file truncated", (char *) 0); } @@ -407,13 +408,19 @@ void pstext(int x, char *s) -{ char *tmp = emalloc(strlen(s)+1); +{ char *tmp = emalloc((int) strlen(s)+1); strcpy(tmp, s); if (depth == 0) I[x] = tmp; else { putbox(x); + if (depth >= TotSteps || ldepth >= TotSteps) + { fprintf(stderr, "max nr of %d steps exceeded\n", + TotSteps); + fatal("aborting", (char *) 0); + } + D[depth] = ldepth; R[ldepth] = depth; L[ldepth] = tmp; @@ -423,15 +430,19 @@ void dotag(FILE *fd, char *s) -{ extern int columns; extern RunList *X; +{ extern int columns, notabs; extern RunList *X; int i = (!strncmp(s, "MSC: ", 5))?5:0; int pid = s_trail ? pno : (X?X->pid:0); if (columns == 2) pstext(pid, &s[i]); else - { for (i = 0; i < pid; i++) - printf("\t"); + { if (!notabs) + { printf(" "); + for (i = 0; i <= pid; i++) + printf(" "); + } fprintf(fd, "%s", s); + fflush(fd); } } --- /sys/src/cmd/spin/reprosrc.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/spin/reprosrc.c Wed Aug 31 04:25:32 2005 @@ -0,0 +1,140 @@ +/***** spin: reprosrc.c *****/ + +/* Copyright (c) 2002-2003 by Lucent Technologies, Bell Laboratories. */ +/* All Rights Reserved. This software is for educational purposes only. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + +#include +#include "spin.h" +#ifdef PC +#include "y_tab.h" +#else +#include "y.tab.h" +#endif + +static int indent = 1; + +extern ProcList *rdy; +void repro_seq(Sequence *); + +void +doindent(void) +{ int i; + for (i = 0; i < indent; i++) + printf(" "); +} + +void +repro_sub(Element *e) +{ + doindent(); + switch (e->n->ntyp) { + case D_STEP: + printf("d_step {\n"); + break; + case ATOMIC: + printf("atomic {\n"); + break; + case NON_ATOMIC: + printf(" {\n"); + break; + } + indent++; + repro_seq(e->n->sl->this); + indent--; + + doindent(); + printf(" };\n"); +} + +void +repro_seq(Sequence *s) +{ Element *e; + Symbol *v; + SeqList *h; + + for (e = s->frst; e; e = e->nxt) + { + v = has_lab(e, 0); + if (v) printf("%s:\n", v->name); + + if (e->n->ntyp == UNLESS) + { printf("/* normal */ {\n"); + repro_seq(e->n->sl->this); + doindent(); + printf("} unless {\n"); + repro_seq(e->n->sl->nxt->this); + doindent(); + printf("}; /* end unless */\n"); + } else if (e->sub) + { + switch (e->n->ntyp) { + case DO: doindent(); printf("do\n"); indent++; break; + case IF: doindent(); printf("if\n"); indent++; break; + } + + for (h = e->sub; h; h = h->nxt) + { indent--; doindent(); indent++; printf("::\n"); + repro_seq(h->this); + printf("\n"); + } + + switch (e->n->ntyp) { + case DO: indent--; doindent(); printf("od;\n"); break; + case IF: indent--; doindent(); printf("fi;\n"); break; + } + } else + { if (e->n->ntyp == ATOMIC + || e->n->ntyp == D_STEP + || e->n->ntyp == NON_ATOMIC) + repro_sub(e); + else if (e->n->ntyp != '.' + && e->n->ntyp != '@' + && e->n->ntyp != BREAK) + { + doindent(); + if (e->n->ntyp == C_CODE) + { printf("c_code "); + plunk_inline(stdout, e->n->sym->name, 1); + } else if (e->n->ntyp == 'c' + && e->n->lft->ntyp == C_EXPR) + { printf("c_expr { "); + plunk_expr(stdout, e->n->lft->sym->name); + printf("} ->\n"); + } else + { comment(stdout, e->n, 0); + printf(";\n"); + } } + } + if (e == s->last) + break; + } +} + +void +repro_proc(ProcList *p) +{ + if (!p) return; + if (p->nxt) repro_proc(p->nxt); + + if (p->det) printf("D"); /* deterministic */ + printf("proctype %s()", p->n->name); + if (p->prov) + { printf(" provided "); + comment(stdout, p->prov, 0); + } + printf("\n{\n"); + repro_seq(p->s); + printf("}\n"); +} + +void +repro_src(void) +{ + repro_proc(rdy); +} --- /sys/src/cmd/spin/run.c Wed Aug 31 04:25:54 2005 +++ /sys/src/cmd/spin/run.c Wed Aug 31 04:25:52 2005 @@ -1,14 +1,13 @@ /***** spin: run.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include #include "spin.h" @@ -52,7 +51,7 @@ if (!e) return (Element *) 0; - if (r = rev_escape(e->nxt)) /* reversed order */ + if ((r = rev_escape(e->nxt)) != ZE) /* reversed order */ return r; return eval_sub(e->this->frst); @@ -84,7 +83,7 @@ } else if (e->sub) /* true for IF, DO, and UNLESS */ { Element *has_else = ZE; Element *bas_else = ZE; - int nr_else, nr_choices = 0; + int nr_else = 0, nr_choices = 0; if (interactive && !MadeChoice && !E_Check @@ -174,8 +173,21 @@ continue; } } + if (z->this->frst + && ((z->this->frst->n->ntyp == ATOMIC + || z->this->frst->n->ntyp == D_STEP) + && z->this->frst->n->sl->this->frst->n->ntyp == ELSE)) + { bas_else = z->this->frst->n->sl->this->frst; + has_else = (Rvous)?ZE:bas_else->nxt; + if (!interactive || depth < jumpsteps + || Escape_Check + || (e->status&(D_ATOM))) + { z = (z->nxt)?z->nxt:e->sub; + continue; + } + } if (i >= k) - { if (f = eval_sub(z->this->frst)) + { if ((f = eval_sub(z->this->frst)) != ZE) return f; else if (interactive && depth >= jumpsteps && !(e->status&(D_ATOM))) @@ -222,11 +234,13 @@ } printf("\n"); } - +#if 0 if (!(e->status & D_ATOM)) /* escapes don't reach inside d_steps */ + /* 4.2.4: only the guard of a d_step can have an escape */ +#endif { Escape_Check++; if (like_java) - { if (g = rev_escape(e->esc)) + { if ((g = rev_escape(e->esc)) != ZE) { if (verbose&4) printf("\tEscape taken\n"); Escape_Check--; @@ -234,7 +248,7 @@ } } else { for (x = e->esc; x; x = x->nxt) - { if (g = eval_sub(x->this->frst)) + { if ((g = eval_sub(x->this->frst)) != ZE) { if (verbose&4) printf("\tEscape taken\n"); Escape_Check--; @@ -245,7 +259,8 @@ switch (e->n->ntyp) { case TIMEOUT: case RUN: - case PRINT: + case PRINT: case PRINTM: + case C_CODE: case C_EXPR: case ASGN: case ASSERT: case 's': case 'r': case 'c': /* toplevel statements only */ @@ -350,7 +365,7 @@ case '?': return (eval(now->lft) ? eval(now->rgt->lft) : eval(now->rgt->rgt)); - case 'p': return remotevar(now); /* only _p allowed */ + case 'p': return remotevar(now); /* _p for remote reference */ case 'q': return remotelab(now); case 'R': return qrecv(now, 0); /* test only */ case LEN: return qlen(now); @@ -372,7 +387,18 @@ case 'r': return qrecv(now, 1); /* receive or poll */ case 'c': return eval(now->lft); /* condition */ case PRINT: return TstOnly?1:interprint(stdout, now); + case PRINTM: return TstOnly?1:printm(stdout, now); case ASGN: return assign(now); + + case C_CODE: printf("%s:\t", now->sym->name); + plunk_inline(stdout, now->sym->name, 0); + return 1; /* uninterpreted */ + + case C_EXPR: printf("%s:\t", now->sym->name); + plunk_expr(stdout, now->sym->name); + printf("\n"); + return 1; /* uninterpreted */ + case ASSERT: if (TstOnly || eval(now->lft)) return 1; non_fatal("assertion violated", (char *) 0); printf("spin: text of failed assertion: assert("); @@ -393,6 +419,25 @@ } int +printm(FILE *fd, Lextok *n) +{ extern char Buf[]; + int j; + + Buf[0] = '\0'; + if (!no_print) + if (!s_trail || depth >= jumpsteps) { + if (n->lft->ismtyp) + j = n->lft->val; + else + j = eval(n->lft); + Buf[0] = '\0'; + sr_buf(j, 1); + dotag(fd, Buf); + } + return 1; +} + +int interprint(FILE *fd, Lextok *n) { Lextok *tmp = n->lft; char c, *s = n->sym->name; @@ -465,22 +510,24 @@ /* else fall through */ default: /* side-effect free */ verbose = 0; -E_Check++; + E_Check++; i = eval(n); -E_Check--; + E_Check--; verbose = v; return i; - case PRINT: case ASGN: case ASSERT: + case C_CODE: case C_EXPR: + case PRINT: case PRINTM: + case ASGN: case ASSERT: return 1; case 's': if (q_is_sync(n)) { if (Rvous) return 0; TstOnly = 1; verbose = 0; -E_Check++; + E_Check++; i = eval(n); -E_Check--; + E_Check--; TstOnly = 0; verbose = v; return i; } @@ -489,9 +536,9 @@ if (q_is_sync(n)) return 0; /* it's never a user-choice */ n->ntyp = 'R'; verbose = 0; -E_Check++; + E_Check++; i = eval(n); -E_Check--; + E_Check--; n->ntyp = 'r'; verbose = v; return i; } @@ -544,6 +591,9 @@ int pid = eval(n); int result = 0; RunList *Y, *oX; + + if (pid == X->pid) + fatal("used: enabled(pid=thisproc) [%s]", X->n->name); for (Y = run; Y; Y = Y->nxt) if (--i == pid) --- /sys/src/cmd/spin/sched.c Wed Aug 31 04:26:16 2005 +++ /sys/src/cmd/spin/sched.c Wed Aug 31 04:26:14 2005 @@ -1,14 +1,13 @@ /***** spin: sched.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include #include "spin.h" @@ -23,8 +22,9 @@ extern Ordered *all_names; extern Symbol *Fname, *context; extern int lineno, nr_errs, dumptab, xspin, jumpsteps, columns; -extern int u_sync, Elcnt, interactive, TstOnly; -extern short has_enabled, has_provided; +extern int u_sync, Elcnt, interactive, TstOnly, cutoff; +extern short has_enabled; +extern int limited_vis; RunList *X = (RunList *) 0; RunList *run = (RunList *) 0; @@ -46,11 +46,20 @@ r->n = p->n; r->tn = p->tn; - r->pid = ++nproc-nstop-1; - r->pc = huntele(p->s->frst, p->s->frst->status); + r->pid = nproc++ - nstop + Skip_claim; + + if ((verbose&4) || (verbose&32)) + printf("Starting %s with pid %d\n", p->n->name, r->pid); + + if (!p->s) + fatal("parsing error, no sequence %s", p->n?p->n->name:"--"); + + r->pc = huntele(p->s->frst, p->s->frst->status, -1); r->ps = p->s; - if (p->s && p->s->last) - p->s->last->status |= ENDSTATE; /* normal endstate */ + + if (p->s->last) + p->s->last->status |= ENDSTATE; /* normal end state */ + r->nxt = run; r->prov = p->prov; r->priority = weight; @@ -120,22 +129,22 @@ firstrow = 1; if (columns == 2) { sprintf(Buf, "%d:%s", - run->pid, run->n->name); - pstext(run->pid, Buf); + run->pid - Have_claim, run->n->name); + pstext(run->pid - Have_claim, Buf); } else printf("proc %d = %s\n", run->pid - Have_claim, run->n->name); return; } -#if 1 + if (dumptab || analyze || s_trail || !(verbose&4)) return; -#endif + if (w) - printf(" 0: proc - (%s) ", w); + printf(" 0: proc - (%s) ", w); else whoruns(1); printf("creates proc %2d (%s)", @@ -146,6 +155,10 @@ printf("\n"); } +#ifndef MAXP +#define MAXP 255 /* matches max nr of processes in verifier */ +#endif + int enable(Lextok *m) { ProcList *p; @@ -155,11 +168,15 @@ if (m->val < 1) m->val = 1; /* minimum priority */ for (p = rdy; p; p = p->nxt) if (strcmp(s->name, p->n->name) == 0) - { runnable(p, m->val, 0); + { if (nproc-nstop >= MAXP) + { printf("spin: too many processes (%d max)\n", MAXP); + break; + } + runnable(p, m->val, 0); announce((char *) 0); setparams(run, p, n); setlocals(run); /* after setparams */ - return run->pid - Have_claim; /* pid */ + return run->pid - Have_claim + Skip_claim; /* effective simu pid */ } return 0; /* process not found */ } @@ -179,7 +196,7 @@ Skip_claim = 1; goto done; found: - /* move claim to far end of runlist, with pid 0 */ + /* move claim to far end of runlist, and reassign it pid 0 */ if (columns == 2) { depth = 0; pstext(0, "0::never:"); @@ -190,23 +207,42 @@ r->pid+1, r->n->name); pstext(r->pid+1, Buf); } } - if (run->pid == 0) return; /* already there */ + + if (run->pid == 0) return; /* it is the first process started */ q = run; run = run->nxt; - q->pid = 0; q->nxt = (RunList *) 0; + q->pid = 0; q->nxt = (RunList *) 0; /* remove */ done: + Have_claim = 1; for (r = run; r; r = r->nxt) - { r->pid = r->pid+1; + { r->pid = r->pid+Have_claim; /* adjust */ if (!r->nxt) { r->nxt = q; break; } } - Have_claim = 1; +} + +int +f_pid(char *n) +{ RunList *r; + int rval = -1; + + for (r = run; r; r = r->nxt) + if (strcmp(n, r->n->name) == 0) + { if (rval >= 0) + { printf("spin: remote ref to proctype %s, ", n); + printf("has more than one match: %d and %d\n", + rval, r->pid); + } else + rval = r->pid; + } + return rval; } void wrapup(int fini) { + limited_vis = 0; if (columns) { extern void putpostlude(void); if (columns == 2) putpostlude(); @@ -217,7 +253,7 @@ goto short_cut; if (nproc != nstop) { int ov = verbose; - printf("#processes: %d\n", nproc-nstop); + printf("#processes: %d\n", nproc-nstop - Have_claim + Skip_claim); verbose &= ~4; dumpglobals(); verbose = ov; @@ -227,7 +263,9 @@ talk(X); verbose = ov; /* restore */ } - printf("%d processes created\n", nproc); + printf("%d process%s created\n", + nproc - Have_claim + Skip_claim, + (xspin || nproc!=1)?"es":""); short_cut: if (xspin) alldone(0); /* avoid an abort from xspin */ if (fini) alldone(1); @@ -237,7 +275,7 @@ static int p_blocked(int p) -{ register int i, j; +{ int i, j; is_blocked[p%256] = 1; for (i = j = 0; i < nproc - nstop; i++) @@ -276,7 +314,7 @@ pickproc(void) { SeqList *z; Element *has_else; short Choices[256]; - int j, k, nr_else; + int j, k, nr_else = 0; if (nproc <= nstop+1) { X = run; @@ -422,7 +460,7 @@ { Element *e; RunList *Y=0; /* previous process in run queue */ RunList *oX; - int go, notbeyond; + int go, notbeyond = 0; #ifdef PC int bufmax = 100; #endif @@ -450,11 +488,8 @@ if (eventmap) printf("warning: trace assertion not used in random simulation\n"); -/* if (interactive) Tval = 1; */ - X = run; pickproc(); - notbeyond = 0; while (X) { context = X->n; @@ -462,19 +497,25 @@ { lineno = X->pc->n->ln; Fname = X->pc->n->fn; } + if (cutoff > 0 && depth >= cutoff) + { printf("-------------\n"); + printf("depth-limit (-u%d steps) reached\n", cutoff); + break; + } #ifdef PC if (xspin && !interactive && --bufmax <= 0) - { /* avoid buffer overflow on pc's */ + { int c; /* avoid buffer overflow on pc's */ printf("spin: type return to proceed\n"); fflush(stdout); - getc(stdin); + c = getc(stdin); + if (c == 'q') wrapup(0); bufmax = 100; } #endif depth++; LastStep = ZE; oX = X; /* a rendezvous could change it */ go = 1; - if (X && X->prov + if (X && X->prov && X->pc && !(X->pc->status & D_ATOM) && !eval(X->prov)) { if (!xspin && ((verbose&32) || (verbose&4))) @@ -487,6 +528,7 @@ { if (depth >= jumpsteps && ((verbose&32) || (verbose&4))) { if (X == oX) + if (!(e->status & D_ATOM) || (verbose&32)) /* no talking in d_steps */ { p_talk(X->pc, 1); printf(" ["); if (!LastStep) LastStep = X->pc; @@ -495,17 +537,23 @@ } if (verbose&1) dumpglobals(); if (verbose&2) dumplocal(X); - if (xspin) printf("\n"); + + if (!(e->status & D_ATOM)) + if (xspin) + printf("\n"); + } + if (oX != X) + { e = silent_moves(e); + notbeyond = 0; } - if (oX != X) e = silent_moves(e); oX->pc = e; LastX = X; if (!interactive) Tval = 0; memset(is_blocked, 0, 256); - if ((X->pc->status & (ATOM|L_ATOM)) - && notbeyond == 0) - { if (X->pc->status & L_ATOM) + if (X->pc && (X->pc->status & (ATOM|L_ATOM)) + && (notbeyond == 0 || oX != X)) + { if ((X->pc->status & L_ATOM)) notbeyond = 1; continue; /* no process switch */ } @@ -535,8 +583,11 @@ { if (Tval) break; Tval = 1; if (depth >= jumpsteps) + { oX = X; + X = (RunList *) 0; /* to suppress indent */ dotag(stdout, "timeout\n"); - } } } + X = oX; + } } } } Y = X; pickproc(); notbeyond = 0; @@ -739,6 +790,20 @@ } int +in_bound(Symbol *r, int n) +{ + if (!r) return 0; + + if (n >= r->nel || n < 0) + { printf("spin: indexing %s[%d] - size is %d\n", + r->name, n, r->nel); + non_fatal("indexing array \'%s\'", r->name); + return 0; + } + return 1; +} + +int getlocal(Lextok *sn) { Symbol *r, *s = sn->sym; int n = eval(sn->lft); @@ -746,14 +811,8 @@ r = findloc(s); if (r && r->type == STRUCT) return Rval_struct(sn, r, 1); /* 1 = check init */ - if (r) - { if (n >= r->nel || n < 0) - { printf("spin: indexing %s[%d] - size is %d\n", - s->name, n, r->nel); - non_fatal("indexing array \'%s\'", s->name); - } else - { return cast_val(r->type, r->val[n], r->nbits); - } } + if (in_bound(r, n)) + return cast_val(r->type, r->val[n], r->nbits); return 0; } @@ -762,19 +821,18 @@ { Symbol *r = findloc(p->sym); int n = eval(p->lft); - if (!r) return 1; - - if (n >= r->nel || n < 0) - { printf("spin: indexing %s[%d] - size is %d\n", - r->name, n, r->nel); - non_fatal("indexing array \'%s\'", r->name); - } else + if (in_bound(r, n)) { if (r->type == STRUCT) (void) Lval_struct(p, r, 1, m); /* 1 = check init */ else - { if (r->nbits > 0) - m = (m & ((1<nbits)-1)); + { +#if 0 + if (r->nbits > 0) + m = (m & ((1<nbits)-1)); r->val[n] = m; +#else + r->val[n] = cast_val(r->type, m, r->nbits); +#endif r->setat = depth; } } @@ -817,12 +875,14 @@ && lastnever != newnever && e) { if (xspin) { printf("MSC: ~G line %d\n", newnever); - printf("%3d: proc 0 (NEVER) line %d \"never\" ", +#if 0 + printf("%3d: proc - (NEVER) line %d \"never\" ", depth, newnever); printf("(state 0)\t[printf('MSC: never\\\\n')]\n"); } else - { printf("%3d: proc 0 (NEVER) line %d \"never\"\n", + { printf("%3d: proc - (NEVER) line %d \"never\"\n", depth, newnever); +#endif } lastnever = newnever; } @@ -835,7 +895,7 @@ e->seqno); if (!xspin && ((e->status&ENDSTATE) || has_lab(e, 2))) /* 2=end */ - { printf(" "); + { printf(" "); } } } @@ -846,8 +906,10 @@ lineno = n->ln; Fname = n->fn; - if (n->sym->type) + if (n->sym->type != 0 && n->sym->type != LABEL) + { printf("spin: error, type: %d\n", n->sym->type); fatal("not a labelname: '%s'", n->sym->name); + } if (n->indstep >= 0) { fatal("remote ref to label '%s' inside d_step", n->sym->name); @@ -859,29 +921,40 @@ int remotevar(Lextok *n) -{ int prno, i, trick=0; - RunList *Y; +{ int prno, i, added=0; + RunList *Y, *oX; + Lextok *onl; + Symbol *os; lineno = n->ln; Fname = n->fn; + if (!n->lft->lft) - { non_fatal("missing pid in %s", n->sym->name); - return 0; - } + prno = f_pid(n->lft->sym->name); + else + { prno = eval(n->lft->lft); /* pid - can cause recursive call */ +#if 0 + if (n->lft->lft->ntyp == CONST) /* user-guessed pid */ +#endif + { prno += Have_claim; + added = Have_claim; + } } - prno = eval(n->lft->lft); /* pid - can cause recursive call */ -TryAgain: + if (prno < 0) + return 0; /* non-existing process */ +#if 0 + i = nproc - nstop; + for (Y = run; Y; Y = Y->nxt) + { --i; + printf(" %s: i=%d, prno=%d, ->pid=%d\n", Y->n->name, i, prno, Y->pid); + } +#endif i = nproc - nstop; for (Y = run; Y; Y = Y->nxt) if (--i == prno) { if (strcmp(Y->n->name, n->lft->sym->name) != 0) - { if (!trick && Have_claim) - { trick = 1; prno++; - /* assumes user guessed the pid */ - goto TryAgain; - } - printf("spin: remote reference error on '%s[%d]'\n", - n->lft->sym->name, prno-trick); + { printf("spin: remote reference error on '%s[%d]'\n", + n->lft->sym->name, prno-added); non_fatal("refers to wrong proctype '%s'", Y->n->name); } if (strcmp(n->sym->name, "_p") == 0) @@ -890,9 +963,28 @@ /* harmless, can only happen with -t */ return 0; } +#if 1 + /* new 4.0 allow remote variables */ + oX = X; + X = Y; + + onl = n->lft; + n->lft = n->rgt; + + os = n->sym; + n->sym = findloc(n->sym); + + i = getval(n); + + n->sym = os; + n->lft = onl; + X = oX; + return i; +#else break; +#endif } - printf("remote ref: %s[%d] ", n->lft->sym->name, prno-trick); + printf("remote ref: %s[%d] ", n->lft->sym->name, prno-added); non_fatal("%s not found", n->sym->name); printf("have only:\n"); i = nproc - nstop - 1; --- /sys/src/cmd/spin/spin.h Wed Aug 31 04:26:38 2005 +++ /sys/src/cmd/spin/spin.h Wed Aug 31 04:26:37 2005 @@ -1,18 +1,22 @@ /***** spin: spin.h *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + +#ifndef SEEN_SPIN_H +#define SEEN_SPIN_H #include #include #include +#ifndef PC +#endif typedef struct Lextok { unsigned short ntyp; /* node type */ @@ -27,6 +31,13 @@ struct Lextok *lft, *rgt; /* children in parse tree */ } Lextok; +typedef struct Slicer { + Lextok *n; /* global var, usable as slice criterion */ + short code; /* type of use: DEREF_USE or normal USE */ + short used; /* set when handled */ + struct Slicer *nxt; /* linked list */ +} Slicer; + typedef struct Access { struct Symbol *who; /* proctype name of accessor */ struct Symbol *what; /* proctype name of accessed */ @@ -44,18 +55,18 @@ 16=formal par, 32=inline par, 64=treat as if local */ - unsigned char colnr; /* for use with xspin */ - int nbits; /* an optional width specifier */ + unsigned char colnr; /* for use with xspin during simulation */ + int nbits; /* optional width specifier */ int nel; /* 1 if scalar, >1 if array */ int setat; /* last depth value changed */ int *val; /* runtime value(s), initl 0 */ - struct Lextok **Sval; /* values for structures */ + Lextok **Sval; /* values for structures */ int xu; /* exclusive r or w by 1 pid */ struct Symbol *xup[2]; /* xr or xs proctype */ struct Access *access;/* e.g., senders and receives of chan */ - struct Lextok *ini; /* initial value, or chan-def */ - struct Lextok *Slst; /* template for structure if struct */ + Lextok *ini; /* initial value, or chan-def */ + Lextok *Slst; /* template for structure if struct */ struct Symbol *Snm; /* name of the defining struct */ struct Symbol *owner; /* set for names of subfields in typedefs */ struct Symbol *context; /* 0 if global, or procname */ @@ -69,8 +80,8 @@ typedef struct Queue { short qid; /* runtime q index */ - short qlen; /* nr messages stored */ - short nslots, nflds; /* capacity, flds/slot */ + int qlen; /* nr messages stored */ + int nslots, nflds; /* capacity, flds/slot */ int setat; /* last depth value changed */ int *fld_width; /* type of each field */ int *contents; /* the values stored */ @@ -78,26 +89,33 @@ struct Queue *nxt; /* linked list */ } Queue; -typedef struct FSM_use { /* used in pangen5.c - dataflow */ - Symbol *var; - int special; - struct FSM_use *nxt; -} FSM_use; +typedef struct FSM_state { /* used in pangen5.c - dataflow */ + int from; /* state number */ + int seen; /* used for dfs */ + int in; /* nr of incoming edges */ + int cr; /* has reachable 1-relevant successor */ + int scratch; + unsigned long *dom, *mod; /* to mark dominant nodes */ + struct FSM_trans *t; /* outgoing edges */ + struct FSM_trans *p; /* incoming edges, predecessors */ + struct FSM_state *nxt; /* linked list of all states */ +} FSM_state; typedef struct FSM_trans { /* used in pangen5.c - dataflow */ int to; - FSM_use *Val[2]; /* 0=reads, 1=writes */ + short relevant; /* when sliced */ + short round; /* ditto: iteration when marked */ + struct FSM_use *Val[2]; /* 0=reads, 1=writes */ struct Element *step; struct FSM_trans *nxt; } FSM_trans; -typedef struct FSM_state { /* used in pangen5.c - dataflow */ - int from; /* state number */ - int seen; /* used for dfs */ - int in; /* nr of incoming edges */ - FSM_trans *t; /* outgoing edges list */ - struct FSM_state *nxt; /* linked list of all states */ -} FSM_state; +typedef struct FSM_use { /* used in pangen5.c - dataflow */ + Lextok *n; + Symbol *var; + int special; + struct FSM_use *nxt; +} FSM_use; typedef struct Element { Lextok *n; /* defines the type & contents */ @@ -132,7 +150,7 @@ Symbol *s; Symbol *c; Element *e; - int visible; /* label referenced in claim */ + int visible; /* label referenced in claim (slice relevant) */ struct Label *nxt; } Label; @@ -182,11 +200,14 @@ #define Nhash 255 /* slots in symbol hash-table */ -#define XR 1 /* non-shared receive-only */ -#define XS 2 /* non-shared send-only */ -#define XX 4 /* overrides XR or XS tag */ +#define XR 1 /* non-shared receive-only */ +#define XS 2 /* non-shared send-only */ +#define XX 4 /* overrides XR or XS tag */ + +#define CODE_FRAG 2 /* auto-numbered code-fragment */ +#define CODE_DECL 4 /* auto-numbered c_decl */ +#define PREDEF 3 /* predefined name: _p, _last */ -#define PREDEF 3 /* predefined names: _p, _last */ #define UNSIGNED 5 /* val defines width in bits */ #define BIT 1 /* also equal to width in bits */ #define BYTE 8 /* ditto */ @@ -195,6 +216,9 @@ #define CHAN 64 /* not */ #define STRUCT 128 /* user defined structure name */ +#define SOMETHINGBIG 65536 +#define RATHERSMALL 512 + #ifndef max #define max(a,b) (((a)<(b)) ? (b) : (a)) #endif @@ -204,7 +228,7 @@ /***** prototype definitions *****/ Element *eval_sub(Element *); Element *get_lab(Lextok *, int); -Element *huntele(Element *, int); +Element *huntele(Element *, int, int); Element *huntstart(Element *); Element *target(Element *); @@ -214,6 +238,7 @@ Lextok *mk_explicit(Lextok *, int, int); Lextok *nn(Lextok *, int, Lextok *, Lextok *); Lextok *rem_lab(Symbol *, Lextok *, Symbol *); +Lextok *rem_var(Symbol *, Lextok *, Symbol *, Lextok *); Lextok *tail_add(Lextok *, Lextok *); ProcList *ready(Symbol *, Lextok *, Sequence *, int, Lextok *); @@ -223,14 +248,16 @@ Symbol *break_dest(void); Symbol *findloc(Symbol *); -Symbol *lookup(char *); Symbol *has_lab(Element *, int); +Symbol *lookup(char *); +Symbol *prep_inline(Symbol *, Lextok *); char *emalloc(int); long Rand(void); int any_oper(Lextok *, int); int any_undo(Lextok *); +int c_add_sv(FILE *); int cast_val(int, int, int); int checkvar(Symbol *, int); int Cnt_flds(Lextok *); @@ -244,8 +271,11 @@ int full_name(FILE *, Lextok *, Symbol *, int); int getlocal(Lextok *); int getval(Lextok *); +int glob_inline(char *); int has_typ(Lextok *, int); +int in_bound(Symbol *, int); int interprint(FILE *, Lextok *); +int printm(FILE *, Lextok *); int ismtype(char *); int isproctype(char *); int isutype(char *); @@ -253,7 +283,7 @@ int main(int, char **); int pc_value(Lextok *); int proper_enabler(Lextok *); -int putcode(FILE *, Sequence *, Element *, int, int); +int putcode(FILE *, Sequence *, Element *, int, int, int); int q_is_sync(Lextok *); int qlen(Lextok *); int qfull(Lextok *); @@ -273,15 +303,28 @@ int yywrap(void); int yylex(void); +void AST_track(Lextok *, int); void add_seq(Lextok *); void alldone(int); void announce(char *); +void c_state(Symbol *, Symbol *, Symbol *); +void c_add_def(FILE *); +void c_add_loc(FILE *, char *); +void c_add_locinit(FILE *, int, char *); +void c_add_use(FILE *); +void c_chandump(FILE *); +void c_preview(void); +void c_struct(FILE *, char *, Symbol *); +void c_track(Symbol *, Symbol *, Symbol *); +void c_var(FILE *, char *, Symbol *); +void c_wrapper(FILE *); void chanaccess(void); void checkrun(Symbol *, int); void comment(FILE *, Lextok *, int); void cross_dsteps(Lextok *, Lextok *); void doq(Symbol *, int, RunList *); void dotag(FILE *, char *); +void do_locinits(FILE *); void do_var(FILE *, int, char *, Symbol *, char *, char *, char *); void dump_struct(Symbol *, char *, RunList *); void dumpclaims(FILE *, int, char *); @@ -289,27 +332,33 @@ void dumplabels(void); void dumplocal(RunList *); void dumpsrc(int, int); -/* void exit(int); in stdlib.h */ void fatal(char *, char *); void fix_dest(Symbol *, Symbol *); void genaddproc(void); void genaddqueue(void); +void gencodetable(FILE *); void genheader(void); void genother(void); void gensrc(void); void gensvmap(void); void genunio(void); void ini_struct(Symbol *); +void loose_ends(void); void make_atomic(Sequence *, int); void match_trail(void); +void no_side_effects(char *); void nochan_manip(Lextok *, Lextok *, int); void non_fatal(char *, char *); void ntimes(FILE *, int, int, char *c[]); void open_seq(int); void p_talk(Element *, int); void pickup_inline(Symbol *, Lextok *); +void plunk_c_decls(FILE *); +void plunk_c_fcts(FILE *); +void plunk_expr(FILE *, char *); +void plunk_inline(FILE *, char *, int); void prehint(Symbol *); -void prep_inline(Symbol *, Lextok *); +void preruse(FILE *, Lextok *); void prune_opts(Lextok *); void pstext(int, char *); void pushbreak(void); @@ -334,6 +383,7 @@ void start_claim(int); void struct_name(Lextok *, Symbol *, int, char *); void symdump(void); +void symvar(Symbol *); void trackchanuse(Lextok *, Lextok *, int); void trackvar(Lextok *, Lextok *); void trackrun(Lextok *); @@ -347,3 +397,4 @@ void whoruns(int); void wrapup(int); void yyerror(char *, ...); +#endif --- /sys/src/cmd/spin/spin.y Wed Aug 31 04:27:01 2005 +++ /sys/src/cmd/spin/spin.y Wed Aug 31 04:27:00 2005 @@ -1,14 +1,13 @@ /***** spin: spin.y *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ %{ #include "spin.h" @@ -20,6 +19,8 @@ extern Symbol *context, *owner; extern int u_sync, u_async, dumptab; extern short has_sorted, has_random, has_enabled, has_pcvalue, has_np; +extern short has_code, has_state, has_io; +extern void count_runs(Lextok *); extern void validref(Lextok *, Lextok *); extern char yytext[]; @@ -33,7 +34,8 @@ %} -%token ASSERT PRINT +%token ASSERT PRINT PRINTM +%token C_CODE C_DECL C_EXPR C_STATE C_TRACK %token RUN LEN ENABLED EVAL PC_VAL %token TYPEDEF MTYPE INLINE LABEL OF %token GOTO BREAK ELSE SEMI @@ -80,6 +82,7 @@ | events /* event assertions */ | one_decl /* variables, chans */ | utype /* user defined types */ + | c_fcts /* c functions etc. */ | ns /* named sequence */ | SEMI /* optional separator */ | error @@ -121,14 +124,17 @@ | ACTIVE { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 1; } | ACTIVE '[' CONST ']' { $$ = nn(ZN,CONST,ZN,ZN); $$->val = $3->val; + if ($3->val > 255) + non_fatal("max nr of processes is 255\n", ""); } | ACTIVE '[' NAME ']' { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 0; if (!$3->sym->type) - non_fatal("undeclared variable %s", $3->sym->name); + non_fatal("undeclared variable %s", + $3->sym->name); else if ($3->sym->ini->ntyp != CONST) - non_fatal("constant initializer required for %s\n", + non_fatal("need constant initializer for %s\n", $3->sym->name); else $$->val = $3->sym->ini->val; @@ -183,7 +189,63 @@ ; ns : INLINE nm '(' { NamesNotAdded++; } - args ')' { prep_inline($2->sym, $5); NamesNotAdded--; } + args ')' { prep_inline($2->sym, $5); + NamesNotAdded--; + } + ; + +c_fcts : ccode { /* leaves pseudo-inlines with sym of + * type CODE_FRAG or CODE_DECL in global context + */ + } + | cstate + ; + +cstate : C_STATE STRING STRING { + c_state($2->sym, $3->sym, ZS); + has_code = has_state = 1; + } + | C_TRACK STRING STRING { + c_track($2->sym, $3->sym, ZS); + has_code = has_state = 1; + } + | C_STATE STRING STRING STRING { + c_state($2->sym, $3->sym, $4->sym); + has_code = has_state = 1; + } + | C_TRACK STRING STRING STRING { + c_track($2->sym, $3->sym, $4->sym); + has_code = has_state = 1; + } + ; + +ccode : C_CODE { Symbol *s; + NamesNotAdded++; + s = prep_inline(ZS, ZN); + NamesNotAdded--; + $$ = nn(ZN, C_CODE, ZN, ZN); + $$->sym = s; + has_code = 1; + } + | C_DECL { Symbol *s; + NamesNotAdded++; + s = prep_inline(ZS, ZN); + NamesNotAdded--; + s->type = CODE_DECL; + $$ = nn(ZN, C_CODE, ZN, ZN); + $$->sym = s; + has_code = 1; + } + ; +cexpr : C_EXPR { Symbol *s; + NamesNotAdded++; + s = prep_inline(ZS, ZN); + NamesNotAdded--; + $$ = nn(ZN, C_EXPR, ZN, ZN); + $$->sym = s; + no_side_effects(s->name); + has_code = 1; + } ; body : '{' { open_seq(1); } @@ -197,6 +259,8 @@ step : one_decl { $$ = ZN; } | XU vref_lst { setxus($2, $1->val); $$ = ZN; } + | NAME ':' one_decl { fatal("label preceding declaration,", (char *)0); } + | NAME ':' XU { fatal("label predecing xr/xs claim,", 0); } | stmnt { $$ = $1; } | stmnt UNLESS stmnt { $$ = do_unless($1, $3); } ; @@ -269,6 +333,11 @@ vardcl : NAME { $1->sym->nel = 1; $$ = $1; } | NAME ':' CONST { $1->sym->nbits = $3->val; + if ($3->val >= 8*sizeof(long)) + { non_fatal("width-field %s too large", + $1->sym->name); + $3->val = 8*sizeof(long)-1; + } $1->sym->nel = 1; $$ = $1; } | NAME '[' CONST ']' { $1->sym->nel = $3->val; $$ = $1; } @@ -311,12 +380,12 @@ ; Special : varref RCV { Expand_Ok++; } - rargs { Expand_Ok--; + rargs { Expand_Ok--; has_io++; $$ = nn($1, 'r', $1, $4); trackchanuse($4, ZN, 'R'); } | varref SND { Expand_Ok++; } - margs { Expand_Ok--; + margs { Expand_Ok--; has_io++; $$ = nn($1, 's', $1, $4); $$->val=0; trackchanuse($4, ZN, 'S'); } @@ -370,32 +439,35 @@ } | PRINT '(' STRING { realread = 0; } prargs ')' { $$ = nn($3, PRINT, $5, ZN); realread = 1; } - | ASSERT full_expr { $$ = nn(ZN, ASSERT, $2, ZN); } + | PRINTM '(' varref ')' { $$ = nn(ZN, PRINTM, $3, ZN); } + | PRINTM '(' CONST ')' { $$ = nn(ZN, PRINTM, $3, ZN); } + | ASSERT full_expr { $$ = nn(ZN, ASSERT, $2, ZN); AST_track($2, 0); } + | ccode { $$ = $1; } | varref R_RCV { Expand_Ok++; } - rargs { Expand_Ok--; + rargs { Expand_Ok--; has_io++; $$ = nn($1, 'r', $1, $4); $$->val = has_random = 1; trackchanuse($4, ZN, 'R'); } | varref RCV { Expand_Ok++; } - LT rargs GT { Expand_Ok--; + LT rargs GT { Expand_Ok--; has_io++; $$ = nn($1, 'r', $1, $5); $$->val = 2; /* fifo poll */ trackchanuse($5, ZN, 'R'); } | varref R_RCV { Expand_Ok++; } - LT rargs GT { Expand_Ok--; /* rrcv poll */ + LT rargs GT { Expand_Ok--; has_io++; /* rrcv poll */ $$ = nn($1, 'r', $1, $5); $$->val = 3; has_random = 1; trackchanuse($5, ZN, 'R'); } | varref O_SND { Expand_Ok++; } - margs { Expand_Ok--; + margs { Expand_Ok--; has_io++; $$ = nn($1, 's', $1, $4); $$->val = has_sorted = 1; trackchanuse($4, ZN, 'S'); } - | full_expr { $$ = nn(ZN, 'c', $1, ZN); } + | full_expr { $$ = nn(ZN, 'c', $1, ZN); count_runs($$); } | ELSE { $$ = nn(ZN,ELSE,ZN,ZN); } | ATOMIC '{' { open_seq(0); } @@ -485,15 +557,16 @@ has_enabled++; } | varref RCV { Expand_Ok++; } - '[' rargs ']' { Expand_Ok--; + '[' rargs ']' { Expand_Ok--; has_io++; $$ = nn($1, 'R', $1, $5); } | varref R_RCV { Expand_Ok++; } - '[' rargs ']' { Expand_Ok--; + '[' rargs ']' { Expand_Ok--; has_io++; $$ = nn($1, 'R', $1, $5); $$->val = has_random = 1; } | varref { $$ = $1; trapwonly($1, "varref"); } + | cexpr { $$ = $1; } | CONST { $$ = nn(ZN,CONST,ZN,ZN); $$->ismtyp = $1->ismtyp; $$->val = $1->val; @@ -505,8 +578,12 @@ | PC_VAL '(' expr ')' { $$ = nn(ZN, PC_VAL, $3, ZN); has_pcvalue++; } - | PNAME '[' expr ']' '@' - NAME { $$ = rem_lab($1->sym, $3, $6->sym); } + | PNAME '[' expr ']' '@' NAME + { $$ = rem_lab($1->sym, $3, $6->sym); } + | PNAME '[' expr ']' ':' pfld + { $$ = rem_var($1->sym, $3, $6->sym, $6->lft); } + | PNAME '@' NAME { $$ = rem_lab($1->sym, ZN, $3->sym); } + | PNAME ':' pfld { $$ = rem_var($1->sym, ZN, $3->sym, $3->lft); } ; Opt_priority: /* none */ { $$ = ZN; } --- /sys/src/cmd/spin/spinlex.c Wed Aug 31 04:27:26 2005 +++ /sys/src/cmd/spin/spinlex.c Wed Aug 31 04:27:25 2005 @@ -1,14 +1,13 @@ /***** spin: spinlex.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include #include "spin.h" @@ -27,25 +26,38 @@ Lextok *cn; /* contents */ Lextok *params; /* formal pars if any */ char **anms; /* literal text for actual pars */ + char *prec; /* precondition for c_code or c_expr */ int dln, cln; /* def and call linenr */ Symbol *dfn, *cfn; /* def and call filename */ struct IType *nxt; /* linked list */ } IType; +typedef struct C_Added { + Symbol *s; + Symbol *t; + Symbol *ival; + struct C_Added *nxt; +} C_Added; + +extern RunList *X; +extern ProcList *rdy; extern Symbol *Fname; +extern Symbol *context, *owner; extern YYSTYPE yylval; -extern short has_last, terse; -extern int verbose, IArgs; +extern short has_last, has_code; +extern int verbose, IArgs, hastrack, separate; -int lineno = 1, IArgno = 0; -int Inlining = -1; -char *Inliner[MAXINL], IArg_cont[MAXPAR][MAXLEN]; -IType *Inline_stub[MAXINL]; +short has_stack = 0; +int lineno = 1; char yytext[2048]; FILE *yyin, *yyout; -static unsigned char in_comment=0; +static C_Added *c_added, *c_tracked; +static IType *Inline_stub[MAXINL]; static char *ReDiRect; +static char *Inliner[MAXINL], IArg_cont[MAXPAR][MAXLEN]; +static unsigned char in_comment=0; +static int IArgno = 0, Inlining = -1; static int check_name(char *); #if 1 @@ -68,11 +80,40 @@ if (!in_comment) return y; else goto again; } #endif +static int getinline(void); +static void uninline(void); + +#if 1 #define Getchar() ((Inlining<0)?getc(yyin):getinline()) #define Ungetch(c) {if (Inlining<0) ungetc(c,yyin); else uninline(); } -static int getinline(void); -static void uninline(void); +#else + +static int +Getchar(void) +{ int c; + if (Inlining<0) + c = getc(yyin); + else + c = getinline(); +#if 1 + printf("<%c>", c); +#endif + return c; +} + +static void +Ungetch(int c) +{ + if (Inlining<0) + ungetc(c,yyin); + else + uninline(); +#if 1 + printf(""); +#endif +} +#endif static int notquote(int c) @@ -100,7 +141,10 @@ yytext[i++]= (char) first; while (tst(c = Getchar())) - yytext[i++] = c; + { yytext[i++] = c; + if (c == '\\') + yytext[i++] = Getchar(); /* no tst */ + } yytext[i] = '\0'; Ungetch(c); } @@ -119,9 +163,9 @@ static IType *seqnames; static void -def_inline(Symbol *s, int ln, char *ptr, Lextok *nms) +def_inline(Symbol *s, int ln, char *ptr, char *prc, Lextok *nms) { IType *tmp; - char *nw = (char *) emalloc(strlen(ptr)+1); + char *nw = (char *) emalloc((int) strlen(ptr)+1); strcpy(nw, ptr); for (tmp = seqnames; tmp; tmp = tmp->nxt) @@ -138,12 +182,67 @@ tmp->nm = s; tmp->cn = (Lextok *) nw; tmp->params = nms; + if (strlen(prc) > 0) + { tmp->prec = (char *) emalloc((int) strlen(prc)+1); + strcpy(tmp->prec, prc); + } tmp->dln = ln; tmp->dfn = Fname; tmp->nxt = seqnames; seqnames = tmp; } +void +gencodetable(FILE *fd) +{ IType *tmp; + char *q; + int cnt; + + if (separate == 2) return; + + fprintf(fd, "struct {\n"); + fprintf(fd, " char *c; char *t;\n"); + fprintf(fd, "} code_lookup[] = {\n"); + + if (has_code) + for (tmp = seqnames; tmp; tmp = tmp->nxt) + if (tmp->nm->type == CODE_FRAG + || tmp->nm->type == CODE_DECL) + { fprintf(fd, "\t{ \"%s\", ", + tmp->nm->name); + q = (char *) tmp->cn; + + while (*q == '\n' || *q == '\r' || *q == '\\') + q++; + + fprintf(fd, "\""); + cnt = 0; + while (*q && cnt < 1024) /* pangen1.h allows 2048 */ + { switch (*q) { + case '"': + fprintf(fd, "\\\""); + break; + case '%': + fprintf(fd, "%%"); + break; + case '\n': + fprintf(fd, "\\n"); + break; + default: + putc(*q, fd); + break; + } + q++; cnt++; + } + if (*q) fprintf(fd, "..."); + fprintf(fd, "\""); + fprintf(fd, " },\n"); + } + + fprintf(fd, " { (char *) 0, \"\" }\n"); + fprintf(fd, "};\n"); +} + static int iseqname(char *t) { IType *tmp; @@ -191,16 +290,594 @@ Inliner[Inlining]--; } +IType * +find_inline(char *s) +{ IType *tmp; + + for (tmp = seqnames; tmp; tmp = tmp->nxt) + if (!strcmp(s, tmp->nm->name)) + break; + if (!tmp) + fatal("cannot happen, missing inline def %s", s); + return tmp; +} + +void +c_state(Symbol *s, Symbol *t, Symbol *ival) /* name, scope, ival */ +{ C_Added *r; + + r = (C_Added *) emalloc(sizeof(C_Added)); + r->s = s; /* pointer to a data object */ + r->t = t; /* size of object, or "global", or "local proctype_name" */ + r->ival = ival; + r->nxt = c_added; + c_added = r; +} + +void +c_track(Symbol *s, Symbol *t, Symbol *stackonly) /* name, size */ +{ C_Added *r; + + r = (C_Added *) emalloc(sizeof(C_Added)); + r->s = s; + r->t = t; + r->ival = stackonly; /* abuse of name */ + r->nxt = c_tracked; + c_tracked = r; + + if (stackonly != ZS) + { if (strcmp(stackonly->name, "\"Matched\"") == 0) + r->ival = ZS; /* the default */ + else if (strcmp(stackonly->name, "\"UnMatched\"") != 0 + && strcmp(stackonly->name, "\"unMatched\"") != 0 + && strcmp(stackonly->name, "\"StackOnly\"") != 0) + non_fatal("expecting '[Un]Matched', saw %s", stackonly->name); + else + has_stack = 1; + } +} + +char * +jump_etc(char *op) +{ char *p = op; + + /* kludgy - try to get the type separated from the name */ + + while (*p == ' ' || *p == '\t') + p++; /* initial white space */ + while (*p != ' ' && *p != '\t') + p++; /* type name */ + while (*p == ' ' || *p == '\t') + p++; /* white space */ + while (*p == '*') + p++; /* decorations */ + while (*p == ' ' || *p == '\t') + p++; /* white space */ + + if (*p == '\0') + fatal("c_state format (%s)", op); + + if (strchr(p, '[') + && !strchr(p, '{')) + { non_fatal("array initialization error, c_state (%s)", p); + return (char *) 0; + } + + return p; +} + +void +c_add_globinit(FILE *fd) +{ C_Added *r; + char *p, *q; + + fprintf(fd, "void\nglobinit(void)\n{\n"); + for (r = c_added; r; r = r->nxt) + { if (r->ival == ZS) + continue; + + if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0) + { for (q = r->ival->name; *q; q++) + { if (*q == '\"') + *q = ' '; + if (*q == '\\') + *q++ = ' '; /* skip over the next */ + } + p = jump_etc(r->s->name); /* e.g., "int **q" */ + if (p) + fprintf(fd, " now.%s = %s;\n", p, r->ival->name); + + } else + if (strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0) + { for (q = r->ival->name; *q; q++) + { if (*q == '\"') + *q = ' '; + if (*q == '\\') + *q++ = ' '; /* skip over the next */ + } + p = jump_etc(r->s->name); /* e.g., "int **q" */ + if (p) + fprintf(fd, " %s = %s;\n", p, r->ival->name); /* no now. prefix */ + + } } + fprintf(fd, "}\n"); +} + +void +c_add_locinit(FILE *fd, int tpnr, char *pnm) +{ C_Added *r; + char *p, *q, *s; + int frst = 1; + + fprintf(fd, "void\nlocinit%d(int h)\n{\n", tpnr); + for (r = c_added; r; r = r->nxt) + if (r->ival != ZS + && strncmp(r->t->name, " Local", strlen(" Local")) == 0) + { for (q = r->ival->name; *q; q++) + if (*q == '\"') + *q = ' '; + + p = jump_etc(r->s->name); /* e.g., "int **q" */ + + q = r->t->name + strlen(" Local"); + while (*q == ' ' || *q == '\t') + q++; /* process name */ + + s = (char *) emalloc(strlen(q)+1); + strcpy(s, q); + + q = &s[strlen(s)-1]; + while (*q == ' ' || *q == '\t') + *q-- = '\0'; + + if (strcmp(pnm, s) != 0) + continue; + + if (frst) + { fprintf(fd, "\tuchar *this = pptr(h);\n"); + frst = 0; + } + + if (p) + fprintf(fd, " ((P%d *)this)->%s = %s;\n", + tpnr, p, r->ival->name); + + } + fprintf(fd, "}\n"); +} + +/* tracking: + 1. for non-global and non-local c_state decls: add up all the sizes in c_added + 2. add a global char array of that size into now + 3. generate a routine that memcpy's the required values into that array + 4. generate a call to that routine + */ + +void +c_preview(void) +{ C_Added *r; + + hastrack = 0; + if (c_tracked) + hastrack = 1; + else + for (r = c_added; r; r = r->nxt) + if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0 + && strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0 + && strncmp(r->t->name, " Local", strlen(" Local")) != 0) + { hastrack = 1; /* c_state variant now obsolete */ + break; + } +} + +int +c_add_sv(FILE *fd) /* 1+2 -- called in pangen1.c */ +{ C_Added *r; + int cnt = 0; + + if (!c_added && !c_tracked) return 0; + + for (r = c_added; r; r = r->nxt) /* pickup global decls */ + if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0) + fprintf(fd, " %s;\n", r->s->name); + + for (r = c_added; r; r = r->nxt) + if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0 + && strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0 + && strncmp(r->t->name, " Local", strlen(" Local")) != 0) + { cnt++; /* obsolete use */ + } + + for (r = c_tracked; r; r = r->nxt) + cnt++; /* preferred use */ + + if (cnt == 0) return 0; + + cnt = 0; + fprintf(fd, " uchar c_state["); + for (r = c_added; r; r = r->nxt) + if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0 + && strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0 + && strncmp(r->t->name, " Local", strlen(" Local")) != 0) + { fprintf(fd, "%ssizeof(%s)", + (cnt==0)?"":"+", r->t->name); + cnt++; + } + + for (r = c_tracked; r; r = r->nxt) + { if (r->ival != ZS) continue; + + fprintf(fd, "%s%s", + (cnt==0)?"":"+", r->t->name); + cnt++; + } + + if (cnt == 0) fprintf(fd, "4"); /* now redundant */ + fprintf(fd, "];\n"); + return 1; +} + +void +c_add_stack(FILE *fd) +{ C_Added *r; + int cnt = 0; + + if ((!c_added && !c_tracked) || !has_stack) return; + + + for (r = c_tracked; r; r = r->nxt) + if (r->ival != ZS) + cnt++; + + if (cnt == 0) return; + + fprintf(fd, " uchar c_stack["); + + cnt = 0; + for (r = c_tracked; r; r = r->nxt) + { if (r->ival == ZS) continue; + + fprintf(fd, "%s%s", + (cnt==0)?"":"+", r->t->name); + cnt++; + } + + if (cnt == 0) fprintf(fd, "4"); /* can't happen */ + fprintf(fd, "];\n"); +} + +void +c_add_hidden(FILE *fd) +{ C_Added *r; + + for (r = c_added; r; r = r->nxt) /* pickup hidden decls */ + if (strncmp(r->t->name, "\"Hidden\"", strlen("\"Hidden\"")) == 0) + { r->s->name[strlen(r->s->name)-1] = ' '; + fprintf(fd, "%s; /* Hidden */\n", &r->s->name[1]); + r->s->name[strlen(r->s->name)-1] = '"'; + } + /* called before c_add_def - quotes are still there */ +} + +void +c_add_loc(FILE *fd, char *s) /* state vector entries for proctype s */ +{ C_Added *r; + static char buf[1024]; + char *p; + + if (!c_added) return; + + strcpy(buf, s); + strcat(buf, " "); + for (r = c_added; r; r = r->nxt) /* pickup local decls */ + if (strncmp(r->t->name, " Local", strlen(" Local")) == 0) + { p = r->t->name + strlen(" Local"); + while (*p == ' ' || *p == '\t') + p++; + if (strcmp(p, buf) == 0) + fprintf(fd, " %s;\n", r->s->name); + } +} +void +c_add_def(FILE *fd) /* 3 - called in plunk_c_fcts() */ +{ C_Added *r; + + fprintf(fd, "#if defined(C_States) && defined(HAS_TRACK)\n"); + for (r = c_added; r; r = r->nxt) + { r->s->name[strlen(r->s->name)-1] = ' '; + r->s->name[0] = ' '; /* remove the "s */ + + r->t->name[strlen(r->t->name)-1] = ' '; + r->t->name[0] = ' '; + + if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0 + || strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0 + || strncmp(r->t->name, " Local", strlen(" Local")) == 0) + continue; + + if (strchr(r->s->name, '&')) + fatal("dereferencing state object: %s", r->s->name); + + fprintf(fd, "extern %s %s;\n", r->t->name, r->s->name); + } + for (r = c_tracked; r; r = r->nxt) + { r->s->name[strlen(r->s->name)-1] = ' '; + r->s->name[0] = ' '; /* remove " */ + + r->t->name[strlen(r->t->name)-1] = ' '; + r->t->name[0] = ' '; + } + + if (separate == 2) + { fprintf(fd, "#endif\n"); + return; + } + + if (has_stack) + { fprintf(fd, "void\nc_stack(char *p_t_r)\n{\n"); + fprintf(fd, "#ifdef VERBOSE\n"); + fprintf(fd, " printf(\"c_stack %%u\\n\", p_t_r);\n"); + fprintf(fd, "#endif\n"); + for (r = c_tracked; r; r = r->nxt) + { if (r->ival == ZS) continue; + + fprintf(fd, "\tif(%s)\n", r->s->name); + fprintf(fd, "\t\tmemcpy(p_t_r, %s, %s);\n", + r->s->name, r->t->name); + fprintf(fd, "\telse\n"); + fprintf(fd, "\t\tmemset(p_t_r, 0, %s);\n", + r->t->name); + fprintf(fd, "\tp_t_r += %s;\n", r->t->name); + } + fprintf(fd, "}\n\n"); + } + + fprintf(fd, "void\nc_update(char *p_t_r)\n{\n"); + fprintf(fd, "#ifdef VERBOSE\n"); + fprintf(fd, " printf(\"c_update %%u\\n\", p_t_r);\n"); + fprintf(fd, "#endif\n"); + for (r = c_added; r; r = r->nxt) + { if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0 + || strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0 + || strncmp(r->t->name, " Local", strlen(" Local")) == 0) + continue; + + fprintf(fd, "\tmemcpy(p_t_r, &%s, sizeof(%s));\n", + r->s->name, r->t->name); + fprintf(fd, "\tp_t_r += sizeof(%s);\n", r->t->name); + } + + for (r = c_tracked; r; r = r->nxt) + { if (r->ival) continue; + + fprintf(fd, "\tif(%s)\n", r->s->name); + fprintf(fd, "\t\tmemcpy(p_t_r, %s, %s);\n", + r->s->name, r->t->name); + fprintf(fd, "\telse\n"); + fprintf(fd, "\t\tmemset(p_t_r, 0, %s);\n", + r->t->name); + fprintf(fd, "\tp_t_r += %s;\n", r->t->name); + } + + fprintf(fd, "}\n"); + + if (has_stack) + { fprintf(fd, "void\nc_unstack(char *p_t_r)\n{\n"); + fprintf(fd, "#ifdef VERBOSE\n"); + fprintf(fd, " printf(\"c_unstack %%u\\n\", p_t_r);\n"); + fprintf(fd, "#endif\n"); + for (r = c_tracked; r; r = r->nxt) + { if (r->ival == ZS) continue; + + fprintf(fd, "\tif(%s)\n", r->s->name); + fprintf(fd, "\t\tmemcpy(%s, p_t_r, %s);\n", + r->s->name, r->t->name); + fprintf(fd, "\tp_t_r += %s;\n", r->t->name); + } + fprintf(fd, "}\n"); + } + + fprintf(fd, "void\nc_revert(char *p_t_r)\n{\n"); + fprintf(fd, "#ifdef VERBOSE\n"); + fprintf(fd, " printf(\"c_revert %%u\\n\", p_t_r);\n"); + fprintf(fd, "#endif\n"); + for (r = c_added; r; r = r->nxt) + { if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0 + || strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0 + || strncmp(r->t->name, " Local", strlen(" Local")) == 0) + continue; + + fprintf(fd, "\tmemcpy(&%s, p_t_r, sizeof(%s));\n", + r->s->name, r->t->name); + fprintf(fd, "\tp_t_r += sizeof(%s);\n", r->t->name); + } + for (r = c_tracked; r; r = r->nxt) + { if (r->ival != ZS) continue; + + fprintf(fd, "\tif(%s)\n", r->s->name); + fprintf(fd, "\t\tmemcpy(%s, p_t_r, %s);\n", + r->s->name, r->t->name); + fprintf(fd, "\tp_t_r += %s;\n", r->t->name); + } + + fprintf(fd, "}\n"); + fprintf(fd, "#endif\n"); +} + +void +plunk_reverse(FILE *fd, IType *p, int matchthis) +{ char *y, *z; + + if (!p) return; + plunk_reverse(fd, p->nxt, matchthis); + + if (!p->nm->context + && p->nm->type == matchthis) + { fprintf(fd, "\n/* start of %s */\n", p->nm->name); + z = (char *) p->cn; + while (*z == '\n' || *z == '\r' || *z == '\\') + z++; + /* e.g.: \#include "..." */ + + y = z; + while ((y = strstr(y, "\\#")) != NULL) + { *y = '\n'; y++; + } + + fprintf(fd, "%s\n", z); + fprintf(fd, "\n/* end of %s */\n", p->nm->name); + } +} + +void +plunk_c_decls(FILE *fd) +{ + plunk_reverse(fd, seqnames, CODE_DECL); +} + +void +plunk_c_fcts(FILE *fd) +{ + if (separate == 2 && hastrack) + { c_add_def(fd); + return; + } + + c_add_hidden(fd); + plunk_reverse(fd, seqnames, CODE_FRAG); + + if (c_added || c_tracked) /* enables calls to c_revert and c_update */ + fprintf(fd, "#define C_States 1\n"); + else + fprintf(fd, "#undef C_States\n"); + + if (hastrack) + c_add_def(fd); + + c_add_globinit(fd); + do_locinits(fd); +} + +static void +check_inline(IType *tmp) +{ char buf[128]; + ProcList *p; + + if (!X) return; + + for (p = rdy; p; p = p->nxt) + { if (strcmp(p->n->name, X->n->name) == 0) + continue; + sprintf(buf, "P%s->", p->n->name); + if (strstr((char *)tmp->cn, buf)) + { printf("spin: in proctype %s, ref to object in proctype %s\n", + X->n->name, p->n->name); + fatal("invalid variable ref in '%s'", tmp->nm->name); + } } +} + +void +plunk_expr(FILE *fd, char *s) +{ IType *tmp; + + tmp = find_inline(s); + check_inline(tmp); + + fprintf(fd, "%s", (char *) tmp->cn); +} + +void +preruse(FILE *fd, Lextok *n) /* check a condition for c_expr with preconditions */ +{ IType *tmp; + + if (!n) return; + if (n->ntyp == C_EXPR) + { tmp = find_inline(n->sym->name); + if (tmp->prec) + { fprintf(fd, "if (!(%s)) { if (!readtrail) { depth++; ", tmp->prec); + fprintf(fd, "trpt++; trpt->pr = II; trpt->o_t = t;"); + fprintf(fd, "trpt->st = tt; Uerror(\"%s\"); } ", tmp->prec); + fprintf(fd, "else { printf(\"pan: precondition false: %s\\n\"); ", tmp->prec); + fprintf(fd, "_m = 3; goto P999; } } \n\t\t"); + } + } else + { preruse(fd, n->rgt); + preruse(fd, n->lft); + } +} + +int +glob_inline(char *s) +{ IType *tmp; + char *bdy; + + tmp = find_inline(s); + bdy = (char *) tmp->cn; + return (strstr(bdy, "now.") /* global ref or */ + || strchr(bdy, '(') > bdy); /* possible C-function call */ +} + +void +plunk_inline(FILE *fd, char *s, int how) /* c_code with precondition */ +{ IType *tmp; + + tmp = find_inline(s); + check_inline(tmp); + + fprintf(fd, "{ "); + if (how && tmp->prec) + { fprintf(fd, "if (!(%s)) { if (!readtrail) { depth++; ", tmp->prec); + fprintf(fd, "trpt++; trpt->pr = II; trpt->o_t = t;"); + fprintf(fd, "trpt->st = tt; Uerror(\"%s\"); } ", tmp->prec); + fprintf(fd, "else { printf(\"pan: precondition false: %s\\n\"); ", tmp->prec); + fprintf(fd, "_m = 3; goto P999; } } "); + } + fprintf(fd, "%s", (char *) tmp->cn); + fprintf(fd, " }\n"); +} + +void +no_side_effects(char *s) +{ IType *tmp; + char *t; + + /* could still defeat this check via hidden + * side effects in function calls, + * but this will catch at least some cases + */ + + tmp = find_inline(s); + t = (char *) tmp->cn; + + if (strchr(t, ';') + || strstr(t, "++") + || strstr(t, "--")) + { +bad: lineno = tmp->dln; + Fname = tmp->dfn; + non_fatal("c_expr %s has side-effects", s); + return; + } + while ((t = strchr(t, '=')) != NULL) + { if (*(t-1) == '!' + || *(t-1) == '>' + || *(t-1) == '<') + { t++; + continue; + } + t++; + if (*t != '=') + goto bad; + t++; + } +} + void pickup_inline(Symbol *t, Lextok *apars) { IType *tmp; Lextok *p, *q; int j; - for (tmp = seqnames; tmp; tmp = tmp->nxt) - if (!strcmp(t->name, tmp->nm->name)) - break; + tmp = find_inline(t->name); - if (!tmp) - fatal("cannot happen, ns %s", t->name); if (++Inlining >= MAXINL) fatal("inline fcts too deeply nested", 0); @@ -214,7 +891,7 @@ tmp->anms = (char **) emalloc(j * sizeof(char *)); for (p = apars, j = 0; p; p = p->rgt, j++) - { tmp->anms[j] = (char *) emalloc(strlen(IArg_cont[j])+1); + { tmp->anms[j] = (char *) emalloc((int) strlen(IArg_cont[j])+1); strcpy(tmp->anms[j], IArg_cont[j]); } @@ -233,11 +910,14 @@ } static void -do_directive(int first, int fromwhere) +do_directive(int first) { int c = first; /* handles lines starting with pound */ getword(c, isalpha_); + if (strcmp(yytext, "#ident") == 0) + goto done; + if ((c = Getchar()) != ' ') fatal("malformed preprocessor directive - # .", 0); @@ -262,17 +942,42 @@ strcat(yytext, "\""); Fname = lookup(yytext); +done: while (Getchar() != '\n') ; } -#define SOMETHINGBIG 65536 - void +precondition(char *q) +{ int c, nest = 1; + + for (;;) + { c = Getchar(); + *q++ = c; + switch (c) { + case '\n': + lineno++; + break; + case '[': + nest++; + break; + case ']': + if (--nest <= 0) + { *--q = '\0'; + return; + } + break; + } + } + fatal("cannot happen", (char *) 0); +} + +Symbol * prep_inline(Symbol *s, Lextok *nms) { int c, nest = 1, dln, firstchar, cnr; - char *p, buf[SOMETHINGBIG]; + char *p, buf[SOMETHINGBIG], buf2[RATHERSMALL]; Lextok *t; + static int c_code = 1; for (t = nms; t; t = t->rgt) if (t->lft) @@ -280,12 +985,26 @@ fatal("bad param to inline %s", s->name); t->lft->sym->hidden |= 32; } - - s->type = PREDEF; + + if (!s) /* C_Code fragment */ + { s = (Symbol *) emalloc(sizeof(Symbol)); + s->name = (char *) emalloc((int) strlen("c_code")+26); + sprintf(s->name, "c_code%d", c_code++); + s->context = context; + s->type = CODE_FRAG; + } else + s->type = PREDEF; + p = &buf[0]; + buf2[0] = '\0'; for (;;) { c = Getchar(); switch (c) { + case '[': + if (s->type != CODE_FRAG) + goto bad; + precondition(&buf2[0]); /* e.g., c_code [p] { r = p-r; } */ + continue; case '{': break; case '\n': @@ -293,12 +1012,21 @@ /* fall through */ case ' ': case '\t': case '\f': case '\r': continue; - default : fatal("bad inline: %s", s->name); + default : + printf("spin: saw char '%c'\n", c); +bad: fatal("bad inline: %s", s->name); } break; } dln = lineno; - sprintf(buf, "\n#line %d %s\n{", lineno, Fname->name); + if (s->type == CODE_FRAG) + { if (verbose&32) + sprintf(buf, "\t/* line %d %s */\n\t\t", + lineno, Fname->name); + else + strcpy(buf, ""); + } else + sprintf(buf, "\n#line %d %s\n{", lineno, Fname->name); p += strlen(buf); firstchar = 1; @@ -320,16 +1048,19 @@ cnr++; if (--nest <= 0) { *p = '\0'; - def_inline(s, dln, &buf[0], nms); - if (firstchar) - fatal("empty inline definition '%s'", s->name); - return; + if (s->type == CODE_FRAG) + *--p = '\0'; /* remove trailing '}' */ + def_inline(s, dln, &buf[0], &buf2[0], nms); + if (firstchar && s) + printf("%3d: %s, warning: empty inline definition (%s)\n", + dln, Fname->name, s->name); + return s; /* normal return */ } break; case '#': if (cnr == 0) { p--; - do_directive(c, 4); /* reads to newline */ + do_directive(c); /* reads to newline */ break; } /* else fall through */ default: @@ -362,7 +1093,7 @@ case '#': /* preprocessor directive */ if (in_comment) goto again; - do_directive(c, 5); + do_directive(c); goto again; case '\"': @@ -381,8 +1112,8 @@ else if (c == 't') c = '\t'; else if (c == 'f') c = '\f'; } - if (Getchar() != '\'') - fatal("character quote missing", yytext); + if (Getchar() != '\'' && !in_comment) + fatal("character quote missing: %s", yytext); ValToken(c, CONST) default: @@ -437,6 +1168,11 @@ {"bool", TYPE, BIT, 0}, {"break", BREAK, 0, 0}, {"byte", TYPE, BYTE, 0}, + {"c_code", C_CODE, 0, 0}, + {"c_decl", C_DECL, 0, 0}, + {"c_expr", C_EXPR, 0, 0}, + {"c_state", C_STATE, 0, 0}, + {"c_track", C_TRACK, 0, 0}, {"D_proctype", D_PROCTYPE, 0, 0}, {"do", DO, 0, 0}, {"chan", TYPE, CHAN, 0}, @@ -452,8 +1188,8 @@ {"if", IF, 0, 0}, {"init", INIT, 0, ":init:"}, {"int", TYPE, INT, 0}, - {"local", ISLOCAL, 0, ":local:"}, {"len", LEN, 0, 0}, + {"local", ISLOCAL, 0, ":local:"}, {"mtype", TYPE, MTYPE, 0}, {"nempty", NEMPTY, 0, 0}, {"never", CLAIM, 0, ":never:"}, @@ -463,7 +1199,9 @@ {"od", OD, 0, 0}, {"of", OF, 0, 0}, {"pc_value", PC_VAL, 0, 0}, + {"pid", TYPE, BYTE, 0}, {"printf", PRINT, 0, 0}, + {"printm", PRINTM, 0, 0}, {"priority", PRIORITY, 0, 0}, {"proctype", PROCTYPE, 0, 0}, {"provided", PROVIDED, 0, 0}, @@ -486,7 +1224,7 @@ static int check_name(char *s) -{ register int i; +{ int i; yylval = nn(ZN, 0, ZN, ZN); for (i = 0; Names[i].s; i++) @@ -497,7 +1235,7 @@ return Names[i].tok; } - if (yylval->val = ismtype(s)) + if ((yylval->val = ismtype(s)) != 0) { yylval->ismtyp = 1; return CONST; } @@ -507,9 +1245,10 @@ if (Inlining >= 0 && !ReDiRect) { Lextok *tt, *t = Inline_stub[Inlining]->params; - for (i = 0; t; t = t->rgt, i++) - if (!strcmp(s, t->lft->sym->name) - && strcmp(s, Inline_stub[Inlining]->anms[i]) != 0) + + for (i = 0; t; t = t->rgt, i++) /* formal pars */ + if (!strcmp(s, t->lft->sym->name) /* varname matches formal */ + && strcmp(s, Inline_stub[Inlining]->anms[i]) != 0) /* actual pars */ { #if 0 if (verbose&32) @@ -518,15 +1257,19 @@ Inline_stub[Inlining]->nm->name, Inline_stub[Inlining]->anms[i]); #endif - tt = Inline_stub[Inlining]->params; - for ( ; tt; tt = tt->rgt) - if (!strcmp(Inline_stub[Inlining]->anms[i], - tt->lft->sym->name)) - { /* would be cyclic if not caught */ - yylval->ntyp = tt->lft->ntyp; - yylval->sym = lookup(tt->lft->sym->name); - return NAME; - } + + for (tt = Inline_stub[Inlining]->params; tt; tt = tt->rgt) + if (!strcmp(Inline_stub[Inlining]->anms[i], + tt->lft->sym->name)) + { /* would be cyclic if not caught */ + printf("spin: line %d replacement value: %s\n", + lineno, tt->lft->sym->name); + fatal("formal par of %s matches replacement value", + Inline_stub[Inlining]->nm->name); + yylval->ntyp = tt->lft->ntyp; + yylval->sym = lookup(tt->lft->sym->name); + return NAME; + } ReDiRect = Inline_stub[Inlining]->anms[i]; return 0; } } @@ -579,8 +1322,7 @@ return SEMI; /* insert ';' */ } if (c == SEMI) - { extern Symbol *context, *owner; - /* if context, we're not in a typedef + { /* if context, we're not in a typedef * because they're global. * if owner, we're at the end of a ref * to a struct field -- prevent that the @@ -600,17 +1342,24 @@ if (IArgs) { static int IArg_nst = 0; + if (strcmp(yytext, ",") == 0) { IArg_cont[++IArgno][0] = '\0'; } else if (strcmp(yytext, "(") == 0) { if (IArg_nst++ == 0) { IArgno = 0; IArg_cont[0][0] = '\0'; - } + } else + strcat(IArg_cont[IArgno], yytext); } else if (strcmp(yytext, ")") == 0) - { IArg_nst--; - } else + { if (--IArg_nst > 0) + strcat(IArg_cont[IArgno], yytext); + } else if (c == CONST && yytext[0] == '\'') + { sprintf(yytext, "'%c'", yylval->val); strcat(IArg_cont[IArgno], yytext); + } else + { strcat(IArg_cont[IArgno], yytext); + } } return c; --- /sys/src/cmd/spin/structs.c Wed Aug 31 04:27:51 2005 +++ /sys/src/cmd/spin/structs.c Wed Aug 31 04:27:50 2005 @@ -1,14 +1,13 @@ /***** spin: structs.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" #ifdef PC @@ -23,8 +22,6 @@ struct UType *nxt; /* linked list */ } UType; -extern Symbol *context; -extern RunList *X; extern Symbol *Fname; extern int lineno, depth, Expand_Ok; @@ -254,7 +251,7 @@ for (tl = fp->lft; tl; tl = tl->rgt) { if (tl->sym->type == STRUCT) { if (tl->sym->nel != 1) - fatal("hidden array in parameter, %s", + fatal("array of structures in param list, %s", tl->sym->name); cnt += Cnt_flds(tl->sym->Slst); } else @@ -275,7 +272,7 @@ if (!t->rgt || !t->rgt->ntyp == '.' || !t->rgt->lft) - fatal("unexpected struct layout %s", s->name); + return STRUCT; /* not a field reference */ return Sym_typ(t->rgt->lft); } @@ -386,7 +383,7 @@ struct_name(Lextok *n, Symbol *v, int xinit, char *buf) { Symbol *tl; Lextok *tmp; - char lbuf[128]; + char lbuf[512]; if (!n || !(tl = do_same(n, v, xinit))) return; @@ -448,9 +445,36 @@ } void +c_struct(FILE *fd, char *ipref, Symbol *z) +{ Lextok *fp, *tl; + char pref[256], eprefix[256]; + int ix; + + ini_struct(z); + + for (ix = 0; ix < z->nel; ix++) + for (fp = z->Sval[ix]; fp; fp = fp->rgt) + for (tl = fp->lft; tl; tl = tl->rgt) + { strcpy(eprefix, ipref); + if (z->nel > 1) + { /* insert index before last '.' */ + eprefix[strlen(eprefix)-1] = '\0'; + sprintf(pref, "[ %d ].", ix); + strcat(eprefix, pref); + } + if (tl->sym->type == STRUCT) + { strcat(eprefix, tl->sym->name); + strcat(eprefix, "."); + c_struct(fd, eprefix, tl->sym); + } else + c_var(fd, eprefix, tl->sym); + } +} + +void dump_struct(Symbol *z, char *prefix, RunList *r) { Lextok *fp, *tl; - char eprefix[128]; + char eprefix[256]; int ix, jx; ini_struct(z); @@ -464,7 +488,7 @@ for (fp = z->Sval[ix]; fp; fp = fp->rgt) for (tl = fp->lft; tl; tl = tl->rgt) { if (tl->sym->type == STRUCT) - { char pref[128]; + { char pref[256]; strcpy(pref, eprefix); strcat(pref, "."); strcat(pref, tl->sym->name); @@ -561,6 +585,22 @@ if (n->sym->type != STRUCT || is_explicit(n)) return n; + + if (n->rgt + && n->rgt->ntyp == '.' + && n->rgt->lft + && n->rgt->lft->sym + && n->rgt->lft->sym->type == STRUCT) + { Lextok *y; + bld = mk_explicit(n->rgt->lft, Ok, Ntyp); + for (x = bld; x; x = x->rgt) + { y = cpnn(n, 1, 0, 0); + y->rgt = nn(ZN, '.', x->lft, ZN); + x->lft = y; + } + + return bld; + } if (!Ok || !n->sym->Slst) { if (IArgs) return n; --- /sys/src/cmd/spin/sym.c Wed Aug 31 04:28:18 2005 +++ /sys/src/cmd/spin/sym.c Wed Aug 31 04:28:16 2005 @@ -1,14 +1,13 @@ /***** spin: sym.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" #ifdef PC @@ -68,7 +67,7 @@ return sp; /* global */ sp = (Symbol *) emalloc(sizeof(Symbol)); - sp->name = (char *) emalloc(strlen(s) + 1); + sp->name = (char *) emalloc((int) strlen(s) + 1); strcpy(sp->name, s); sp->nel = 1; sp->setat = depth; @@ -155,7 +154,7 @@ { if (!(verbose&32)) return; strcpy(buf2, (!(res&4))?"bit":"byte"); sputtype(buf, parnm->type); - i = strlen(buf); + i = (int) strlen(buf); while (buf[--i] == ' ') buf[i] = '\0'; if (strcmp(buf, buf2) == 0) return; prehint(parnm); @@ -331,7 +330,8 @@ n->lft->sym->ini = nn(ZN,CONST,ZN,ZN); n->lft->sym->ini->val = cnt; } else if (n->lft->sym->ini->val != cnt) - fatal("cannot happen: setmtype", (char *) 0); + non_fatal("name %s appears twice in mtype declaration", + n->lft->sym->name); } lineno = oln; if (cnt > 256) @@ -382,7 +382,7 @@ return 0; } -static void +void symvar(Symbol *sp) { Lextok *m; @@ -402,10 +402,10 @@ printf("\t%d", eval(sp->ini)); if (sp->owner) - printf("\t"); + printf("\t<:struct-field:>"); else if (!sp->context) - printf("\t"); + printf("\t<:global:>"); else printf("\t<%s>", sp->context->name); @@ -419,7 +419,10 @@ i++; printf("\t%d\t", i); for (m = sp->ini->rgt; m; m = m->rgt) - { (void) puttype(m->ntyp); + { if (m->ntyp == STRUCT) + printf("struct %s", m->sym->name); + else + (void) puttype(m->ntyp); if (m->rgt) printf("\t"); } } @@ -496,6 +499,7 @@ { Ordered *walk; char buf[128]; extern int Caccess, separate; + extern short has_code; for (walk = all_names; walk; walk = walk->next) { if (!walk->entry->owner) @@ -512,10 +516,13 @@ if ((walk->entry->hidden&32)) continue; - if (!separate && !walk->entry->context && deadvar) + if (!separate + && !walk->entry->context + && !has_code + && deadvar) walk->entry->hidden |= 1; /* auto-hide */ - if (!(verbose&32)) continue; + if (!(verbose&32) || has_code) continue; printf("spin: warning, %s, ", Fname->name); sputtype(buf, walk->entry->type); @@ -526,6 +533,5 @@ printf("global"); printf(", '%s%s' variable is never used\n", buf, walk->entry->name); - } - } + } } } --- /sys/src/cmd/spin/tl.h Wed Aug 31 04:28:43 2005 +++ /sys/src/cmd/spin/tl.h Wed Aug 31 04:28:42 2005 @@ -1,14 +1,16 @@ /***** tl_spin: tl.h *****/ -/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ #include #include --- /sys/src/cmd/spin/tl_buchi.c Wed Aug 31 04:29:11 2005 +++ /sys/src/cmd/spin/tl_buchi.c Wed Aug 31 04:29:09 2005 @@ -1,14 +1,16 @@ /***** tl_spin: tl_buchi.c *****/ -/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ #include "tl.h" @@ -77,12 +79,6 @@ if (!p->rgt) return p->lft; return p; -#if 0 -/* 3.3.9 */ - case V_OPER: - releasenode(1, p->lft); - return Prune(p->rgt); -#endif } releasenode(1, p); return ZN; @@ -118,7 +114,7 @@ b->reachable = 1; if (b->redundant) - printf("spin: internal error, Dfs hits redundant state %s\n", + printf("/* redundant state %s */\n", b->name->name); for (t = b->trans; t; t = t->nxt) { if (!t->redundant) @@ -140,12 +136,8 @@ for (b = never; b; b = b->nxt) { if (!strcmp(b->name->name, from)) - { b->redundant = 1; - for (t = b->trans; t; t = t->nxt) - { /* releasenode(1, t->cond); */ - t->cond = ZN; - } - } else + b->redundant = 1; + else for (t = b->trans; t; t = t->nxt) { if (!strcmp(t->name->name, from)) t->name = To; @@ -189,7 +181,7 @@ #ifdef NXT Node *a = nonxt(s); Node *b = nonxt(t); -#if 1 + if (tl_verbose) { printf("\tnonxtA: "); dump(a); printf("\n\tnonxtB: "); dump(b); @@ -201,22 +193,6 @@ else nc = tl_nn(OR, a, b); #else - if (!a) - { releasenode(1, s); - if (!b) - { releasenode(1, t); - nc = False; - } else - { nc = b; - } - } else if (!b) - { releasenode(1, t); - nc = a; - } else - { nc = tl_nn(OR, a, b); - } -#endif -#else nc = tl_nn(OR, s, t); #endif if (tl_verbose) @@ -309,7 +285,7 @@ } static int -mergetrans(int v) +mergetrans(void) { State *b; Transition *s, *t; Node *nc; int cnt = 0; @@ -389,7 +365,11 @@ s->marked = 0; return result; } + +#ifndef NO_OPT #define BUCKY +#endif + #ifdef BUCKY static int all_bucky(State *a, State *b) @@ -477,7 +457,12 @@ } if (a->accepting && !b->accepting) - { c = b; d = a; + { if (strcmp(b->name->name, "T0_init") == 0) + { c = a; d = b; + b->accepting = 1; + } else + { c = b; d = a; + } } else { c = a; d = b; } @@ -501,10 +486,10 @@ mergestates(int v) { State *a, *b; int m, cnt=0; -#if 1 + if (tl_verbose) return 0; -#endif + do { m = 0; cnt++; for (a = never; a; a = a->nxt) @@ -538,7 +523,8 @@ #if 0 else if (tl_verbose) { printf("\n%d: state %s differs from state %s [%d,%d]\n", - cnt, a->name->name, b->name->name, a->accepting, b->accepting); + cnt, a->name->name, b->name->name, + a->accepting, b->accepting); showtrans(a); printf("==\n"); showtrans(b); @@ -574,6 +560,12 @@ b->reachable = 0; /* print only once */ fprintf(tl_out, "%s:\n", b->name->name); + if (tl_verbose) + { fprintf(tl_out, " /* "); + dump(b->colors->Other); + fprintf(tl_out, " */\n"); + } + if (strncmp(b->name->name, "accept", 6) == 0 && Max_Red == 0) fprintf(tl_out, "T0%s:\n", &(b->name->name[6])); @@ -595,11 +587,11 @@ t->name = tl_lookup(to); t->cond = Prune(dupnode(op)); -if (tl_verbose) -{ printf("\n<<\t"); dump(op); - printf("\n\t"); dump(t->cond); - printf(">> %s\n", t->name->name); -} + if (tl_verbose) + { printf("\n%s <<\t", from); dump(op); + printf("\n\t"); dump(t->cond); + printf(">> %s\n", t->name->name); + } if (t->cond) t->cond = rewrite(t->cond); for (b = never; b; b = b->nxt) @@ -647,7 +639,7 @@ do { clr_reach(); Dfs(b); - cnt1 = mergetrans(1); + cnt1 = mergetrans(); cnt2 = mergestates(1); if (tl_verbose) printf("/* >>%d,%d<< */\n", cnt1, cnt2); @@ -658,7 +650,7 @@ clr_reach(); Dfs(b); #endif - if (Max_Red == 0) + if (b && b->accepting) fprintf(tl_out, "accept_init:\n"); if (!b && !never) --- /sys/src/cmd/spin/tl_cache.c Wed Aug 31 04:29:38 2005 +++ /sys/src/cmd/spin/tl_cache.c Wed Aug 31 04:29:37 2005 @@ -1,14 +1,16 @@ /***** tl_spin: tl_cache.c *****/ -/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ #include "tl.h" @@ -26,6 +28,7 @@ extern void fatal(char *, char *); int sameform(Node *, Node *); +#if 0 void cache_dump(void) { Cache *d; int nr=0; @@ -38,6 +41,7 @@ } printf("============\n"); } +#endif Node * in_cache(Node *n) @@ -58,7 +62,7 @@ Node *m; if (!n) return n; - if (m = in_cache(n)) + if ((m = in_cache(n)) != ZN) return m; Caches++; --- /sys/src/cmd/spin/tl_lex.c Wed Aug 31 04:30:07 2005 +++ /sys/src/cmd/spin/tl_lex.c Wed Aug 31 04:30:06 2005 @@ -1,14 +1,16 @@ /***** tl_spin: tl_lex.c *****/ -/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ #include #include @@ -23,7 +25,7 @@ #define Token(y) tl_yylval = tl_nn(y,ZN,ZN); return y static void -getword(int first, int (*tst)(int)) +tl_getword(int first, int (*tst)(int)) { int i=0; char c; yytext[i++]= (char ) first; @@ -34,7 +36,7 @@ } static int -follow(int tok, int ifyes, int ifno) +tl_follow(int tok, int ifyes, int ifno) { int c; char buf[32]; extern int tl_yychar; @@ -73,7 +75,7 @@ } while (c == ' '); /* '\t' is removed in tl_main.c */ if (islower(c)) - { getword(c, isalnum_); + { tl_getword(c, isalnum_); if (strcmp("true", yytext) == 0) { Token(TRUE); } @@ -102,12 +104,12 @@ } switch (c) { - case '/' : c = follow('\\', AND, '/'); break; - case '\\': c = follow('/', OR, '\\'); break; - case '&' : c = follow('&', AND, '&'); break; - case '|' : c = follow('|', OR, '|'); break; - case '[' : c = follow(']', ALWAYS, '['); break; - case '-' : c = follow('>', IMPLIES, '-'); break; + case '/' : c = tl_follow('\\', AND, '/'); break; + case '\\': c = tl_follow('/', OR, '\\'); break; + case '&' : c = tl_follow('&', AND, '&'); break; + case '|' : c = tl_follow('|', OR, '|'); break; + case '[' : c = tl_follow(']', ALWAYS, '['); break; + case '-' : c = tl_follow('>', IMPLIES, '-'); break; case '!' : c = NOT; break; case 'U' : c = U_OPER; break; case 'V' : c = V_OPER; break; @@ -129,7 +131,7 @@ return sp; sp = (Symbol *) tl_emalloc(sizeof(Symbol)); - sp->name = (char *) tl_emalloc(strlen(s) + 1); + sp->name = (char *) tl_emalloc((int) strlen(s) + 1); strcpy(sp->name, s); sp->next = symtab[h]; symtab[h] = sp; --- /sys/src/cmd/spin/tl_main.c Wed Aug 31 04:30:37 2005 +++ /sys/src/cmd/spin/tl_main.c Wed Aug 31 04:30:37 2005 @@ -1,14 +1,16 @@ /***** tl_spin: tl_main.c *****/ -/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ #include "tl.h" @@ -24,8 +26,8 @@ static char uform[4096]; static int hasuform=0, cnt=0; -static void tl_stats(void); -static void non_fatal(char *, char *); +extern void cache_stats(void); +extern void a_stats(void); int tl_Getchar(void) @@ -48,6 +50,15 @@ if (cnt > 0) cnt--; } +static void +tl_stats(void) +{ extern int Stack_mx; + printf("total memory used: %9ld\n", All_Mem); + printf("largest stack sze: %9d\n", Stack_mx); + cache_stats(); + a_stats(); +} + int tl_main(int argc, char *argv[]) { int i; @@ -67,7 +78,7 @@ argv[1][i] = ' '; } strcpy(uform, argv[1]); - hasuform = strlen(uform); + hasuform = (int) strlen(uform); break; case 'v': tl_verbose++; break; @@ -90,15 +101,6 @@ return tl_errs; } -static void -tl_stats(void) -{ extern int Stack_mx; - printf("total memory used: %9ld\n", All_Mem); - printf("largest stack sze: %9d\n", Stack_mx); - cache_stats(); - a_stats(); -} - #define Binop(a) \ fprintf(tl_out, "("); \ dump(n->lft); \ @@ -174,7 +176,7 @@ } static void -non_fatal(char *s1, char *s2) +tl_non_fatal(char *s1, char *s2) { extern int tl_yychar; int i; @@ -205,7 +207,7 @@ void Fatal(char *s1, char *s2) { - non_fatal(s1, s2); + tl_non_fatal(s1, s2); /* tl_stats(); */ exit(1); } --- /sys/src/cmd/spin/tl_mem.c Wed Aug 31 04:31:07 2005 +++ /sys/src/cmd/spin/tl_mem.c Wed Aug 31 04:31:07 2005 @@ -1,14 +1,16 @@ /***** tl_spin: tl_mem.c *****/ -/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ #include "tl.h" --- /sys/src/cmd/spin/tl_parse.c Wed Aug 31 04:31:40 2005 +++ /sys/src/cmd/spin/tl_parse.c Wed Aug 31 04:31:38 2005 @@ -1,14 +1,16 @@ /***** tl_spin: tl_parse.c *****/ -/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ #include "tl.h" @@ -48,7 +50,7 @@ tl_yychar = tl_yylex(); ptr = tl_factor(); - +#ifndef NO_OPT if (ptr->ntyp == FALSE || ptr->ntyp == TRUE) break; /* [] false == false */ @@ -59,7 +61,7 @@ ptr = ptr->rgt; /* [] (p V q) = [] q */ } - +#endif ptr = tl_nn(V_OPER, False, ptr); break; #ifdef NXT @@ -75,6 +77,7 @@ tl_yychar = tl_yylex(); ptr = tl_factor(); +#ifndef NO_OPT if (ptr->ntyp == TRUE || ptr->ntyp == FALSE) break; /* <> true == true */ @@ -88,7 +91,7 @@ ptr = ptr->rgt; /* fall thru */ } - +#endif ptr = tl_nn(U_OPER, True, ptr); break; @@ -118,6 +121,7 @@ if (ptr) switch (ptr->ntyp) { case U_OPER: +#ifndef NO_OPT if (ptr->rgt->ntyp == TRUE || ptr->rgt->ntyp == FALSE || ptr->lft->ntyp == FALSE) @@ -151,8 +155,10 @@ ptr->rgt->lft), ZN); } #endif +#endif break; case V_OPER: +#ifndef NO_OPT if (ptr->rgt->ntyp == FALSE || ptr->rgt->ntyp == TRUE || ptr->lft->ntyp == TRUE) @@ -177,20 +183,25 @@ ptr->rgt = ptr->rgt->rgt; break; } +#endif break; case IMPLIES: +#ifndef NO_OPT if (isequal(ptr->lft, ptr->rgt)) { ptr = True; break; } +#endif ptr = tl_nn(OR, Not(ptr->lft), ptr->rgt); ptr = rewrite(ptr); break; case EQUIV: +#ifndef NO_OPT if (isequal(ptr->lft, ptr->rgt)) { ptr = True; break; } +#endif a = rewrite(tl_nn(AND, dupnode(ptr->lft), dupnode(ptr->rgt))); @@ -201,6 +212,7 @@ ptr = rewrite(ptr); break; case AND: +#ifndef NO_OPT /* p && (q U p) = p */ if (ptr->rgt->ntyp == U_OPER && isequal(ptr->rgt->rgt, ptr->lft)) @@ -275,9 +287,11 @@ { ptr = ptr->lft; break; } +#endif break; case OR: +#ifndef NO_OPT /* p || (q U p) == q U p */ if (ptr->rgt->ntyp == U_OPER && isequal(ptr->rgt->rgt, ptr->lft)) @@ -331,7 +345,7 @@ { ptr = ptr->rgt; break; } - +#endif break; } return ptr; --- /sys/src/cmd/spin/tl_rewrt.c Wed Aug 31 04:32:14 2005 +++ /sys/src/cmd/spin/tl_rewrt.c Wed Aug 31 04:32:13 2005 @@ -1,14 +1,16 @@ /***** tl_spin: tl_rewrt.c *****/ -/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ #include "tl.h" @@ -40,7 +42,7 @@ { Node *m; /* assumes input is right_linked */ if (!n) return n; - if (m = in_cache(n)) + if ((m = in_cache(n)) != ZN) return m; n->rgt = canonical(n->rgt); @@ -127,11 +129,7 @@ addcan(tok, n->lft); return; } -#if 0 - if ((tok == AND && n->ntyp == TRUE) - || (tok == OR && n->ntyp == FALSE)) - return; -#endif + N = dupnode(n); if (!can) { can = N; @@ -196,7 +194,7 @@ can = ZN; addcan(tok, n); -#if 1 +#if 0 Debug("\nA0: "); Dump(can); Debug("\nA1: "); Dump(n); Debug("\n"); #endif @@ -233,11 +231,6 @@ { marknode(AND, p); continue; } - if (k2->ntyp == U_OPER - && anywhere(AND, k2->rgt, can)) - { marknode(AND, p); - continue; - } /* q && (p U q) = q */ } } if (tok == OR) { for (m = can; m; m = (m->ntyp == OR) ? m->rgt : ZN) @@ -269,12 +262,6 @@ { marknode(OR, p); continue; } - if (k2->ntyp == V_OPER - && k2->lft->ntyp == FALSE - && anywhere(AND, k2->rgt, can)) - { marknode(OR, p); - continue; - } /* p || (F V p) = p */ } } for (m = can, prev = ZN; m; ) /* remove marked nodes */ { if (m->ntyp == -1) @@ -301,7 +288,7 @@ m = m->rgt; } out: -#if 1 +#if 0 Debug("A2: "); Dump(can); Debug("\n"); #endif if (!can) --- /sys/src/cmd/spin/tl_trans.c Wed Aug 31 04:32:48 2005 +++ /sys/src/cmd/spin/tl_trans.c Wed Aug 31 04:32:46 2005 @@ -1,14 +1,16 @@ /***** tl_spin: tl_trans.c *****/ -/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A. */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ + /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ #include "tl.h" @@ -40,7 +42,7 @@ static void Addout(char *, char *); static void fsm_trans(Graph *, int, char *); static void mkbuchi(void); -static void expand(Graph *); +static void expand_g(Graph *); static void fixinit(Node *); static void liveness(Node *); static void mk_grn(Node *); @@ -131,6 +133,7 @@ { Graph *p; n = right_linked(n); +more: for (p = Nodes_Set; p; p = p->nxt) if (p->outgoing && has_clause(AND, p, n)) @@ -138,6 +141,11 @@ (unsigned char) Red_cnt; Lab_cnt++; } + + if (n->ntyp == U_OPER) /* 3.4.0 */ + { n = n->rgt; + goto more; + } } static void @@ -347,6 +355,14 @@ sprintf(nwnm, "%s_%s", prefix, s->name); } else strcpy(nwnm, "accept_all"); + + if (tl_verbose) + { printf("maxred=%d, count=%d, curnm=%s, nwnm=%s ", + Max_Red, count, curnm, nwnm); + printf("(greencnt=%d,%d, redcnt=%d,%d)\n", + r->grncnt, r->isgrn[0], + r->redcnt, r->isred[0]); + } addtrans(p, curnm, r->Old, nwnm); } } @@ -625,10 +641,9 @@ } static void -expand(Graph *g) +expand_g(Graph *g) { Node *now, *n1, *n2, *nx; int can_release; - extern void cache_dump(void); if (!g->New) { Debug2("\nDone with %s", g->name->name); @@ -681,14 +696,7 @@ g->New = g->New->nxt; now->nxt = ZN; - if (now->ntyp != TRUE -#if 1 -/* 3.4.0 */ - ) -#else -/* 3.3.9 */ - && now->ntyp != FALSE) -#endif + if (now->ntyp != TRUE) { if (g->Old) { for (n1 = g->Old; n1->nxt; n1 = n1->nxt) if (isequal(now, n1)) @@ -702,24 +710,7 @@ out: switch (now->ntyp) { case FALSE: -#if 1 -/* 3.4.0 */ -push_stack(g); -#else - releasenode(1, now); - for (n1 = g->Old; n1; n1 = n2) - { n2 = n1->nxt; - releasenode(1, n1); - } - for (n1 = g->New; n1; n1 = n2) - { n2 = n1->nxt; - releasenode(1, n1); - } - for (n1 = g->Next; n1; n1 = n2) - { n2 = n1->nxt; - releasenode(1, n1); - } -#endif + push_stack(g); break; case TRUE: releasenode(1, now); @@ -863,9 +854,9 @@ op = dupnode(p); ng(ZS, getsym(tl_lookup("init")), p, ZN, ZN); - while (g = Nodes_Stack) + while ((g = Nodes_Stack) != (Graph *) 0) { Nodes_Stack = g->nxt; - expand(g); + expand_g(g); } if (newstates) return; --- /sys/src/cmd/spin/vars.c Wed Aug 31 04:33:23 2005 +++ /sys/src/cmd/spin/vars.c Wed Aug 31 04:33:22 2005 @@ -1,14 +1,13 @@ /***** spin: vars.c *****/ -/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */ +/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ -/* Permission is given to distribute this code provided that this intro- */ -/* ductory message is not removed and no monies are exchanged. */ -/* No guarantee is expressed or implied by the distribution of this code. */ -/* Software written by Gerard J. Holzmann as part of the book: */ -/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */ -/* Prentice Hall, Englewood Cliffs, NJ, 07632. */ -/* Send bug-reports and/or questions to: gerard@research.bell-labs.com */ +/* No guarantee whatsoever is expressed or implied by the distribution of */ +/* this code. Permission is given to distribute this code provided that */ +/* this introductory message is not removed and no monies are exchanged. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" #ifdef PC @@ -23,7 +22,7 @@ extern char Buf[]; extern int lineno, depth, verbose, xspin, limited_vis; extern int analyze, jumpsteps, nproc, nstop, columns; -extern short no_arrays, Have_claim, Skip_claim; +extern short no_arrays, Have_claim; extern void sr_mesg(FILE *, int, int); extern void sr_buf(int, int); @@ -96,12 +95,9 @@ { int i, oln = lineno; /* calls on eval() change it */ Symbol *ofnm = Fname; - if (n >= s->nel || n < 0) - { printf("spin: indexing %s[%d] - size is %d\n", - s->name, n, s->nel); - non_fatal("indexing array \'%s\'", s->name); + if (!in_bound(s, n)) return 0; - } + if (s->type == 0) { non_fatal("undecl var %s (assuming int)", s->name); s->type = INT; @@ -139,19 +135,20 @@ int cast_val(int t, int v, int w) -{ int i=0; short s=0; unsigned char u=0; +{ int i=0; short s=0; unsigned int u=0; - if (t == INT || t == CHAN) i = v; + if (t == PREDEF || t == INT || t == CHAN) i = v; /* predef means _ */ else if (t == SHORT) s = (short) v; else if (t == BYTE || t == MTYPE) u = (unsigned char)v; else if (t == BIT) u = (unsigned char)(v&1); else if (t == UNSIGNED) { if (w == 0) fatal("cannot happen, cast_val", (char *)0); - u = (unsigned char)(v& ((1<>(8*sizeof(unsigned)-w))); /* doug */ } - if (v != i+s+u) + if (v != i+s+ (int) u) { char buf[32]; sprintf(buf, "%d->%d (%d)", v, i+s+u, t); non_fatal("value (%s) truncated in assignment", buf); } @@ -166,9 +163,7 @@ else { int n = eval(v->lft); if (checkvar(v->sym, n)) - { if (v->sym->nbits > 0) - m = (m & ((1<sym->nbits)-1)); - v->sym->val[n] = m; + { v->sym->val[n] = cast_val(v->sym->type, m, v->sym->nbits); v->sym->setat = depth; } } return 1; @@ -208,14 +203,18 @@ void dumpglobals(void) { Ordered *walk; - Lextok *dummy; + static Lextok *dummy = ZN; Symbol *sp; int j; + if (!dummy) + dummy = nn(ZN, NAME, nn(ZN,CONST,ZN,ZN), ZN); + for (walk = all_names; walk; walk = walk->next) { sp = walk->entry; if (!sp->type || sp->context || sp->owner - || sp->type == PROCTYPE || sp->type == PREDEF + || sp->type == PROCTYPE || sp->type == PREDEF + || sp->type == CODE_FRAG || sp->type == CODE_DECL || (sp->type == MTYPE && ismtype(sp->name))) continue; @@ -233,7 +232,6 @@ && (sp->setat < depth && jumpsteps != depth)) continue; - dummy = nn(ZN, NAME, nn(ZN,CONST,ZN,ZN), ZN); dummy->sym = sp; dummy->lft->val = j; /* in case of cast_val warnings, do this first: */ @@ -279,10 +277,13 @@ void dumplocal(RunList *r) -{ Lextok *dummy; +{ static Lextok *dummy = ZN; Symbol *z, *s = r->symtab; int i; + if (!dummy) + dummy = nn(ZN, NAME, nn(ZN,CONST,ZN,ZN), ZN); + for (z = s; z; z = z->next) { if (z->type == STRUCT) { dump_struct(z, z->name, r); @@ -298,7 +299,6 @@ && jumpsteps != depth)) continue; - dummy = nn(ZN, NAME, nn(ZN,CONST,ZN,ZN), ZN); dummy->sym = z; dummy->lft->val = i; @@ -306,8 +306,7 @@ r->n->name, r->pid, z->name); if (z->nel > 1) printf("[%d]", i); printf(" = "); - sr_mesg(stdout, getval(dummy), - z->type == MTYPE); + sr_mesg(stdout, getval(dummy), z->type == MTYPE); printf("\n"); if (limited_vis && (z->hidden&2)) { int colpos; --- /sys/src/cmd/spin/version.h Wed Aug 31 04:33:58 2005 +++ /sys/src/cmd/spin/version.h Wed Aug 31 04:33:57 2005 @@ -1 +1 @@ -#define Version "Spin Version 3.4.0 -- 27 March 2000" +#define Version "Spin Version 4.2.5 -- 2 April 2005" --- /sys/src/cmd/unix/spin/readme Wed Aug 31 04:34:34 2005 +++ /sys/src/cmd/unix/spin/readme Wed Aug 31 04:34:33 2005 @@ -1,4 +1,4 @@ the latest version of sources, documentation, newsletters, workshop announcements, etc., for the Spin system can always -be found online at: http://netlib.bell-labs.com/netlib/spin/whatispin.html -online references live at: http://cm.bell-labs.com/cm/cs/what/spin/Man.html +be found online at: http://spinroot.com/spin/whatispin.html +online references live at: http://spinroot.com/spin/Man/index.html Binary files /sys/src/cmd/unix/spin/spin425.tar.gz and spin425.tar.gz differ